Skip to content

Commit b58d19a

Browse files
gustywallymathieu
authored andcommitted
Enable try blocks for ValueTask
1 parent 3bf4186 commit b58d19a

3 files changed

Lines changed: 806 additions & 13 deletions

File tree

src/FSharpPlus/Control/Monad.fs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ type TryWith =
232232
static member TryWith (computation: unit -> Async<_> , catchHandler: exn -> Async<_> , _: TryWith , _) = async.TryWith ((computation ()), catchHandler)
233233
#if !FABLE_COMPILER
234234
static member TryWith (computation: unit -> Task<_> , catchHandler: exn -> Task<_> , _: TryWith, True) = Task.tryWith computation catchHandler
235+
static member TryWith (computation: unit -> ValueTask<_> , catchHandler: exn -> ValueTask<_> , _: TryWith, True) = ValueTask.tryWith catchHandler computation
235236
#endif
236237
static member TryWith (computation: unit -> Lazy<_> , catchHandler: exn -> Lazy<_> , _: TryWith , _) = lazy (try (computation ()).Force () with e -> (catchHandler e).Force ()) : Lazy<_>
237238

@@ -270,7 +271,8 @@ type TryFinally =
270271
static member TryFinally ((computation: unit -> Id<_> , compensation: unit -> unit), _: TryFinally, _, _) = try computation () finally compensation ()
271272
static member TryFinally ((computation: unit -> Async<_>, compensation: unit -> unit), _: TryFinally, _, _) = async.TryFinally (computation (), compensation) : Async<_>
272273
#if !FABLE_COMPILER
273-
static member TryFinally ((computation: unit -> Task<_> , compensation: unit -> unit), _: TryFinally, _, True) = Task.tryFinally computation compensation : Task<_>
274+
static member TryFinally ((computation: unit -> Task<_> , compensation: unit -> unit), _: TryFinally, _, True) = Task.tryFinally computation compensation : Task<_>
275+
static member TryFinally ((computation: unit -> ValueTask<_>, compensation: unit -> unit), _: TryFinally, _, True) = ValueTask.tryFinally compensation computation : ValueTask<_>
274276
#endif
275277
static member TryFinally ((computation: unit -> Lazy<_> , compensation: unit -> unit), _: TryFinally, _, _) = lazy (try (computation ()).Force () finally compensation ()) : Lazy<_>
276278

@@ -307,7 +309,8 @@ type Using =
307309
static member Using (resource: 'T when 'T :> IDisposable, body: 'T -> 'R -> 'U , _: Using ) = (fun s -> try body resource s finally if not (isNull (box resource)) then resource.Dispose ()) : 'R->'U
308310
static member Using (resource: 'T when 'T :> IDisposable, body: 'T -> Async<'U>, _: Using ) = async.Using (resource, body)
309311
#if !FABLE_COMPILER
310-
static member Using (resource: 'T when 'T :> IDisposable, body: 'T -> Task<'U>, _: Using ) = Task.using resource body
312+
static member Using (resource: 'T when 'T :> IDisposable, body: 'T -> Task<'U> , _: Using) = Task.using resource body
313+
static member Using (resource: 'T when 'T :> IDisposable, body: 'T -> ValueTask<'U>, _: Using) = ValueTask.using resource body
311314
#endif
312315
static member Using (resource: 'T when 'T :> IDisposable, body: 'T -> Lazy<'U> , _: Using ) = lazy (try (body resource).Force () finally if not (isNull (box resource)) then resource.Dispose ()) : Lazy<'U>
313316

src/FSharpPlus/Extensions/ValueTask.fs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,58 @@ module ValueTask =
241241
else source.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted (fun () -> k source)
242242
tcs.Task |> ValueTask<unit>
243243

244+
/// Used to de-sugar try .. with .. blocks in Computation Expressions.
245+
let inline tryWith ([<InlineIfLambda>]compensation: exn -> ValueTask<'T>) ([<InlineIfLambda>]body: unit -> ValueTask<'T>) : ValueTask<'T> =
246+
let unwrapException (agg: AggregateException) =
247+
if agg.InnerExceptions.Count = 1 then agg.InnerExceptions.[0]
248+
else agg :> Exception
249+
try
250+
let task = body ()
251+
if task.IsCompleted then
252+
match task with
253+
| Succeeded _ -> task
254+
| Faulted exn -> compensation (unwrapException exn)
255+
| Canceled -> compensation (TaskCanceledException ())
256+
else
257+
let tcs = TaskCompletionSource<'T> ()
258+
let f = function
259+
| Succeeded r -> tcs.SetResult r
260+
| Faulted exn -> continueTask tcs (compensation (unwrapException exn)) (fun r -> try tcs.SetResult r with e -> tcs.SetException e)
261+
| Canceled -> continueTask tcs (compensation (TaskCanceledException ())) (fun r -> try tcs.SetResult r with e -> tcs.SetException e)
262+
task.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted (fun () -> f task)
263+
ValueTask<'T> tcs.Task
264+
with
265+
| :? AggregateException as exn -> compensation (unwrapException exn)
266+
| exn -> compensation exn
267+
268+
/// Used to de-sugar try .. finally .. blocks in Computation Expressions.
269+
let inline tryFinally ([<InlineIfLambda>]compensation : unit -> unit) ([<InlineIfLambda>]body: unit -> ValueTask<'T>) : ValueTask<'T> =
270+
let mutable ran = false
271+
let compensation () =
272+
if not ran then
273+
compensation ()
274+
ran <- true
275+
try
276+
let task = body ()
277+
if task.IsCompleted then compensation (); task
278+
else
279+
let tcs = TaskCompletionSource<'T> ()
280+
let f = function
281+
| Succeeded r -> tcs.SetResult r
282+
| Faulted exn -> tcs.SetException exn.InnerExceptions
283+
| Canceled -> tcs.SetCanceled ()
284+
task.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted (fun () -> compensation (); f task)
285+
ValueTask<'T> tcs.Task
286+
with _ ->
287+
compensation ()
288+
reraise ()
289+
290+
/// Used to de-sugar use .. blocks in Computation Expressions.
291+
let inline using (disp: 'T when 'T :> IDisposable) ([<InlineIfLambda>]body: 'T -> ValueTask<'U>) =
292+
tryFinally
293+
(fun () -> if not (isNull (box disp)) then disp.Dispose ())
294+
(fun () -> body disp)
295+
244296

245297
/// Raises an exception in the ValueTask
246298
let raise<'TResult> (``exception``: exn) = ValueTask<'TResult> (Task.FromException<'TResult> ``exception``)

0 commit comments

Comments
 (0)