Skip to content

Commit

Permalink
use copy of initial state machine to get resumption back to zero
Browse files Browse the repository at this point in the history
  • Loading branch information
dsyme authored and abelbraaksma committed Oct 28, 2022
1 parent c095488 commit cfd09c4
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/FSharpy.TaskSeq.Test/TaskSeq.Iter.Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ let ``TaskSeq-iter multiple iterations over same sequence`` () = task {
do! tq |> TaskSeq.iter (fun item -> sum <- sum + item)
do! tq |> TaskSeq.iter (fun item -> sum <- sum + item)
do! tq |> TaskSeq.iter (fun item -> sum <- sum + item)
sum |> should equal 220 // task-dummies started at 1
sum |> should equal 820 // task-dummies started at 1
}

[<Fact>]
Expand Down
6 changes: 3 additions & 3 deletions src/FSharpy.TaskSeq.Test/TaskSeq.ToXXX.Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ let ``TaskSeq-toArrayAsync can be applied multiple times to the same sequence``
let! (results3: _[]) = tq |> TaskSeq.toArrayAsync
let! (results4: _[]) = tq |> TaskSeq.toArrayAsync
results1 |> should equal [| 1..10 |]
results2 |> should equal [| 1..10 |]
results3 |> should equal [| 1..10 |]
results4 |> should equal [| 1..10 |]
results2 |> should equal [| 11..20 |]
results3 |> should equal [| 21..30 |]
results4 |> should equal [| 31..40 |]
}

[<Fact>]
Expand Down
27 changes: 6 additions & 21 deletions src/FSharpy.TaskSeq/TaskSeqBuilder.fs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ and [<NoComparison; NoEquality>] TaskSeq<'Machine, 'T
inherit TaskSeq<'T>()
let initialThreadId = Environment.CurrentManagedThreadId

[<DefaultValue(false)>]
val mutable InitialMachine: 'Machine

[<DefaultValue(false)>]
val mutable Machine: 'Machine

Expand Down Expand Up @@ -247,7 +250,6 @@ and [<NoComparison; NoEquality>] TaskSeq<'Machine, 'T
(not data.taken
&& initialThreadId = Environment.CurrentManagedThreadId)
then
//let clone = this.MemberwiseClone() :?> TaskSeq<'Machine, 'T>
let data = this.Machine.Data
data.taken <- true
data.cancellationToken <- ct
Expand All @@ -274,24 +276,7 @@ and [<NoComparison; NoEquality>] TaskSeq<'Machine, 'T
// iteration twice, we are trying to *await* twice, which is not allowed
// see, for instance: https://itnext.io/why-can-a-valuetask-only-be-awaited-once-31169b324fa4
let clone = this.MemberwiseClone() :?> TaskSeq<'Machine, 'T>
data.taken <- true

// Explanation for resetting Machine use brute-force
//
// This appears to fix the problem that ResumptionPoint was not reset. I'd prefer
// a less drastical method. It solves a scenario like the following:
// let ts = taskSeq { yield 1; yield 2 }
// let e1 = ts.GetAsyncEnumerator()
// let! hasNext = e.MoveNextAsync()
// let e2 = ts.GetAsyncEnumerator()
// let! hasNext = e.MoveNextAsync() // without this hack, it would continue where e1 left off
// let a = e1.Current
// let b = e2.Current
// let isTrue = a = b // true with this, false without it
clone.Machine <- Unchecked.defaultof<_>
//clone.Machine.ResumptionPoint <- 0

// the following lines just re-initialize the key data fields State.
clone.Machine <- clone.InitialMachine
clone.Machine.Data <- TaskSeqStateMachineData()
clone.Machine.Data.cancellationToken <- ct
clone.Machine.Data.taken <- true
Expand All @@ -301,10 +286,9 @@ and [<NoComparison; NoEquality>] TaskSeq<'Machine, 'T
printfn "All data after clone:"
clone.Machine.Data.LogDump()


//// calling reset causes NRE in IValueTaskSource.GetResult above
//clone.Machine.Data.promiseOfValueOrEnd.Reset()
//clone.Machine.Data.boxed <- clone
clone.Machine.Data.boxed <- clone
////clone.Machine.Data.disposalStack <- null // reference type, would otherwise still reference original stack
//////clone.Machine.Data.tailcallTarget <- Some clone // this will lead to an SO exception
//clone.Machine.Data.awaiter <- null
Expand Down Expand Up @@ -521,6 +505,7 @@ type TaskSeqBuilder() =
printfn "at AfterCode<_, _>, setting the Machine field to the StateMachine"

let ts = TaskSeq<TaskSeqStateMachine<'T>, 'T>()
ts.InitialMachine <- sm
ts.Machine <- sm
ts.Machine.Data <- TaskSeqStateMachineData()
ts.Machine.Data.boxed <- ts
Expand Down

0 comments on commit cfd09c4

Please sign in to comment.