From 4737f76fc6fa4cdfbe1644ea554eff7194e0f1a9 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sun, 17 Mar 2024 02:42:34 +0100 Subject: [PATCH 01/17] Update release notes and keywords for release 0.4.0 --- release-notes.txt | 23 +++++++++++-------- .../FSharp.Control.TaskSeq.fsproj | 4 ++-- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/release-notes.txt b/release-notes.txt index df20d858..7f0d630c 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -1,38 +1,43 @@ Release notes: -0.4.x (unreleased) - - overhaul all doc comments, add exceptions, improve IDE quick-info experience, #136 +0.4.0 + - overhaul all doc comments, add exceptions, improve IDE quick-info experience, #136, #220, #234 - new surface area functions, fixes #208: * TaskSeq.take, skip, #209 * TaskSeq.truncate, drop, #209 * TaskSeq.where, whereAsync, #217 * TaskSeq.skipWhile, skipWhileInclusive, skipWhileAsync, skipWhileInclusiveAsync, #219 * TaskSeq.max, min, maxBy, minBy, maxByAsync, minByAsync, #221 + * TaskSeq.insertAt, insertManyAt, removeAt, removeManyAt, updateAt, #236 + * TaskSeq.forall, forallAsync, #240 + * TaskSeq.concat (overloads: seq, array, resizearray, list), #237 - Performance: less thread hops with 'StartImmediateAsTask' instead of 'StartAsTask', fixes #135 - - BINARY INCOMPATIBILITY: 'TaskSeq' module is now static members on 'TaskSeq<_>', fixes #184 + - Performance: several inline and allocation improvements + - BINARY INCOMPATIBILITY: 'TaskSeq' module replaced by static members on 'TaskSeq<_>', fixes #184 - DEPRECATIONS (warning FS0044): - type 'taskSeq<_>' is renamed to 'TaskSeq<_>', fixes #193 - function 'ValueTask.ofIValueTaskSource` renamed to `ValueTask.ofSource`, fixes #193 - function `ValueTask.FromResult` is renamed to `ValueTask.fromResult`, fixes #193 0.4.0-alpha.1 - - fixes not calling Dispose for 'use!', 'use', or `finally` blocks #157 (by @bartelink) + - bugfix: not calling Dispose for 'use!', 'use', or `finally` blocks #157 (by @bartelink) - BREAKING CHANGE: null args now raise ArgumentNullException instead of NullReferenceException, #127 - adds `let!` and `do!` support for F#'s Async<'T>, #79, #114 - adds TaskSeq.takeWhile, takeWhileAsync, takeWhileInclusive, takeWhileInclusiveAsync, #126 (by @bartelink) - adds AsyncSeq vs TaskSeq comparison chart, #131 - - removes release-notes.txt from file dependencies, but keep in the package, #138 + - bugfix: removes release-notes.txt from file dependencies, but keep in the package, #138 0.3.0 - - internal renames, improved doc comments, signature files for complex types, hide internal-only types, fixes #112. + - improved xml doc comments, signature files for exposing types, fixes #112. - adds support for static TaskLike, allowing the same let! and do! overloads that F# task supports, fixes #110. - implements 'do!' for non-generic Task like with Task.Delay, fixes #43. - - adds support for 'for .. in ..' with task sequences in F# tasks and async, #75, #93 and #99 (with help from @theangrybyrd). + - task and async CEs extended with support for 'for .. in ..do' with TaskSeq, #75, #93, #99 (in part by @theangrybyrd). - adds TaskSeq.singleton, #90 (by @gusty). - - fixes overload resolution bug with 'use' and 'use!', #97 (thanks @peterfaria). + - bugfix: fixes overload resolution bug with 'use' and 'use!', #97 (thanks @peterfaria). - improves TaskSeq.empty by not relying on resumable state, #89 (by @gusty). - - does not throw exceptions anymore for unequal lengths in TaskSeq.zip, fixes #32. + - bugfix: does not throw exceptions anymore for unequal lengths in TaskSeq.zip, fixes #32. + - BACKWARD INCOMPATIBILITY: several internal-only types now hidden 0.2.2 - removes TaskSeq.toSeqCachedAsync, which was incorrectly named. Use toSeq or toListAsync instead. diff --git a/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj b/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj index 297af81f..15cfdc69 100644 --- a/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj +++ b/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj @@ -13,7 +13,7 @@ The 'taskSeq' computation expression adds support for awaitable asynchronous sequences with similar ease of use and performance to F#'s 'task' CE, with minimal overhead through ValueTask under the hood. TaskSeq brings 'seq' and 'task' together in a safe way. Generates optimized IL code through resumable state machines, and comes with a comprehensive set of functions in module 'TaskSeq'. See README for documentation and more info. - Copyright 2023 + Copyright 2022-2024 https://github.com/fsprojects/FSharp.Control.TaskSeq https://github.com/fsprojects/FSharp.Control.TaskSeq taskseq-icon.png @@ -22,7 +22,7 @@ Generates optimized IL code through resumable state machines, and comes with a c False nuget-package-readme.md $([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/../../release-notes.txt")) - taskseq;f#;computation expression;IAsyncEnumerable;task;async;asyncseq; + taskseq;f#;fsharp;asyncseq;seq;sequences;sequential;threading;computation expression;IAsyncEnumerable;task;async;iteration True snupkg From 03941c0064aec86e6c09078cbb1a6602d60d03be Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Tue, 19 Mar 2024 03:06:43 +0100 Subject: [PATCH 02/17] Update release information in `readme.md` --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9cf9bcdd..cac8cf2b 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,11 @@ An implementation of [`IAsyncEnumerable<'T>`][3] as a computation expression: `taskSeq { ... }` with an accompanying `TaskSeq` module and functions, that allow seamless use of asynchronous sequences similar to F#'s native `seq` and `task` CE's. -* Latest stable version: [0.3.0 is on NuGet][nuget]. -* Latest prerelease version: [0.4.0-alpha.1 is on NuGet][nuget]. +* Latest stable version: [0.4.0 is on NuGet][nuget]. ## Release notes -See [release notes.txt](release-notes.txt) for the version history of `TaskSeq`. See [Status overview](#status--planning) for current status of the surface area of `TaskSeq`. +See [Releases](https://github.com/fsprojects/FSharp.Control.TaskSeq/releases) for the an extensive version history of `TaskSeq`. See [Status overview](#status--planning) below for a progress report. ----------------------------------------- From 60183d9837a0326a6bb0f38e7242161f92bd7da9 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Wed, 27 Mar 2024 18:08:03 +0100 Subject: [PATCH 03/17] Useful script to backdate git tags --- backdate-tags.cmd | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 backdate-tags.cmd diff --git a/backdate-tags.cmd b/backdate-tags.cmd new file mode 100644 index 00000000..1444417b --- /dev/null +++ b/backdate-tags.cmd @@ -0,0 +1,60 @@ +@echo off + +REM Batch file to override the date and/or message of existing tag, or create a new +REM tag that takes the same date/time of an existing commit. +REM +REM Usage: +REM > backdate-tags.cmd v0.1.1 "New message" +REM +REM How it works: +REM * checkout the commit at the moment of the tag +REM * get the date/time of that commit and store in GIT_COMMITER_DATE env var +REM * recreate the tag (it will now take the date of its commit) +REM * push tags changes to remove (with --force) +REM * return to HEAD +REM +REM PS: +REM * these escape codes are for underlining the headers so they stand out between all GIT's output garbage +REM * the back-dating trick is taken from here: https://stackoverflow.com/questions/21738647/change-date-of-git-tag-or-github-release-based-on-it + +ECHO. +ECHO List existing tags: +git tag -n + +ECHO. +ECHO Checkout to tag: +git checkout tags/%1 + +REM Output the first string, containing the date of commit, and put it in a file +REM then set the contents of that file to env var GIT_COMMITTER_DATE (which in turn is needed to enable back-dating) +REM then delete the temp file +ECHO. +ECHO Retrieve original commit date + +git show --format=%%aD | findstr "^[MTWFS][a-z][a-z],.*" > _date.tmp +< _date.tmp (set /p GIT_COMMITTER_DATE=) +del _date.tmp + +ECHO Committer date for tag: %GIT_COMMITTER_DATE% +ECHO Overriding tag '%1' with text: %2 +ECHO. +REM Override (with -af) the tag, if it exists (no quotes around %2) +git tag -af %1 -m %2 + +ECHO. +ECHO Updated tag: +git tag --points-at HEAD -n +ECHO. + +REM Push to remove and override (with --force) +ECHO Push changes to remote +git push --tags --force + +REM Go back to original HEAD +ECHO. +ECHO Back to original HEAD +git checkout - + +ECHO. +ECHO List of all tags +git tag -n From ec5d9c2552e12f4e85949787a2c3645549783285 Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sun, 31 Mar 2024 10:59:30 +0100 Subject: [PATCH 04/17] Utils naming/xmldoc polish --- src/FSharp.Control.TaskSeq/Utils.fs | 18 +++++++----------- src/FSharp.Control.TaskSeq/Utils.fsi | 24 ++++++++++++------------ 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/FSharp.Control.TaskSeq/Utils.fs b/src/FSharp.Control.TaskSeq/Utils.fs index c02bab35..63e0798f 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fs +++ b/src/FSharp.Control.TaskSeq/Utils.fs @@ -2,8 +2,6 @@ namespace FSharp.Control open System.Threading.Tasks open System -open System.Diagnostics -open System.Threading [] module ValueTaskExtensions = @@ -24,15 +22,15 @@ module ValueTask = let inline ofSource taskSource version = ValueTask(taskSource, version) let inline ofTask (task: Task<'T>) = ValueTask<'T> task - let inline ignore (vtask: ValueTask<'T>) = + let inline ignore (valueTask: ValueTask<'T>) = // this implementation follows Stephen Toub's advice, see: // https://github.com/dotnet/runtime/issues/31503#issuecomment-554415966 - if vtask.IsCompletedSuccessfully then + if valueTask.IsCompletedSuccessfully then // ensure any side effect executes - vtask.Result |> ignore + valueTask.Result |> ignore ValueTask() else - ValueTask(vtask.AsTask()) + ValueTask(valueTask.AsTask()) [] let inline FromResult (value: 'T) = ValueTask<'T> value @@ -72,14 +70,12 @@ module Async = let inline ofTask (task: Task<'T>) = Async.AwaitTask task let inline ofUnitTask (task: Task) = Async.AwaitTask task let inline toTask (async: Async<'T>) = task { return! async } - let inline bind binder (task: Async<'T>) : Async<'U> = ExtraTopLevelOperators.async { return! binder task } - let inline ignore (async': Async<'T>) = async { - let! _ = async' - return () - } + let inline ignore (async: Async<'T>) = Async.Ignore async let inline map mapper (async: Async<'T>) : Async<'U> = ExtraTopLevelOperators.async { let! result = async return mapper result } + + let inline bind binder (async: Async<'T>) : Async<'U> = ExtraTopLevelOperators.async { return! binder async } diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index d34a1e57..13b7e205 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -24,13 +24,13 @@ module ValueTask = /// /// The function is deprecated since version 0.4.0, - /// please use in its stead. See . + /// please use in its stead. See . /// [] val inline FromResult: value: 'T -> ValueTask<'T> /// - /// Initialized a new instance of with an representing + /// Initializes a new instance of with an /// representing its operation. /// val inline ofSource: taskSource: IValueTaskSource -> version: int16 -> ValueTask @@ -42,15 +42,18 @@ module ValueTask = [] val inline ofIValueTaskSource: taskSource: IValueTaskSource -> version: int16 -> ValueTask - /// Creates a ValueTask form a Task<'T> + /// Creates a ValueTask from a Task<'T> val inline ofTask: task: Task<'T> -> ValueTask<'T> - /// Ignore a ValueTask<'T>, returns a non-generic ValueTask. - val inline ignore: vtask: ValueTask<'T> -> ValueTask + /// Convert a ValueTask<'T> into a non-generic ValueTask, ignoring the result + val inline ignore: valueTask: ValueTask<'T> -> ValueTask module Task = - /// Convert an Async<'T> into a Task<'T> + /// Create a task from a value + val inline fromResult: value: 'U -> Task<'U> + + /// Starts a running instance of an Async<'T>, represented as a Task<'T> val inline ofAsync: async: Async<'T> -> Task<'T> /// Convert a unit-task into a Task @@ -80,9 +83,6 @@ module Task = /// Bind a Task<'T> val inline bind: binder: ('T -> #Task<'U>) -> task: Task<'T> -> Task<'U> - /// Create a task from a value - val inline fromResult: value: 'U -> Task<'U> - module Async = /// Convert an Task<'T> into an Async<'T> @@ -91,14 +91,14 @@ module Async = /// Convert a unit-task into an Async val inline ofUnitTask: task: Task -> Async - /// Convert a Task<'T> into an Async<'T> + /// Starts a running instance of an Async<'T>, represented as a Task<'T> val inline toTask: async: Async<'T> -> Task<'T> /// Convert an Async<'T> into an Async, ignoring the result - val inline ignore: async': Async<'T> -> Async + val inline ignore: async: Async<'T> -> Async /// Map an Async<'T> val inline map: mapper: ('T -> 'U) -> async: Async<'T> -> Async<'U> /// Bind an Async<'T> - val inline bind: binder: (Async<'T> -> Async<'U>) -> task: Async<'T> -> Async<'U> + val inline bind: binder: (Async<'T> -> Async<'U>) -> async: Async<'T> -> Async<'U> From e5a128ca6b046e8c821978a61093646e7f278dfc Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sun, 31 Mar 2024 11:06:17 +0100 Subject: [PATCH 05/17] Lint --- src/FSharp.Control.TaskSeq/Utils.fsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index 13b7e205..dacc1689 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -6,10 +6,10 @@ open System.Threading.Tasks.Sources [] module ValueTaskExtensions = - type System.Threading.Tasks.ValueTask with + type ValueTask with /// (Extension member) Gets a task that has already completed successfully. - static member inline CompletedTask: System.Threading.Tasks.ValueTask + static member inline CompletedTask: ValueTask module ValueTask = From 72224295fa87088890acb3cc8d1fc3e1cfebbd8f Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sun, 31 Mar 2024 11:21:13 +0100 Subject: [PATCH 06/17] non- consistency --- src/FSharp.Control.TaskSeq/TaskSeq.fsi | 4 ++-- src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs | 4 ++-- src/FSharp.Control.TaskSeq/Utils.fsi | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/FSharp.Control.TaskSeq/TaskSeq.fsi b/src/FSharp.Control.TaskSeq/TaskSeq.fsi index cb5eefe5..ff98586c 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeq.fsi +++ b/src/FSharp.Control.TaskSeq/TaskSeq.fsi @@ -274,7 +274,7 @@ type TaskSeq = static member append: source1: TaskSeq<'T> -> source2: TaskSeq<'T> -> TaskSeq<'T> /// - /// Concatenates a task sequence with a non-async F# in + /// Concatenates a task sequence with a (non-async) F# in /// and returns a single task sequence. /// /// @@ -285,7 +285,7 @@ type TaskSeq = static member appendSeq: source1: TaskSeq<'T> -> source2: seq<'T> -> TaskSeq<'T> /// - /// Concatenates a non-async F# in with a task sequence in + /// Concatenates a (non-async) F# in with a task sequence in /// and returns a single task sequence. /// /// diff --git a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs index 958678ab..0b2e370e 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs +++ b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs @@ -525,9 +525,9 @@ module LowPriority = // and we need a way to distinguish these two methods. // // Types handled: - // - ValueTask (non-generic, because it implements GetResult() -> unit) + // - (non-generic) ValueTask (because it implements GetResult() -> unit) // - ValueTask<'T> (because it implements GetResult() -> 'TResult) - // - Task (non-generic, because it implements GetResult() -> unit) + // - (non-generic) Task (because it implements GetResult() -> unit) // - any other type that implements GetAwaiter() // // Not handled: diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index dacc1689..aecada8d 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -56,10 +56,10 @@ module Task = /// Starts a running instance of an Async<'T>, represented as a Task<'T> val inline ofAsync: async: Async<'T> -> Task<'T> - /// Convert a unit-task into a Task + /// Convert a non-generic Task into a Task val inline ofTask: task': Task -> Task - /// Convert a non-task function into a task-returning function + /// Convert a plain function into a task-returning function val inline apply: func: ('a -> 'b) -> ('a -> Task<'b>) /// Convert a Task<'T> into an Async<'T> @@ -69,8 +69,8 @@ module Task = val inline toValueTask: task: Task<'T> -> ValueTask<'T> /// - /// Convert a ValueTask<'T> to a Task<'T>. To use a non-generic ValueTask, - /// consider using: . + /// Convert a ValueTask<'T> to a Task<'T>. For a non-generic ValueTask, + /// consider: . /// val inline ofValueTask: valueTask: ValueTask<'T> -> Task<'T> @@ -88,7 +88,7 @@ module Async = /// Convert an Task<'T> into an Async<'T> val inline ofTask: task: Task<'T> -> Async<'T> - /// Convert a unit-task into an Async + /// Convert a non-generic Task into an Async val inline ofUnitTask: task: Task -> Async /// Starts a running instance of an Async<'T>, represented as a Task<'T> From c1ac47170f76835cfcfc796dd2429d4e82c0b98d Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sat, 6 Apr 2024 20:53:50 +0100 Subject: [PATCH 07/17] Cleanup CompletedTask --- src/FSharp.Control.TaskSeq/Utils.fs | 10 ++-------- src/FSharp.Control.TaskSeq/Utils.fsi | 4 +++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/FSharp.Control.TaskSeq/Utils.fs b/src/FSharp.Control.TaskSeq/Utils.fs index 63e0798f..ec076f20 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fs +++ b/src/FSharp.Control.TaskSeq/Utils.fs @@ -1,20 +1,15 @@ namespace FSharp.Control -open System.Threading.Tasks open System +open System.Threading.Tasks [] module ValueTaskExtensions = - /// Extensions for ValueTask that are not available in NetStandard 2.1, but are - /// available in .NET 5+. We put them in Extension space to mimic the behavior of NetStandard 2.1 type ValueTask with - - /// (Extension member) Gets a task that has already completed successfully. static member inline CompletedTask = - // This mimics how it is done in .NET itself + // This mimics how it is done in net5.0 and later internally Unchecked.defaultof - module ValueTask = let False = ValueTask() let True = ValueTask true @@ -38,7 +33,6 @@ module ValueTask = [] let inline ofIValueTaskSource taskSource version = ofSource taskSource version - module Task = let inline fromResult (value: 'U) : Task<'U> = Task.FromResult value let inline ofAsync (async: Async<'T>) = task { return! async } diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index aecada8d..86d9dd44 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -6,9 +6,11 @@ open System.Threading.Tasks.Sources [] module ValueTaskExtensions = + + /// Shims back-filling .NET 5+ functionality for use on netstandard2.1 type ValueTask with - /// (Extension member) Gets a task that has already completed successfully. + /// (Extension member) Gets a ValueTask that has already completed successfully. static member inline CompletedTask: ValueTask module ValueTask = From 377025a3dd96be5daf71da1e9262e6f9118c3eeb Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sat, 6 Apr 2024 21:16:32 +0100 Subject: [PATCH 08/17] Reword Async.toTask/Task.ofAsync summary --- src/FSharp.Control.TaskSeq/Utils.fsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index 86d9dd44..ec7badd6 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -55,7 +55,7 @@ module Task = /// Create a task from a value val inline fromResult: value: 'U -> Task<'U> - /// Starts a running instance of an Async<'T>, represented as a Task<'T> + /// Starts the `Async<'T>` computation, returning the associated `Task<'T>` val inline ofAsync: async: Async<'T> -> Task<'T> /// Convert a non-generic Task into a Task From 593db0d15cf7871de08e4015173f7dbffad37513 Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sat, 6 Apr 2024 21:24:30 +0100 Subject: [PATCH 09/17] Align fromResult summary with .NET FW --- src/FSharp.Control.TaskSeq/Utils.fsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index ec7badd6..fab0cb2a 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -52,7 +52,7 @@ module ValueTask = module Task = - /// Create a task from a value + /// Creates a Task<'U> that's completed successfully with the specified result. val inline fromResult: value: 'U -> Task<'U> /// Starts the `Async<'T>` computation, returning the associated `Task<'T>` From b4ce4ee4690cbcc6545445a75d44ba656718e93b Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sat, 13 Apr 2024 14:16:59 +0100 Subject: [PATCH 10/17] Straggler, align Async.toTask with Task.toAsync --- src/FSharp.Control.TaskSeq/Utils.fsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index fab0cb2a..b1717204 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -93,7 +93,7 @@ module Async = /// Convert a non-generic Task into an Async val inline ofUnitTask: task: Task -> Async - /// Starts a running instance of an Async<'T>, represented as a Task<'T> + /// Starts the `Async<'T>` computation, returning the associated `Task<'T>` val inline toTask: async: Async<'T> -> Task<'T> /// Convert an Async<'T> into an Async, ignoring the result From a2c9f9514a47f4b87a9931892a65149144a8f6f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 14:49:09 +0000 Subject: [PATCH 11/17] Bump xunit from 2.7.0 to 2.8.0 Bumps [xunit](https://github.com/xunit/xunit) from 2.7.0 to 2.8.0. - [Commits](https://github.com/xunit/xunit/compare/2.7.0...2.8.0) --- updated-dependencies: - dependency-name: xunit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .../FSharp.Control.TaskSeq.SmokeTests.fsproj | 2 +- .../FSharp.Control.TaskSeq.Test.fsproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj b/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj index 53be692e..dec26b03 100644 --- a/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj +++ b/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj @@ -22,7 +22,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj index d625d93a..3fbdd3d3 100644 --- a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj +++ b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj @@ -64,7 +64,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 3310569bf414d88fc1e2fb4563be4969e45af531 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 14:49:46 +0000 Subject: [PATCH 12/17] Bump xunit.runner.visualstudio from 2.5.3 to 2.8.0 Bumps [xunit.runner.visualstudio](https://github.com/xunit/visualstudio.xunit) from 2.5.3 to 2.8.0. - [Release notes](https://github.com/xunit/visualstudio.xunit/releases) - [Commits](https://github.com/xunit/visualstudio.xunit/compare/2.5.3...2.8.0) --- updated-dependencies: - dependency-name: xunit.runner.visualstudio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .../FSharp.Control.TaskSeq.SmokeTests.fsproj | 2 +- .../FSharp.Control.TaskSeq.Test.fsproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj b/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj index 53be692e..eb3ae3dc 100644 --- a/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj +++ b/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj @@ -23,7 +23,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj index d625d93a..dcaf0380 100644 --- a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj +++ b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj @@ -65,7 +65,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 7f38792d59ec3a7735312f039f071bdf0df7ede8 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Wed, 1 May 2024 19:36:11 +0200 Subject: [PATCH 13/17] Add comments explaining FSharp.Core versioning --- .../FSharp.Control.TaskSeq.SmokeTests.fsproj | 9 +++++++-- .../FSharp.Control.TaskSeq.Test.fsproj | 6 +++++- .../FSharp.Control.TaskSeq.fsproj | 12 ++++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj b/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj index 53be692e..28a196ce 100644 --- a/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj +++ b/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj @@ -16,8 +16,13 @@ - - + diff --git a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj index d625d93a..a726bd8a 100644 --- a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj +++ b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj @@ -60,7 +60,11 @@ - + diff --git a/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj b/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj index 15cfdc69..9e6b6d9c 100644 --- a/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj +++ b/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj @@ -57,7 +57,15 @@ Generates optimized IL code through resumable state machines, and comes with a c - - + + + + true + From b8c38227913b732059cb4419349e4d872b4157cf Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Wed, 1 May 2024 19:39:42 +0200 Subject: [PATCH 14/17] Update all references (except FSharp.Core) --- .../FSharp.Control.TaskSeq.SmokeTests.fsproj | 10 +++++----- .../FSharp.Control.TaskSeq.Test.fsproj | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj b/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj index 28a196ce..ad3342a7 100644 --- a/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj +++ b/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj @@ -23,16 +23,16 @@ highest version available. This ensures that, if we have a forwards compat issue, we will get an error. --> - - + + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj index a726bd8a..6b5d755c 100644 --- a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj +++ b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj @@ -68,12 +68,12 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all From a16b91d8224c67afac76b7c1597b36881f3fbcaa Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Wed, 1 May 2024 22:52:37 +0200 Subject: [PATCH 15/17] Improve errors raised, simplify/generalize some code --- src/FSharp.Control.TaskSeq/TaskSeqInternal.fs | 52 ++++++++++--------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs b/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs index d7773ceb..66a92f2d 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs +++ b/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs @@ -62,7 +62,21 @@ module internal TaskSeqInternal = let inline raiseEmptySeq () = invalidArg "source" "The input task sequence was empty." - let inline raiseCannotBeNegative name = invalidArg name "The value must be non-negative." + /// Moves the enumerator to its first element, assuming it has just been allocated. + /// Raises "The input sequence was empty" if there was no first element. + let inline moveFirstOrRaiseUnsafe (e: IAsyncEnumerator<_>) = task { + let! hasFirst = e.MoveNextAsync() + + if not hasFirst then + invalidArg "source" "The input task sequence was empty." + } + + /// Tests the given integer value and raises if it is -1 or lower. + let inline raiseCannotBeNegative name value = + if value >= 0 then + () + else + invalidArg name $"The value must be non-negative, but was {value}." let inline raiseOutOfBounds name = invalidArg name "The value or index must be within the bounds of the task sequence." @@ -183,10 +197,7 @@ module internal TaskSeqInternal = task { use e = source.GetAsyncEnumerator CancellationToken.None - let! nonEmpty = e.MoveNextAsync() - - if not nonEmpty then - raiseEmptySeq () + do! moveFirstOrRaiseUnsafe e let mutable acc = e.Current @@ -202,10 +213,7 @@ module internal TaskSeqInternal = task { use e = source.GetAsyncEnumerator CancellationToken.None - let! nonEmpty = e.MoveNextAsync() - - if not nonEmpty then - raiseEmptySeq () + do! moveFirstOrRaiseUnsafe e let value = e.Current let mutable accProjection = projection value @@ -228,10 +236,7 @@ module internal TaskSeqInternal = task { use e = source.GetAsyncEnumerator CancellationToken.None - let! nonEmpty = e.MoveNextAsync() - - if not nonEmpty then - raiseEmptySeq () + do! moveFirstOrRaiseUnsafe e let value = e.Current let! projValue = projectionAsync value @@ -276,7 +281,10 @@ module internal TaskSeqInternal = let count = match count with - | Some c -> if c >= 0 then c else raiseCannotBeNegative (nameof count) + | Some c -> + raiseCannotBeNegative (nameof count) c + c + | None -> Int32.MaxValue match initializer with @@ -741,9 +749,7 @@ module internal TaskSeqInternal = let skipOrTake skipOrTake count (source: TaskSeq<_>) = checkNonNull (nameof source) source - - if count < 0 then - raiseCannotBeNegative (nameof count) + raiseCannotBeNegative (nameof count) count match skipOrTake with | Skip -> @@ -907,8 +913,7 @@ module internal TaskSeqInternal = /// InsertAt or InsertManyAt let insertAt index valueOrValues (source: TaskSeq<_>) = - if index < 0 then - raiseCannotBeNegative (nameof index) + raiseCannotBeNegative (nameof index) index taskSeq { let mutable i = 0 @@ -933,8 +938,7 @@ module internal TaskSeqInternal = } let removeAt index (source: TaskSeq<'T>) = - if index < 0 then - raiseCannotBeNegative (nameof index) + raiseCannotBeNegative (nameof index) index taskSeq { let mutable i = 0 @@ -951,8 +955,7 @@ module internal TaskSeqInternal = } let removeManyAt index count (source: TaskSeq<'T>) = - if index < 0 then - raiseCannotBeNegative (nameof index) + raiseCannotBeNegative (nameof index) index taskSeq { let mutable i = 0 @@ -970,8 +973,7 @@ module internal TaskSeqInternal = } let updateAt index value (source: TaskSeq<'T>) = - if index < 0 then - raiseCannotBeNegative (nameof index) + raiseCannotBeNegative (nameof index) index taskSeq { let mutable i = 0 From 5c8640b64f15018afd7381e2cddd7db7030c6436 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 May 2024 00:03:50 +0000 Subject: [PATCH 16/17] Bump Microsoft.NET.Test.Sdk from 17.9.0 to 17.10.0 Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.9.0 to 17.10.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md) - [Commits](https://github.com/microsoft/vstest/compare/v17.9.0...v17.10.0) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .../FSharp.Control.TaskSeq.SmokeTests.fsproj | 2 +- .../FSharp.Control.TaskSeq.Test.fsproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj b/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj index ad3342a7..83587f71 100644 --- a/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj +++ b/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj @@ -26,7 +26,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj index 6b5d755c..dbf1cfc5 100644 --- a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj +++ b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj @@ -67,7 +67,7 @@ --> - + runtime; build; native; contentfiles; analyzers; buildtransitive From 9ea3177abdb44bb9f9ec1632bd1fa6dfaf91bec5 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Wed, 12 Jun 2024 18:02:50 +0200 Subject: [PATCH 17/17] Remove redundant typar `'TOverall`, not used anymore --- src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs | 2 +- src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs index 0b2e370e..6ac6d0e7 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs +++ b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs @@ -534,7 +534,7 @@ module LowPriority = // - Task<'T> (because it only implements GetResult() -> unit, not GetResult() -> 'TResult) [] - member inline _.Bind< ^TaskLike, 'T, 'U, ^Awaiter, 'TOverall + member inline _.Bind< ^TaskLike, 'T, 'U, ^Awaiter when ^TaskLike: (member GetAwaiter: unit -> ^Awaiter) and ^Awaiter :> ICriticalNotifyCompletion and ^Awaiter: (member get_IsCompleted: unit -> bool) diff --git a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi index 4c185be6..e0607046 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi +++ b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi @@ -173,7 +173,7 @@ module LowPriority = type TaskSeqBuilder with [] - member inline Bind< ^TaskLike, 'T, 'U, ^Awaiter, 'TOverall> : + member inline Bind< ^TaskLike, 'T, 'U, ^Awaiter> : task: ^TaskLike * continuation: ('T -> ResumableTSC<'U>) -> ResumableTSC<'U> when ^TaskLike: (member GetAwaiter: unit -> ^Awaiter) and ^Awaiter :> ICriticalNotifyCompletion