Skip to content

Commit 78d9daa

Browse files
committed
Add BackgroundTaskOption
1 parent 181505b commit 78d9daa

File tree

5 files changed

+705
-25
lines changed

5 files changed

+705
-25
lines changed

src/FsToolkit.ErrorHandling.TaskResult/TaskOptionCE.fs

Lines changed: 240 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ open System.Threading.Tasks
55

66

77
#if NETSTANDARD2_0
8-
open FSharp.Control.Tasks.Affine.Unsafe
9-
open FSharp.Control.Tasks.Affine
108
open Ply
119
open System.Runtime.CompilerServices
1210

@@ -15,11 +13,16 @@ module TaskOptionCE =
1513
type TaskOptionBuilder() =
1614
member val SomeUnit = Some()
1715

18-
member inline _.Return(value: 'T) : Ply<_ option> = uply.Return <| option.Return value
16+
member inline _.Return(value: 'T) : Ply<_ option> =
17+
FSharp.Control.Tasks.Affine.Unsafe.uply.Return
18+
<| option.Return value
1919

20-
member inline _.ReturnFrom(taskResult: Task<_ option>) : Ply<_ option> = uply.ReturnFrom taskResult
20+
member inline _.ReturnFrom(taskResult: Task<_ option>) : Ply<_ option> =
21+
FSharp.Control.Tasks.Affine.Unsafe.uply.ReturnFrom taskResult
2122

22-
member inline _.Zero() : Ply<_ option> = uply.Return <| option.Zero()
23+
member inline _.Zero() : Ply<_ option> =
24+
FSharp.Control.Tasks.Affine.Unsafe.uply.Return
25+
<| option.Zero()
2326

2427
member inline _.Bind
2528
(
@@ -29,18 +32,19 @@ module TaskOptionCE =
2932
let binder' r =
3033
match r with
3134
| Some x -> binder x
32-
| None -> uply.Return None
35+
| None -> FSharp.Control.Tasks.Affine.Unsafe.uply.Return None
3336

34-
uply.Bind(taskResult, binder')
37+
FSharp.Control.Tasks.Affine.Unsafe.uply.Bind(taskResult, binder')
3538

36-
member inline _.Delay([<InlineIfLambda>] generator: unit -> Ply<_ option>) = uply.Delay(generator)
39+
member inline _.Delay([<InlineIfLambda>] generator: unit -> Ply<_ option>) =
40+
FSharp.Control.Tasks.Affine.Unsafe.uply.Delay(generator)
3741

3842
member inline _.Combine
3943
(
4044
computation1: Ply<'T option>,
4145
[<InlineIfLambda>] computation2: unit -> Ply<'U option>
4246
) : Ply<'U option> =
43-
uply {
47+
FSharp.Control.Tasks.Affine.Unsafe.uply {
4448
match! computation1 with
4549
| None -> return None
4650
| Some _ -> return! computation2 ()
@@ -51,28 +55,28 @@ module TaskOptionCE =
5155
[<InlineIfLambda>] computation: unit -> Ply<_ option>,
5256
[<InlineIfLambda>] handler: exn -> Ply<_ option>
5357
) : Ply<_ option> =
54-
uply.TryWith(computation, handler)
58+
FSharp.Control.Tasks.Affine.Unsafe.uply.TryWith(computation, handler)
5559

5660
member inline _.TryFinally
5761
(
5862
[<InlineIfLambda>] computation: unit -> Ply<_ option>,
5963
[<InlineIfLambda>] compensation: unit -> unit
6064
) : Ply<_ option> =
61-
uply.TryFinally(computation, compensation)
65+
FSharp.Control.Tasks.Affine.Unsafe.uply.TryFinally(computation, compensation)
6266

6367
member inline _.Using
6468
(
6569
resource: 'T :> IDisposable,
6670
[<InlineIfLambda>] binder: 'T -> Ply<_ option>
6771
) : Ply<_ option> =
68-
uply.Using(resource, binder)
72+
FSharp.Control.Tasks.Affine.Unsafe.uply.Using(resource, binder)
6973

7074
member inline _.While
7175
(
7276
[<InlineIfLambda>] guard: unit -> bool,
7377
[<InlineIfLambda>] computation: unit -> Ply<'U option>
7478
) : Ply<'U option> =
75-
uply {
79+
FSharp.Control.Tasks.Affine.Unsafe.uply {
7680
let mutable fin, result = false, None
7781

7882
while not fin && guard () do
@@ -86,7 +90,7 @@ module TaskOptionCE =
8690
}
8791

8892
member inline _.For(sequence: #seq<'T>, binder: 'T -> Ply<'U option>) : Ply<'U option> =
89-
uply {
93+
FSharp.Control.Tasks.Affine.Unsafe.uply {
9094
use enumerator = sequence.GetEnumerator()
9195
let mutable fin, result = false, None
9296

@@ -104,7 +108,7 @@ module TaskOptionCE =
104108
this.Bind(x, (fun x -> this.Return(f x)))
105109

106110
member inline _.MergeSources(t1: Task<'T option>, t2: Task<'T1 option>) = TaskOption.zip t1 t2
107-
member inline _.Run([<InlineIfLambda>] f: unit -> Ply<'m>) = task.Run f
111+
member inline _.Run([<InlineIfLambda>] f: unit -> Ply<'m>) = FSharp.Control.Tasks.Affine.task.Run f
108112

109113
/// <summary>
110114
/// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type.
@@ -115,7 +119,8 @@ module TaskOptionCE =
115119
/// <summary>
116120
/// Method lets us transform data types into our internal representation.
117121
/// </summary>
118-
member inline _.Source(t: ValueTask<_ option>) : Task<_ option> = task { return! t }
122+
member inline _.Source(t: ValueTask<_ option>) : Task<_ option> =
123+
FSharp.Control.Tasks.Affine.task { return! t }
119124

120125
/// <summary>
121126
/// Method lets us transform data types into our internal representation.
@@ -125,10 +130,144 @@ module TaskOptionCE =
125130
/// <summary>
126131
/// Method lets us transform data types into our internal representation.
127132
/// </summary>
128-
member inline _.Source(p: Ply<_ option>) : Task<_ option> = task { return! p }
133+
member inline _.Source(p: Ply<_ option>) : Task<_ option> =
134+
FSharp.Control.Tasks.Affine.task { return! p }
129135

130136
let taskOption = TaskOptionBuilder()
131137

138+
type BackgroundTaskOptionBuilder() =
139+
member val SomeUnit = Some()
140+
141+
member inline _.Return(value: 'T) : Ply<_ option> =
142+
FSharp.Control.Tasks.NonAffine.Unsafe.uply.Return
143+
<| option.Return value
144+
145+
member inline _.ReturnFrom(taskResult: Task<_ option>) : Ply<_ option> =
146+
FSharp.Control.Tasks.NonAffine.Unsafe.uply.ReturnFrom taskResult
147+
148+
member inline _.Zero() : Ply<_ option> =
149+
FSharp.Control.Tasks.NonAffine.Unsafe.uply.Return
150+
<| option.Zero()
151+
152+
member inline _.Bind
153+
(
154+
taskResult: Task<_ option>,
155+
[<InlineIfLambda>] binder: 'T -> Ply<_ option>
156+
) : Ply<_ option> =
157+
let binder' r =
158+
match r with
159+
| Some x -> binder x
160+
| None -> FSharp.Control.Tasks.NonAffine.Unsafe.uply.Return None
161+
162+
FSharp.Control.Tasks.NonAffine.Unsafe.uply.Bind(taskResult, binder')
163+
164+
member inline _.Delay([<InlineIfLambda>] generator: unit -> Ply<_ option>) =
165+
FSharp.Control.Tasks.NonAffine.Unsafe.uply.Delay(generator)
166+
167+
member inline _.Combine
168+
(
169+
computation1: Ply<'T option>,
170+
[<InlineIfLambda>] computation2: unit -> Ply<'U option>
171+
) : Ply<'U option> =
172+
FSharp.Control.Tasks.NonAffine.Unsafe.uply {
173+
match! computation1 with
174+
| None -> return None
175+
| Some _ -> return! computation2 ()
176+
}
177+
178+
member inline _.TryWith
179+
(
180+
[<InlineIfLambda>] computation: unit -> Ply<_ option>,
181+
[<InlineIfLambda>] handler: exn -> Ply<_ option>
182+
) : Ply<_ option> =
183+
FSharp.Control.Tasks.NonAffine.Unsafe.uply.TryWith(computation, handler)
184+
185+
member inline _.TryFinally
186+
(
187+
[<InlineIfLambda>] computation: unit -> Ply<_ option>,
188+
[<InlineIfLambda>] compensation: unit -> unit
189+
) : Ply<_ option> =
190+
FSharp.Control.Tasks.NonAffine.Unsafe.uply.TryFinally(computation, compensation)
191+
192+
member inline _.Using
193+
(
194+
resource: 'T :> IDisposable,
195+
[<InlineIfLambda>] binder: 'T -> Ply<_ option>
196+
) : Ply<_ option> =
197+
FSharp.Control.Tasks.NonAffine.Unsafe.uply.Using(resource, binder)
198+
199+
member inline _.While
200+
(
201+
[<InlineIfLambda>] guard: unit -> bool,
202+
[<InlineIfLambda>] computation: unit -> Ply<'U option>
203+
) : Ply<'U option> =
204+
FSharp.Control.Tasks.NonAffine.Unsafe.uply {
205+
let mutable fin, result = false, None
206+
207+
while not fin && guard () do
208+
match! computation () with
209+
| Some _ as o -> result <- o
210+
| None ->
211+
result <- None
212+
fin <- true
213+
214+
return result
215+
}
216+
217+
member inline _.For(sequence: #seq<'T>, binder: 'T -> Ply<'U option>) : Ply<'U option> =
218+
FSharp.Control.Tasks.NonAffine.Unsafe.uply {
219+
use enumerator = sequence.GetEnumerator()
220+
let mutable fin, result = false, None
221+
222+
while not fin && enumerator.MoveNext() do
223+
match! binder enumerator.Current with
224+
| Some _ as o -> result <- o
225+
| None ->
226+
result <- None
227+
fin <- true
228+
229+
return result
230+
}
231+
232+
member inline this.BindReturn(x: Task<'T option>, [<InlineIfLambda>] f) =
233+
this.Bind(x, (fun x -> this.Return(f x)))
234+
235+
member inline _.MergeSources(t1: Task<'T option>, t2: Task<'T1 option>) =
236+
FSharp.Control.Tasks.NonAffine.task {
237+
let! o1 = t1
238+
let! o2 = t2
239+
return Option.zip o1 o2
240+
}
241+
242+
member inline _.Run([<InlineIfLambda>] f: unit -> Ply<'m>) =
243+
FSharp.Control.Tasks.NonAffine.task.Run f
244+
245+
/// <summary>
246+
/// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type.
247+
/// See https://stackoverflow.com/questions/35286541/why-would-you-use-builder-source-in-a-custom-computation-expression-builder
248+
/// </summary>
249+
member inline _.Source(task: Task<_ option>) : Task<_ option> = task
250+
251+
/// <summary>
252+
/// Method lets us transform data types into our internal representation.
253+
/// </summary>
254+
member inline _.Source(t: ValueTask<_ option>) : Task<_ option> =
255+
FSharp.Control.Tasks.NonAffine.task { return! t }
256+
257+
/// <summary>
258+
/// Method lets us transform data types into our internal representation.
259+
/// </summary>
260+
member inline _.Source(async: Async<_ option>) : Task<_ option> = async |> Async.StartAsTask
261+
262+
/// <summary>
263+
/// Method lets us transform data types into our internal representation.
264+
/// </summary>
265+
member inline _.Source(p: Ply<_ option>) : Task<_ option> =
266+
FSharp.Control.Tasks.NonAffine.task { return! p }
267+
268+
let backgroundTaskOption = BackgroundTaskOptionBuilder()
269+
270+
132271

133272
[<AutoOpen>]
134273
// Having members as extensions gives them lower priority in
@@ -137,7 +276,14 @@ module TaskOptionCEExtensionsLower =
137276

138277
type TaskOptionBuilder with
139278
member inline this.Source(t: ^TaskLike) : Task<'T option> =
140-
task {
279+
FSharp.Control.Tasks.Affine.task {
280+
let! r = t
281+
return Some r
282+
}
283+
284+
type BackgroundTaskOptionBuilder with
285+
member inline this.Source(t: ^TaskLike) : Task<'T option> =
286+
FSharp.Control.Tasks.NonAffine.task {
141287
let! r = t
142288
return Some r
143289
}
@@ -161,35 +307,106 @@ module TaskOptionCEExtensions =
161307
/// <summary>
162308
/// Method lets us transform data types into our internal representation.
163309
/// </summary>
164-
member inline _.Source(a: Task<'T>) = a |> Task.map Some
310+
member inline _.Source(a: Task<'T>) =
311+
FSharp.Control.Tasks.Affine.task {
312+
let! o = a
313+
return Some o
314+
}
165315

166316
/// <summary>
167317
/// Method lets us transform data types into our internal representation.
168318
/// </summary>
169319
member inline x.Source(a: Task) =
170-
task {
320+
FSharp.Control.Tasks.Affine.task {
171321
do! a
172322
return x.SomeUnit
173323
}
174324

175325
/// <summary>
176326
/// Method lets us transform data types into our internal representation.
177327
/// </summary>
178-
member inline _.Source(a: ValueTask<'T>) = a |> Task.mapV Some
328+
member inline _.Source(a: ValueTask<'T>) =
329+
FSharp.Control.Tasks.Affine.task {
330+
let! o = a
331+
return Some o
332+
}
179333

180334
/// <summary>
181335
/// Method lets us transform data types into our internal representation.
182336
/// </summary>
183337
member inline x.Source(a: ValueTask) =
184-
task {
338+
FSharp.Control.Tasks.Affine.task {
185339
do! a
186340
return x.SomeUnit
187341
}
188342

189343
/// <summary>
190344
/// Method lets us transform data types into our internal representation.
191345
/// </summary>
192-
member inline _.Source(a: Async<'t>) = a |> Async.StartAsTask |> Task.map Some
346+
member inline _.Source(a: Async<'t>) =
347+
FSharp.Control.Tasks.Affine.task {
348+
let! o = a |> Async.StartAsTask
349+
return Some o
350+
}
351+
352+
353+
type BackgroundTaskOptionBuilder with
354+
/// <summary>
355+
/// Needed to allow `for..in` and `for..do` functionality
356+
/// </summary>
357+
member inline _.Source(s: #seq<_>) = s
358+
359+
/// <summary>
360+
/// Method lets us transform data types into our internal representation.
361+
/// </summary>
362+
member inline _.Source(r: 't option) = Task.singleton r
363+
364+
/// <summary>
365+
/// Method lets us transform data types into our internal representation.
366+
/// </summary>
367+
member inline _.Source(a: Task<'T>) =
368+
FSharp.Control.Tasks.NonAffine.task {
369+
let! o = a
370+
return Some o
371+
}
372+
373+
/// <summary>
374+
/// Method lets us transform data types into our internal representation.
375+
/// </summary>
376+
member inline x.Source(a: Task) =
377+
FSharp.Control.Tasks.NonAffine.task {
378+
do! a
379+
return x.SomeUnit
380+
}
381+
382+
/// <summary>
383+
/// Method lets us transform data types into our internal representation.
384+
/// </summary>
385+
member inline _.Source(a: ValueTask<'T>) =
386+
FSharp.Control.Tasks.NonAffine.task {
387+
let! o = a
388+
return Some o
389+
}
390+
391+
/// <summary>
392+
/// Method lets us transform data types into our internal representation.
393+
/// </summary>
394+
member inline x.Source(a: ValueTask) =
395+
FSharp.Control.Tasks.NonAffine.task {
396+
do! a
397+
return x.SomeUnit
398+
}
399+
400+
/// <summary>
401+
/// Method lets us transform data types into our internal representation.
402+
/// </summary>
403+
member inline _.Source(a: Async<'t>) =
404+
FSharp.Control.Tasks.NonAffine.task {
405+
let! o = a |> Async.StartAsTask
406+
return Some o
407+
}
408+
409+
193410

194411
#else
195412

0 commit comments

Comments
 (0)