Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Generates optimized IL code through the new resumable state machines, and comes
<PackageReleaseNotes>
Release notes:
0.2.3
- improve TaskSeq.empty by not relying on resumable state, #89
- do not throw exception for unequal lengths in TaskSeq.zip, fixes #32
0.2.2
- removes TaskSeq.toSeqCachedAsync, which was incorrectly named. Use toSeq or toListAsync instead.
Expand Down
13 changes: 9 additions & 4 deletions src/FSharp.Control.TaskSeq/TaskSeq.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ module TaskSeq =
// Just for convenience
module Internal = TaskSeqInternal

let empty<'T> = taskSeq {
for c: 'T in [] do
yield c
}
let empty<'T> =
{ new IAsyncEnumerable<'T> with
member _.GetAsyncEnumerator(_) =
{ new IAsyncEnumerator<'T> with
member _.MoveNextAsync() = ValueTask.False
member _.Current = Unchecked.defaultof<'T>
member _.DisposeAsync() = ValueTask.CompletedTask
}
}

let isEmpty source = Internal.isEmpty source

Expand Down
11 changes: 6 additions & 5 deletions src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ open System.Threading.Tasks.Sources

open FSharp.Core.CompilerServices
open FSharp.Core.CompilerServices.StateMachineHelpers
open FSharp.Control


[<AutoOpen>]
Expand Down Expand Up @@ -279,14 +280,14 @@ and [<NoComparison; NoEquality>] TaskSeq<'Machine, 'T
if this._machine.ResumptionPoint = -1 then // can't use as IAsyncEnumerator before IAsyncEnumerable
logInfo "at MoveNextAsync: Resumption point = -1"

ValueTask<bool>()
ValueTask.False

elif this._machine.Data.completed then
logInfo "at MoveNextAsync: completed = true"

// return False when beyond the last item
this._machine.Data.promiseOfValueOrEnd.Reset()
ValueTask<bool>()
ValueTask.False

else
logInfo "at MoveNextAsync: normal resumption scenario"
Expand Down Expand Up @@ -343,18 +344,18 @@ and [<NoComparison; NoEquality>] TaskSeq<'Machine, 'T
// the Current value
data.current <- ValueNone

ValueTask<bool>(result)
ValueTask.FromResult result

| ValueTaskSourceStatus.Faulted
| ValueTaskSourceStatus.Canceled
| ValueTaskSourceStatus.Pending as state ->
logInfo ("at MoveNextAsyncResult: case ", state)

ValueTask<bool>(this, version) // uses IValueTaskSource<'T>
ValueTask.ofIValueTaskSource this version
| _ ->
logInfo "at MoveNextAsyncResult: Unexpected state"
// assume it's a possibly new, not yet supported case, treat as default
ValueTask<bool>(this, version) // uses IValueTaskSource<'T>
ValueTask.ofIValueTaskSource this version

and TaskSeqCode<'T> = ResumableCode<TaskSeqStateMachineData<'T>, unit>
and TaskSeqStateMachine<'T> = ResumableStateMachine<TaskSeqStateMachineData<'T>>
Expand Down
16 changes: 15 additions & 1 deletion src/FSharp.Control.TaskSeq/Utils.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,26 @@ open System.Threading.Tasks
[<AutoOpen>]
module ValueTaskExtensions =
/// Extensions for ValueTask that are not available in NetStandard 2.1, but are
/// available in .NET 5+.
/// 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 = Unchecked.defaultof<ValueTask>


module ValueTask =
/// A successfully completed ValueTask of boolean that has the value false.
let False = ValueTask<bool>()

/// A successfully completed ValueTask of boolean that has the value true.
let True = ValueTask<bool> true

/// Creates a ValueTask with the supplied result of the successful operation.
let inline FromResult (x: 'T) = ValueTask<'T> x

/// Creates a ValueTask with an IValueTaskSource representing the operation
let inline ofIValueTaskSource taskSource version = ValueTask<bool>(taskSource, version)

module Task =
/// Convert an Async<'T> into a Task<'T>
let inline ofAsync (async: Async<'T>) = task { return! async }
Expand Down