Skip to content

Commit cde6790

Browse files
committed
Merge remote-tracking branch 'origin/master' into v1.3
2 parents 13ff2c6 + 5b61ffc commit cde6790

File tree

5 files changed

+111
-61
lines changed

5 files changed

+111
-61
lines changed

src/FSharpPlus/Control/Comonad.fs

Lines changed: 18 additions & 5 deletions
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/Control/Monad.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ type Return =
145145
static member Return (_: 'T Task , _: Return ) = fun x -> Task.FromResult x : 'T Task
146146
#endif
147147
#if NETSTANDARD2_1 && !FABLE_COMPILER
148-
static member Return (_: 'T ValueTask , _: Return ) = fun x -> ValueTask.FromResult x : 'T ValueTask
148+
static member Return (_: 'T ValueTask , _: Return ) = fun (x: 'T) -> ValueTask<'T> x : 'T ValueTask
149149
#endif
150150
static member Return (_: option<'a> , _: Return ) = fun x -> Some x : option<'a>
151151
static member Return (_ : voption<'a> , _: Return ) = fun x -> ValueSome x : voption<'a>

src/FSharpPlus/Extensions/ValueTask.fs

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,99 +5,113 @@ namespace FSharpPlus
55
/// Additional operations on ValueTask<'T>
66
[<RequireQualifiedAccess>]
77
module ValueTask =
8-
9-
open System.Threading
8+
109
open System.Threading.Tasks
10+
11+
let inline internal (|Succeeded|Canceled|Faulted|) (t: ValueTask<'T>) =
12+
if t.IsCompletedSuccessfully then Succeeded t.Result
13+
elif t.IsCanceled then Canceled
14+
else Faulted (t.AsTask().Exception.InnerExceptions)
1115

12-
let FromResult<'T> (result : 'T) =
13-
ValueTask<'T>(result)
14-
15-
let FromException<'T> (e : exn) =
16-
ValueTask<'T>(Task.FromException<'T>(e))
17-
18-
let FromCanceled<'T> (ct : CancellationToken) =
19-
ValueTask<'T>(Task.FromCanceled<'T>(ct))
20-
21-
let FromTask<'T> (t : Task<'T>) =
22-
ValueTask<'T>(t)
16+
let inline internal continueTask (tcs: TaskCompletionSource<'Result>) (x: ValueTask<'t>) (k: 't -> unit) =
17+
let f = function
18+
| Succeeded r -> k r
19+
| Canceled -> tcs.SetCanceled ()
20+
| Faulted e -> tcs.SetException e
21+
if x.IsCompleted then f x
22+
else
23+
let aw = x.GetAwaiter ()
24+
aw.OnCompleted (fun () -> f x)
2325

2426
/// <summary>Creates a ValueTask workflow from 'source' another, mapping its result with 'f'.</summary>
27+
/// <param name="f">The mapping function.</param>
28+
/// <param name="source">ValueTask workflow.</param>
2529
let map (f: 'T -> 'U) (source: ValueTask<'T>) : ValueTask<'U> =
26-
backgroundTask {
27-
let! r = source
28-
return f r
29-
} |> ValueTask<'U>
30+
let tcs = TaskCompletionSource<'U> ()
31+
continueTask tcs source (fun x ->
32+
try tcs.SetResult (f x)
33+
with e -> tcs.SetException e)
34+
tcs.Task |> ValueTask<'U>
35+
3036

3137
/// <summary>Creates a ValueTask workflow from two workflows 'x' and 'y', mapping its results with 'f'.</summary>
3238
/// <remarks>Workflows are run in sequence.</remarks>
3339
/// <param name="f">The mapping function.</param>
3440
/// <param name="x">First ValueTask workflow.</param>
3541
/// <param name="y">Second ValueTask workflow.</param>
3642
let map2 (f: 'T -> 'U -> 'V) (x: ValueTask<'T>) (y: ValueTask<'U>) : ValueTask<'V> =
37-
backgroundTask {
38-
let! rX = x
39-
let! rY = y
40-
return f rX rY
41-
} |> ValueTask<'V>
43+
let tcs = TaskCompletionSource<'V> ()
44+
continueTask tcs x (fun x ->
45+
continueTask tcs y (fun y ->
46+
try tcs.SetResult (f x y)
47+
with e -> tcs.SetException e))
48+
tcs.Task |> ValueTask<'V>
4249

4350
/// <summary>Creates a ValueTask workflow from three workflows 'x', 'y' and z, mapping its results with 'f'.</summary>
4451
/// <remarks>Workflows are run in sequence.</remarks>
4552
/// <param name="f">The mapping function.</param>
4653
/// <param name="x">First ValueTask workflow.</param>
4754
/// <param name="y">Second ValueTask workflow.</param>
4855
/// <param name="z">Third ValueTask workflow.</param>
49-
let map3 (f : 'T -> 'U -> 'V -> 'W) (x : ValueTask<'T>) (y : ValueTask<'U>) (z: ValueTask<'V>) : ValueTask<'W> =
50-
backgroundTask {
51-
let! rX = x
52-
let! rY = y
53-
let! rZ = z
54-
return f rX rY rZ
55-
} |> ValueTask<'W>
56+
let map3 (f: 'T -> 'U -> 'V -> 'W) (x: ValueTask<'T>) (y: ValueTask<'U>) (z: ValueTask<'V>) : ValueTask<'W> =
57+
let tcs = TaskCompletionSource<'W> ()
58+
continueTask tcs x (fun x ->
59+
continueTask tcs y (fun y ->
60+
continueTask tcs z (fun z ->
61+
try tcs.SetResult (f x y z)
62+
with e -> tcs.SetException e)))
63+
tcs.Task |> ValueTask<'W>
5664

5765
/// <summary>Creates a ValueTask workflow that is the result of applying the resulting function of a ValueTask workflow
5866
/// to the resulting value of another ValueTask workflow</summary>
5967
/// <param name="f">ValueTask workflow returning a function</param>
6068
/// <param name="x">ValueTask workflow returning a value</param>
6169
let apply (f: ValueTask<'T->'U>) (x: ValueTask<'T>) : ValueTask<'U> =
62-
backgroundTask {
63-
let! r = x
64-
let! fn = f
65-
return (fn r)
66-
} |> ValueTask<'U>
70+
let tcs = TaskCompletionSource<'U> ()
71+
continueTask tcs f (fun f ->
72+
continueTask tcs x (fun x ->
73+
try tcs.SetResult (f x)
74+
with e -> tcs.SetException e))
75+
tcs.Task |> ValueTask<'U>
6776

6877
/// <summary>Creates a ValueTask workflow from two workflows 'x' and 'y', tupling its results.</summary>
6978
let zip (x: ValueTask<'T>) (y: ValueTask<'U>) : ValueTask<'T * 'U> =
70-
backgroundTask {
71-
let! rX = x
72-
let! rY = y
73-
return (rX, rY)
74-
} |> ValueTask<'T * 'U>
79+
let tcs = TaskCompletionSource<'T * 'U> ()
80+
continueTask tcs x (fun x ->
81+
continueTask tcs y (fun y ->
82+
tcs.SetResult (x, y)))
83+
tcs.Task |> ValueTask<'T * 'U>
7584

7685
/// Flattens two nested ValueTask into one.
7786
let join (source: ValueTask<ValueTask<'T>>) : ValueTask<'T> =
78-
backgroundTask {
79-
let! s = source
80-
return! s
81-
} |> ValueTask<'T>
87+
let tcs = TaskCompletionSource<'T> ()
88+
continueTask tcs source (fun x ->
89+
continueTask tcs x (fun x ->
90+
tcs.SetResult x))
91+
tcs.Task |> ValueTask<'T>
8292

8393

8494
/// <summary>Creates a ValueTask workflow from 'source' workflow, mapping and flattening its result with 'f'.</summary>
8595
let bind (f: 'T -> ValueTask<'U>) (source: ValueTask<'T>) : ValueTask<'U> =
86-
source
87-
|> map f
88-
|> join
96+
let tcs = TaskCompletionSource<'U> ()
97+
continueTask tcs source (fun x ->
98+
try
99+
continueTask tcs (f x) (fun fx ->
100+
tcs.SetResult fx)
101+
with e -> tcs.SetException e)
102+
tcs.Task |> ValueTask<'U>
89103

90104
/// <summary>Creates a ValueTask that ignores the result of the source ValueTask.</summary>
91105
/// <remarks>It can be used to convert non-generic ValueTask to unit ValueTask.</remarks>
92106
let ignore (source: ValueTask<'T>) =
93-
backgroundTask {
94-
let! _ = source
95-
return ()
96-
} |> ValueTask
107+
if source.IsCompletedSuccessfully then
108+
source.GetAwaiter().GetResult() |> ignore
109+
Unchecked.defaultof<_>
110+
else
111+
new ValueTask (source.AsTask ())
97112

98113

99114
/// Raises an exception in the ValueTask
100-
let raise (e: exn) =
101-
FromException e
115+
let raise (``exception``: exn) = ValueTask<'TResult> (Task.FromException<'TResult> ``exception``)
102116

103117
#endif

src/FSharpPlus/FSharpPlus.fsproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
2525
<Configurations>Debug;Release;Fable;Fable3</Configurations>
2626
<Platforms>AnyCPU</Platforms>
27-
<LangVersion Condition=" '$(Configuration)' == 'Fable' OR '$(Configuration)' == 'Fable3' ">6.0</LangVersion>
27+
<LangVersion>6.0</LangVersion>
2828
<DefineConstants Condition=" '$(Configuration)' == 'Fable'">$(DefineConstants);FABLE_COMPILER</DefineConstants>
2929
<DefineConstants Condition=" '$(Configuration)' == 'Fable3'">$(DefineConstants);FABLE_COMPILER;FABLE_COMPILER_3</DefineConstants>
3030
<!--<OutputPath>..\..\bin</OutputPath>-->

tests/FSharpPlus.Tests/ValueTask.fs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,35 @@ module ValueTask =
1212

1313
exception TestException of string
1414

15+
16+
module ValueTask =
17+
18+
// Following is not available in F#6
19+
20+
/// <summary>Creates a <see cref="ValueTask{TResult}"/> that's completed successfully with the specified result.</summary>
21+
/// <typeparam name="TResult">The type of the result returned by the task.</typeparam>
22+
/// <param name="result">The result to store into the completed task.</param>
23+
/// <returns>The successfully completed task.</returns>
24+
let FromResult<'TResult> (result: 'TResult) = ValueTask<'TResult> result
25+
26+
/// <summary>Creates a <see cref="ValueTask{TResult}"/> that's completed exceptionally with the specified exception.</summary>
27+
/// <typeparam name="TResult">The type of the result returned by the task.</typeparam>
28+
/// <param name="exception">The exception with which to complete the task.</param>
29+
/// <returns>The faulted task.</returns>
30+
let FromException<'TResult> (``exception``: exn) = ValueTask<'TResult> (Task.FromException<'TResult> ``exception``)
31+
32+
/// <summary>Creates a <see cref="ValueTask{TResult}"/> that's completed due to cancellation with the specified token.</summary>
33+
/// <typeparam name="TResult">The type of the result returned by the task.</typeparam>
34+
/// <param name="cancellationToken">The token with which to complete the task.</param>
35+
/// <returns>The canceled task.</returns>
36+
let FromCanceled<'TResult> (cancellationToken: CancellationToken) = ValueTask<'TResult> (Task.FromCanceled<'TResult> cancellationToken)
37+
1538
module ValueTaskTests =
1639

1740
let createValueTask isFailed value =
18-
if not isFailed then ValueTask.FromResult value
41+
if not isFailed then ValueTask.FromResult<_> value
1942
else
20-
ValueTask.FromException (TestException (sprintf "Ouch, can't create: %A" value ))
43+
ValueTask.FromException<_> (TestException (sprintf "Ouch, can't create: %A" value ))
2144

2245
let (|AggregateException|_|) (x: exn) =
2346
match x with

0 commit comments

Comments
 (0)