Skip to content

Commit a02a410

Browse files
committed
Try fix vtask
1 parent e658508 commit a02a410

File tree

1 file changed

+70
-46
lines changed

1 file changed

+70
-46
lines changed

src/FSharpPlus/Extensions/ValueTask.fs

Lines changed: 70 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ module ValueTask =
2626
if x.IsCompleted then f x
2727
else x.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted (fun () -> f x)
2828

29-
let inline continueWith (x: ValueTask<'t>) f =
29+
let inline continueWith f (x: ValueTask<'t>) =
3030
if x.IsCompleted then f x
3131
else x.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted (fun () -> f x)
3232

33-
/// Creates a ValueTask from a value
33+
34+
/// <summary>Creates a ValueTask that's completed successfully with the specified value.</summary>
35+
/// <param name="value"></param>
36+
/// <returns>A ValueTask that is completed successfully with the specified value.</returns>
3437
let result (value: 'T) : ValueTask<'T> =
3538
#if NET5_0_OR_GREATER
3639
ValueTask.FromResult value
@@ -39,45 +42,72 @@ module ValueTask =
3942
tcs.SetResult value
4043
tcs.Task |> ValueTask<'T>
4144
#endif
45+
46+
/// <summary>Creates a ValueTask that's completed unsuccessfully with the specified exception.</summary>
47+
/// <param name="exn">The exception to be raised.</param>
48+
/// <returns>A ValueTask that is completed unsuccessfully with the specified exception.</returns>
49+
/// <remarks>
50+
/// If the exception is not an AggregateException it is wrapped into one.
51+
/// Prefer this function over ValueTask.FromException as it handles AggregateExceptions correctly.
52+
/// </remarks>
53+
let raise<'T> (exn: exn) : ValueTask<'T> =
54+
match exn with
55+
| :? AggregateException as agg when agg.InnerExceptions.Count > 1 ->
56+
let tcs = TaskCompletionSource<'T> ()
57+
tcs.SetException agg.InnerExceptions
58+
ValueTask<'T> tcs.Task
59+
| :? AggregateException as agg -> ValueTask.FromException<'T> agg.InnerExceptions[0]
60+
| exn -> ValueTask.FromException<'T> exn
4261

43-
/// <summary>Creates a ValueTask workflow from 'source' another, mapping its result with 'f'.</summary>
44-
/// <param name="f">The mapping function.</param>
45-
/// <param name="source">ValueTask workflow.</param>
46-
let map (f: 'T -> 'U) (source: ValueTask<'T>) : ValueTask<'U> =
47-
let tcs = TaskCompletionSource<'U> ()
48-
continueTask tcs source (fun x ->
49-
try tcs.SetResult (f x)
50-
with e -> tcs.SetException e)
51-
tcs.Task |> ValueTask<'U>
62+
let private cancellationTokenSingleton = CancellationToken true
63+
64+
/// <summary>Creates a ValueTask that's canceled.</summary>
65+
/// <returns>A ValueTask that's canceled.</returns>
66+
let canceled<'T> : ValueTask<'T> = ValueTask.FromCanceled<'T> cancellationTokenSingleton
67+
68+
/// <summary>Creates a ValueTask workflow from 'source' workflow, mapping its result with 'mapper'.</summary>
69+
/// <param name="mapper">The mapping function.</param>
70+
/// <param name="source">The source ValueTask workflow.</param>
71+
/// <returns>The resulting ValueTask workflow.</returns>
72+
let map (mapper: 'T -> 'U) (source: ValueTask<'T>) : ValueTask<'U> =
73+
if source.IsCompleted then
74+
match source with
75+
| Succeeded r -> try result (mapper r) with e -> raise e
76+
| Faulted exn -> raise exn
77+
| Canceled -> canceled
78+
else
79+
let tcs = TaskCompletionSource<'U> ()
80+
let k = function
81+
| Succeeded r -> try tcs.SetResult (mapper r) with e -> tcs.SetException e
82+
| Faulted exn -> tcs.SetException exn.InnerExceptions
83+
| Canceled -> tcs.SetCanceled ()
84+
continueWith k source
85+
ValueTask<'U> tcs.Task
5286

5387

5488
/// <summary>Creates a ValueTask workflow from two workflows 'x' and 'y', mapping its results with 'f'.</summary>
5589
/// <remarks>Workflows are run in sequence.</remarks>
5690
/// <param name="f">The mapping function.</param>
5791
/// <param name="x">First ValueTask workflow.</param>
5892
/// <param name="y">Second ValueTask workflow.</param>
59-
let lift2 (f: 'T -> 'U -> 'V) (x: ValueTask<'T>) (y: ValueTask<'U>) : ValueTask<'V> =
60-
let tcs = TaskCompletionSource<'V> ()
61-
continueTask tcs x (fun x ->
62-
continueTask tcs y (fun y ->
63-
try tcs.SetResult (f x y)
64-
with e -> tcs.SetException e))
65-
tcs.Task |> ValueTask<'V>
66-
93+
let lift2 (f: 'T1 -> 'T2 -> 'U) (task1: ValueTask<'T1>) (task2: ValueTask<'T2>) : ValueTask<'U> =
94+
let tcs = TaskCompletionSource<'U> ()
95+
continueTask tcs task1 (fun x ->
96+
continueTask tcs task2 (fun y -> try tcs.SetResult (f x y) with e -> tcs.SetException e))
97+
ValueTask<'U> tcs.Task
98+
6799
/// <summary>Creates a ValueTask workflow from three workflows 'x', 'y' and z, mapping its results with 'f'.</summary>
68100
/// <remarks>Workflows are run in sequence.</remarks>
69101
/// <param name="f">The mapping function.</param>
70102
/// <param name="x">First ValueTask workflow.</param>
71103
/// <param name="y">Second ValueTask workflow.</param>
72104
/// <param name="z">Third ValueTask workflow.</param>
73-
let lift3 (f: 'T -> 'U -> 'V -> 'W) (x: ValueTask<'T>) (y: ValueTask<'U>) (z: ValueTask<'V>) : ValueTask<'W> =
74-
let tcs = TaskCompletionSource<'W> ()
105+
let lift3 (f: 'T1 -> 'T2 -> 'T3 -> 'U) (x: ValueTask<'T1>) (y: ValueTask<'T2>) (z: ValueTask<'T3>) : ValueTask<'U> =
106+
let tcs = TaskCompletionSource<'U> ()
75107
continueTask tcs x (fun x ->
76108
continueTask tcs y (fun y ->
77-
continueTask tcs z (fun z ->
78-
try tcs.SetResult (f x y z)
79-
with e -> tcs.SetException e)))
80-
tcs.Task |> ValueTask<'W>
109+
continueTask tcs z (fun z -> try tcs.SetResult (f x y z) with e -> tcs.SetException e)))
110+
ValueTask<'U> tcs.Task
81111

82112
/// <summary>Creates a ValueTask workflow from two workflows, mapping its results with a specified function.</summary>
83113
/// <remarks>Similar to lift2 but although workflows are started in sequence they might end independently in different order
@@ -121,9 +151,9 @@ module ValueTask =
121151
task1 |> k r1 0
122152
task2 |> k r2 1
123153
else
124-
continueWith task1 (k r1 0)
125-
continueWith task2 (k r2 1)
126-
tcs.Task |> ValueTask<'U>
154+
continueWith (k r1 0) task1
155+
continueWith (k r2 1) task2
156+
ValueTask<'U> tcs.Task
127157

128158
/// <summary>Creates a ValueTask workflow from three workflows, mapping its results with a specified function.</summary>
129159
/// <remarks>Similar to lift3 but although workflows are started in sequence they might end independently in different order
@@ -139,7 +169,7 @@ module ValueTask =
139169
with e ->
140170
let tcs = TaskCompletionSource<_> ()
141171
tcs.SetException e
142-
tcs.Task |> ValueTask<'U>
172+
ValueTask<'U> tcs.Task
143173
else
144174
let tcs = TaskCompletionSource<_> ()
145175
let r1 = ref Unchecked.defaultof<_>
@@ -170,10 +200,10 @@ module ValueTask =
170200
task2 |> k r2 1
171201
task3 |> k r3 2
172202
else
173-
continueWith task1 (k r1 0)
174-
continueWith task2 (k r2 1)
175-
continueWith task3 (k r3 2)
176-
tcs.Task |> ValueTask<'U>
203+
continueWith (k r1 0) task1
204+
continueWith (k r2 1) task2
205+
continueWith (k r3 2) task3
206+
ValueTask<'U> tcs.Task
177207

178208
/// <summary>Creates a ValueTask workflow that is the result of applying the resulting function of a ValueTask workflow
179209
/// to the resulting value of another ValueTask workflow</summary>
@@ -182,18 +212,15 @@ module ValueTask =
182212
let apply (f: ValueTask<'T->'U>) (x: ValueTask<'T>) : ValueTask<'U> =
183213
let tcs = TaskCompletionSource<'U> ()
184214
continueTask tcs f (fun f ->
185-
continueTask tcs x (fun x ->
186-
try tcs.SetResult (f x)
187-
with e -> tcs.SetException e))
188-
tcs.Task |> ValueTask<'U>
215+
continueTask tcs x (fun x -> try tcs.SetResult (f x) with e -> tcs.SetException e))
216+
ValueTask<'U> tcs.Task
189217

190218
/// <summary>Creates a ValueTask workflow from two workflows 'x' and 'y', tupling its results.</summary>
191-
let zipSequentially (x: ValueTask<'T>) (y: ValueTask<'U>) : ValueTask<'T * 'U> =
192-
let tcs = TaskCompletionSource<'T * 'U> ()
193-
continueTask tcs x (fun x ->
194-
continueTask tcs y (fun y ->
195-
tcs.SetResult (x, y)))
196-
tcs.Task |> ValueTask<'T * 'U>
219+
let zipSequentially (task1: ValueTask<'T1>) (task2: ValueTask<'T2>) : ValueTask<'T1 * 'T2> =
220+
let tcs = TaskCompletionSource<'T1 * 'T2> ()
221+
continueTask tcs task1 (fun x ->
222+
continueTask tcs task2 (fun y -> tcs.SetResult (x, y)))
223+
ValueTask<'T1 * 'T2> tcs.Task
197224

198225
/// <summary>Creates a ValueTask workflow from two workflows, tupling its results.</summary>
199226
/// <remarks>Similar to zipSequentially but although workflows are started in sequence they might end independently in different order
@@ -306,7 +333,4 @@ module ValueTask =
306333
/// <returns>The option if the option is Some, else the alternate option.</returns>
307334
let orElse (fallbackValueTask: ValueTask<'T>) (source: ValueTask<'T>) : ValueTask<'T> = orElseWith (fun _ -> fallbackValueTask) source
308335

309-
/// Raises an exception in the ValueTask
310-
let raise<'TResult> (``exception``: exn) = ValueTask<'TResult> (Task.FromException<'TResult> ``exception``)
311-
312336
#endif

0 commit comments

Comments
 (0)