11namespace FSharp.Data.GraphQL
22
33open System
4+ open System.Collections .Generic
45
56[<Struct>]
67type AsyncVal < 'T > =
@@ -49,13 +50,21 @@ module AsyncVal =
4950
5051 /// Maps content of AsyncVal using provided mapping function, returning new
5152 /// AsyncVal as the result.
52- let map ( fn : 'T -> 'Res ) ( x : AsyncVal < 'T >) =
53+ let map ( fn : 'T -> 'U ) ( x : AsyncVal < 'T >) =
5354 if x.IsSync
54- then AsyncVal< 'Res >( fn x.Value)
55- else AsyncVal< 'Res > ( async {
55+ then AsyncVal< 'U >( fn x.Value)
56+ else AsyncVal< 'U > ( async {
5657 let! result = x.Async
5758 return fn result })
5859
60+ /// Applies rescue fn in case when contained Async value throws an exception.
61+ let rescue ( fn : exn -> 'T ) ( x : AsyncVal < 'T >) =
62+ if x.IsSync // sync vals will never throw, as they contain ready value
63+ then x
64+ else ofAsync( async {
65+ try return ! x.Async
66+ with e -> return fn e })
67+
5968 /// Folds content of AsyncVal over provided initial state zero using provided fn.
6069 /// Returns new AsyncVal as a result.
6170 let fold ( fn : 'State -> 'T -> 'State ) ( zero : 'State ) ( x : AsyncVal < 'T >) : AsyncVal < 'State > =
@@ -79,67 +88,47 @@ module AsyncVal =
7988 /// Converts array of AsyncVals into AsyncVal with array results.
8089 /// In case when are non-immediate values in provided array, they are
8190 /// executed asynchronously, one by one with regard to their order in array.
91+ /// Returned array maintain order of values.
8292 let collectSequential ( values : AsyncVal < 'T > []) : AsyncVal < 'T []> =
83- let i , a = values |> Array.partition isSync
84- match i, a with
85- | [||], [||] -> AsyncVal<_> [||]
86- | immediates, [||] ->
87- let x = immediates |> Array.map ( fun v -> v.Value)
88- AsyncVal<_> x
89- | [||], awaitings ->
90- let asyncs = awaitings |> Array.map ( fun v -> v.Async)
91- let x = async {
92- let results = Array.zeroCreate asyncs.Length
93- let mutable i = 0
94- for a in asyncs do
95- let! res = a
96- results.[ i] <- res
97- i <- i + 1
98- return results
99- }
100- ofAsync x
101- | immediates, awaitings ->
102- //TODO: optimize
103- let ready = immediates |> Array.map ( fun v -> v.Value)
104- let asyncs = awaitings |> Array.map ( fun v -> v.Async)
105- let x = async {
106- let results = Array.zeroCreate ( ready.Length + asyncs.Length)
107- Array.Copy( ready, results, ready.Length)
108- let mutable i = ready.Length
109- for a in asyncs do
110- let! res = a
111- results.[ i] <- res
112- i <- i + 1
113- return results
114- }
115- ofAsync x
93+ if values.Length = 0 then AsyncVal<_> [||]
94+ elif values |> Array.exists isAsync then
95+ ofAsync <| async {
96+ let results = Array.zeroCreate values.Length
97+ for i = 0 to values.Length - 1 do
98+ let v = values.[ i]
99+ if v.IsSync
100+ then results.[ i] <- v.Value
101+ else
102+ let! r = v.Async
103+ results.[ i] <- r
104+ return results }
105+ else AsyncVal<_> ( values |> Array.map ( fun x -> x.Value))
106+
116107
117108 /// Converts array of AsyncVals into AsyncVal with array results.
118109 /// In case when are non-immediate values in provided array, they are
119- /// executed all in parallel, in unordered fashion.
110+ /// executed all in parallel, in unordered fashion. Order of values
111+ /// inside returned array is maintained.
120112 let collectParallel ( values : AsyncVal < 'T > []) : AsyncVal < 'T []> =
121- let i , a = values |> Array.partition isSync
122- match i, a with
123- | [||], [||] -> AsyncVal<_> [||]
124- | immediates, [||] ->
125- let x = immediates |> Array.map ( fun v -> v.Value)
126- AsyncVal<_> x
127- | [||], awaitings ->
128- let x = awaitings |> Array.map ( fun v -> v.Async) |> Async.Parallel
129- ofAsync x
130- | immediates, awaitings ->
131- //TODO: optimize
132- let len = immediates.Length
133- let asyncs = awaitings |> Array.map ( fun v -> v.Async)
134- let results = Array.zeroCreate ( len + asyncs.Length)
135- for i = 0 to len - 1 do
136- results.[ i] <- immediates.[ i]. Value
137- let x = async {
138- let! asyncResults = asyncs |> Async.Parallel
139- Array.Copy( asyncResults, 0 , results, len, asyncResults.Length)
140- return results
141- }
142- ofAsync x
113+ if values.Length = 0 then AsyncVal<_> [||]
114+ else
115+ let indexes = List<_>( 0 )
116+ let continuations = List<_>( 0 )
117+ let results = Array.zeroCreate values.Length
118+ for i = 0 to values.Length - 1 do
119+ let v = values.[ i]
120+ if v.IsSync
121+ then results.[ i] <- v.Value
122+ else
123+ indexes.Add i
124+ continuations.Add v.Async
125+ if indexes.Count = 0
126+ then AsyncVal<_> results
127+ else ofAsync ( async {
128+ let! vals = continuations |> Async.Parallel
129+ for i = 0 to indexes.Count - 1 do
130+ results.[ indexes.[ i]] <- vals.[ i]
131+ return results })
143132
144133type AsyncValBuilder () =
145134 member x.Zero () = AsyncVal.empty
0 commit comments