-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathpromise_functions.go
109 lines (101 loc) · 3.76 KB
/
promise_functions.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*
* Copyright (c) 2022, [email protected]
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package promises
import (
"context"
"fmt"
"github.com/nwillc/genfuncs"
"github.com/nwillc/genfuncs/container"
"github.com/nwillc/genfuncs/results"
)
var (
PromiseAnyNoPromisesErrorMsg = "no any without promises"
PromiseNoneFulfilled = "no promises fulfilled"
)
type promiseResult[T any] struct {
result *genfuncs.Result[T]
index int
}
// All accepts promises and collects their results, returning a container.GSlice of the results in correlating order,
// or if *any* genfuncs.Promise fails then All returns its error and immediately returns.
func All[T any](ctx context.Context, promises ...*genfuncs.Promise[T]) *genfuncs.Promise[container.GSlice[T]] {
count := len(promises)
promiseResults := make(container.GSlice[T], count)
if count == 0 {
return genfuncs.NewPromiseFromResult(genfuncs.NewResult(promiseResults))
}
return genfuncs.NewPromise(
ctx,
func(_ context.Context) *genfuncs.Result[container.GSlice[T]] {
resultChan := make(chan promiseResult[T], count)
for i := 0; i < count; i++ {
i := i
promises[i].
OnSuccess(func(value T) { resultChan <- promiseResult[T]{result: genfuncs.NewResult(value), index: i} }).
OnError(func(err error) { resultChan <- promiseResult[T]{result: genfuncs.NewError[T](err), index: i} })
}
for i := 0; i < count; i++ {
select {
case r := <-resultChan:
if !r.result.Ok() {
cancelAll(promises)
return results.MapError[T, container.GSlice[T]](r.result)
}
promiseResults[r.index] = r.result.OrEmpty()
}
}
return genfuncs.NewResult(promiseResults)
})
}
// Any returns a Promise that will return the first Promise fulfilled, or an error if none were.
func Any[T any](ctx context.Context, promises ...*genfuncs.Promise[T]) *genfuncs.Promise[T] {
count := len(promises)
if count == 0 {
return genfuncs.NewPromiseFromResult(genfuncs.NewError[T](fmt.Errorf(PromiseAnyNoPromisesErrorMsg)))
}
return genfuncs.NewPromise(
ctx,
func(_ context.Context) *genfuncs.Result[T] {
resultChan := make(chan promiseResult[T], count)
for i := 0; i < count; i++ {
i := i
promises[i].
OnSuccess(func(value T) { resultChan <- promiseResult[T]{result: genfuncs.NewResult(value), index: i} }).
OnError(func(err error) { resultChan <- promiseResult[T]{result: genfuncs.NewError[T](err), index: i} })
}
for i := 0; i < count; i++ {
select {
case r := <-resultChan:
cancelAll(promises)
if r.result.Ok() {
return r.result
}
}
}
return genfuncs.NewError[T](fmt.Errorf(PromiseNoneFulfilled))
})
}
// Map will Wait for aPromise and then return a new Promise which then maps its result.
func Map[A, B any](ctx context.Context, aPromise *genfuncs.Promise[A], then genfuncs.Function[A, *genfuncs.Result[B]]) *genfuncs.Promise[B] {
return genfuncs.NewPromise(ctx, func(_ context.Context) *genfuncs.Result[B] {
return results.Map[A, B](aPromise.Wait(), then)
})
}
func cancelAll[T any](promises []*genfuncs.Promise[T]) {
for _, p := range promises {
p.Cancel()
}
}