Skip to content

Commit 94a0704

Browse files
authored
Merge branch 'forloop-with-iasyncenumerable-with-task-and-async' into forloop-with-iasyncenumerable-with-task-and-async-2
2 parents fe1aafa + 16df03d commit 94a0704

File tree

4 files changed

+32
-11
lines changed

4 files changed

+32
-11
lines changed

src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Generates optimized IL code through the new resumable state machines, and comes
2424
<PackageReleaseNotes>
2525
Release notes:
2626
0.2.3
27+
- improve TaskSeq.empty by not relying on resumable state, #89
2728
- do not throw exception for unequal lengths in TaskSeq.zip, fixes #32
2829
0.2.2
2930
- removes TaskSeq.toSeqCachedAsync, which was incorrectly named. Use toSeq or toListAsync instead.

src/FSharp.Control.TaskSeq/TaskSeq.fs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,15 @@ module TaskSeq =
1313
// Just for convenience
1414
module Internal = TaskSeqInternal
1515

16-
let empty<'T> = taskSeq {
17-
for c: 'T in [] do
18-
yield c
19-
}
16+
let empty<'T> =
17+
{ new IAsyncEnumerable<'T> with
18+
member _.GetAsyncEnumerator(_) =
19+
{ new IAsyncEnumerator<'T> with
20+
member _.MoveNextAsync() = ValueTask.False
21+
member _.Current = Unchecked.defaultof<'T>
22+
member _.DisposeAsync() = ValueTask.CompletedTask
23+
}
24+
}
2025

2126
let isEmpty source = Internal.isEmpty source
2227

@@ -423,7 +428,7 @@ module AsyncSeqExtensions =
423428
sm.Data.MethodBuilder.AwaitUnsafeOnCompleted(&awaiter, &sm)
424429
false)
425430
)
426-
431+
427432
member inline this.For
428433
(
429434
tasksq: IAsyncEnumerable<'T>,

src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ open System.Threading.Tasks.Sources
1313

1414
open FSharp.Core.CompilerServices
1515
open FSharp.Core.CompilerServices.StateMachineHelpers
16+
open FSharp.Control
1617

1718

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

282-
ValueTask<bool>()
283+
ValueTask.False
283284

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

287288
// return False when beyond the last item
288289
this._machine.Data.promiseOfValueOrEnd.Reset()
289-
ValueTask<bool>()
290+
ValueTask.False
290291

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

346-
ValueTask<bool>(result)
347+
ValueTask.FromResult result
347348

348349
| ValueTaskSourceStatus.Faulted
349350
| ValueTaskSourceStatus.Canceled
350351
| ValueTaskSourceStatus.Pending as state ->
351352
logInfo ("at MoveNextAsyncResult: case ", state)
352353

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

359360
and TaskSeqCode<'T> = ResumableCode<TaskSeqStateMachineData<'T>, unit>
360361
and TaskSeqStateMachine<'T> = ResumableStateMachine<TaskSeqStateMachineData<'T>>

src/FSharp.Control.TaskSeq/Utils.fs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,26 @@ open System.Threading.Tasks
55
[<AutoOpen>]
66
module ValueTaskExtensions =
77
/// Extensions for ValueTask that are not available in NetStandard 2.1, but are
8-
/// available in .NET 5+.
8+
/// available in .NET 5+. We put them in Extension space to mimic the behavior of NetStandard 2.1
99
type ValueTask with
1010

1111
/// (Extension member) Gets a task that has already completed successfully.
1212
static member inline CompletedTask = Unchecked.defaultof<ValueTask>
1313

14+
15+
module ValueTask =
16+
/// A successfully completed ValueTask of boolean that has the value false.
17+
let False = ValueTask<bool>()
18+
19+
/// A successfully completed ValueTask of boolean that has the value true.
20+
let True = ValueTask<bool> true
21+
22+
/// Creates a ValueTask with the supplied result of the successful operation.
23+
let inline FromResult (x: 'T) = ValueTask<'T> x
24+
25+
/// Creates a ValueTask with an IValueTaskSource representing the operation
26+
let inline ofIValueTaskSource taskSource version = ValueTask<bool>(taskSource, version)
27+
1428
module Task =
1529
/// Convert an Async<'T> into a Task<'T>
1630
let inline ofAsync (async: Async<'T>) = task { return! async }

0 commit comments

Comments
 (0)