Skip to content

Commit 68588db

Browse files
committedDec 2, 2022
Avoid use of backgroundTask CE

File tree

2 files changed

+82
-44
lines changed

2 files changed

+82
-44
lines changed
 

‎src/FSharpPlus/Control/Comonad.fs

+18-5
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,27 @@ type Extend =
6262
elif k.Status = TaskStatus.Canceled then tcs.SetCanceled ()
6363
elif k.Status = TaskStatus.Faulted then tcs.SetException k.Exception.InnerExceptions) |> ignore
6464
tcs.Task
65-
66-
6765
#endif
66+
6867
#if NETSTANDARD2_1 && !FABLE_COMPILER
6968
static member (=>>) (g: ValueTask<'T> , f: ValueTask<'T> -> 'U ) : ValueTask<'U> =
70-
backgroundTask {
71-
return! f g
72-
} |> ValueTask<'U>
69+
if g.IsCompletedSuccessfully then
70+
try
71+
let r = f g
72+
ValueTask<'U> r
73+
with e -> ValueTask<'U> (Task.FromException<'U> e)
74+
else
75+
let tcs = TaskCompletionSource<'U> ()
76+
if g.IsCompleted then
77+
match g with
78+
| ValueTask.Faulted e -> tcs.SetException e
79+
| ValueTask.Canceled -> tcs.SetCanceled ()
80+
else
81+
ValueTask.continueTask tcs g (fun _ ->
82+
try tcs.SetResult (f g)
83+
with e -> tcs.SetException e)
84+
tcs.Task |> ValueTask<'U>
85+
7386
#endif
7487

7588
// Restricted Comonads

‎src/FSharpPlus/Extensions/ValueTask.fs

+64-39
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ module ValueTask =
88

99
open System.Threading
1010
open System.Threading.Tasks
11+
12+
let inline internal (|Succeeded|Canceled|Faulted|) (t: ValueTask<'T>) =
13+
if t.IsCompletedSuccessfully then Succeeded t.Result
14+
elif t.IsCanceled then Canceled
15+
else Faulted (t.AsTask().Exception.InnerExceptions)
1116

1217
/// <summary>Creates a <see cref="ValueTask{TResult}"/> that's completed successfully with the specified result.</summary>
1318
/// <typeparam name="TResult">The type of the result returned by the task.</typeparam>
@@ -31,83 +36,103 @@ module ValueTask =
3136
/// <param name="source">Task workflow.</param>
3237
let FromTask<'TResult> (source: Task<'TResult>) = ValueTask<'TResult> source
3338

39+
let inline internal continueTask (tcs: TaskCompletionSource<'Result>) (x: ValueTask<'t>) (k: 't -> unit) =
40+
let f = function
41+
| Succeeded r -> k r
42+
| Canceled -> tcs.SetCanceled ()
43+
| Faulted e -> tcs.SetException e
44+
if x.IsCompleted then f x
45+
else
46+
let aw = x.GetAwaiter ()
47+
aw.OnCompleted (fun () -> f x)
48+
3449
/// <summary>Creates a ValueTask workflow from 'source' another, mapping its result with 'f'.</summary>
3550
let map (f: 'T -> 'U) (source: ValueTask<'T>) : ValueTask<'U> =
36-
backgroundTask {
37-
let! r = source
38-
return f r
39-
} |> ValueTask<'U>
51+
let tcs = TaskCompletionSource<'U> ()
52+
continueTask tcs source (fun x ->
53+
try tcs.SetResult (f x)
54+
with e -> tcs.SetException e)
55+
tcs.Task |> ValueTask<'U>
56+
4057

4158
/// <summary>Creates a ValueTask workflow from two workflows 'x' and 'y', mapping its results with 'f'.</summary>
4259
/// <remarks>Workflows are run in sequence.</remarks>
4360
/// <param name="f">The mapping function.</param>
4461
/// <param name="x">First ValueTask workflow.</param>
4562
/// <param name="y">Second ValueTask workflow.</param>
4663
let map2 (f: 'T -> 'U -> 'V) (x: ValueTask<'T>) (y: ValueTask<'U>) : ValueTask<'V> =
47-
backgroundTask {
48-
let! rX = x
49-
let! rY = y
50-
return f rX rY
51-
} |> ValueTask<'V>
64+
let tcs = TaskCompletionSource<'V> ()
65+
continueTask tcs x (fun x ->
66+
continueTask tcs y (fun y ->
67+
try tcs.SetResult (f x y)
68+
with e -> tcs.SetException e))
69+
tcs.Task |> ValueTask<'V>
5270

5371
/// <summary>Creates a ValueTask workflow from three workflows 'x', 'y' and z, mapping its results with 'f'.</summary>
5472
/// <remarks>Workflows are run in sequence.</remarks>
5573
/// <param name="f">The mapping function.</param>
5674
/// <param name="x">First ValueTask workflow.</param>
5775
/// <param name="y">Second ValueTask workflow.</param>
5876
/// <param name="z">Third ValueTask workflow.</param>
59-
let map3 (f : 'T -> 'U -> 'V -> 'W) (x : ValueTask<'T>) (y : ValueTask<'U>) (z: ValueTask<'V>) : ValueTask<'W> =
60-
backgroundTask {
61-
let! rX = x
62-
let! rY = y
63-
let! rZ = z
64-
return f rX rY rZ
65-
} |> ValueTask<'W>
77+
let map3 (f: 'T -> 'U -> 'V -> 'W) (x: ValueTask<'T>) (y: ValueTask<'U>) (z: ValueTask<'V>) : ValueTask<'W> =
78+
let tcs = TaskCompletionSource<'W> ()
79+
continueTask tcs x (fun x ->
80+
continueTask tcs y (fun y ->
81+
continueTask tcs z (fun z ->
82+
try tcs.SetResult (f x y z)
83+
with e -> tcs.SetException e)))
84+
tcs.Task |> ValueTask<'W>
6685

6786
/// <summary>Creates a ValueTask workflow that is the result of applying the resulting function of a ValueTask workflow
6887
/// to the resulting value of another ValueTask workflow</summary>
6988
/// <param name="f">ValueTask workflow returning a function</param>
7089
/// <param name="x">ValueTask workflow returning a value</param>
7190
let apply (f: ValueTask<'T->'U>) (x: ValueTask<'T>) : ValueTask<'U> =
72-
backgroundTask {
73-
let! r = x
74-
let! fn = f
75-
return (fn r)
76-
} |> ValueTask<'U>
91+
let tcs = TaskCompletionSource<'U> ()
92+
continueTask tcs f (fun f ->
93+
continueTask tcs x (fun x ->
94+
try tcs.SetResult (f x)
95+
with e -> tcs.SetException e))
96+
tcs.Task |> ValueTask<'U>
7797

7898
/// <summary>Creates a ValueTask workflow from two workflows 'x' and 'y', tupling its results.</summary>
7999
let zip (x: ValueTask<'T>) (y: ValueTask<'U>) : ValueTask<'T * 'U> =
80-
backgroundTask {
81-
let! rX = x
82-
let! rY = y
83-
return (rX, rY)
84-
} |> ValueTask<'T * 'U>
100+
let tcs = TaskCompletionSource<'T * 'U> ()
101+
continueTask tcs x (fun x ->
102+
continueTask tcs y (fun y ->
103+
tcs.SetResult (x, y)))
104+
tcs.Task |> ValueTask<'T * 'U>
85105

86106
/// Flattens two nested ValueTask into one.
87107
let join (source: ValueTask<ValueTask<'T>>) : ValueTask<'T> =
88-
backgroundTask {
89-
let! s = source
90-
return! s
91-
} |> ValueTask<'T>
108+
let tcs = TaskCompletionSource<'T> ()
109+
continueTask tcs source (fun x ->
110+
continueTask tcs x (fun x ->
111+
tcs.SetResult x))
112+
tcs.Task |> ValueTask<'T>
92113

93114

94115
/// <summary>Creates a ValueTask workflow from 'source' workflow, mapping and flattening its result with 'f'.</summary>
95116
let bind (f: 'T -> ValueTask<'U>) (source: ValueTask<'T>) : ValueTask<'U> =
96-
source
97-
|> map f
98-
|> join
117+
let tcs = TaskCompletionSource<'U> ()
118+
continueTask tcs source (fun x ->
119+
try
120+
continueTask tcs (f x) (fun fx ->
121+
tcs.SetResult fx)
122+
with e -> tcs.SetException e)
123+
tcs.Task |> ValueTask<'U>
99124

100125
/// <summary>Creates a ValueTask that ignores the result of the source ValueTask.</summary>
101126
/// <remarks>It can be used to convert non-generic ValueTask to unit ValueTask.</remarks>
102127
let ignore (source: ValueTask<'T>) =
103-
backgroundTask {
104-
let! _ = source
105-
return ()
106-
} |> ValueTask
128+
if source.IsCompletedSuccessfully then
129+
source.GetAwaiter().GetResult() |> ignore
130+
Unchecked.defaultof<_>
131+
else
132+
new ValueTask (source.AsTask ())
107133

108134

109135
/// Raises an exception in the ValueTask
110-
let raise (e: exn) =
111-
FromException e
136+
let raise (e: exn) = FromException e
112137

113138
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.