-
Notifications
You must be signed in to change notification settings - Fork 5
/
promise.go
93 lines (76 loc) · 3.03 KB
/
promise.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
// Promises for golang.
//
// This package implements a set of concurrency primitives for composing
// executions upon values which may exist in the future. They follow the model
// of JavaScript's Promises/A+ (https://promisesaplus.com/), with some
// exceptions centric to Go. There are both applicative functor (`Then()`) and
// monadic combinator (`Combine()`) methods.
package promise
// A computation which can be composed with Then().
// Types which implement this interface can be composed with the Then() method,
// they have an indicator of their status, Resolved(), which determines whether
// or not calls to the Get() method are safe. Otherwise, the presence of a
// value is observable with Then().
type Thenable interface {
// Resolved determines whether or not calling Get() is safe.
Resolved() bool
// Errored determines whether or not a promise has been rejected at any
// point.
Rejected() bool
// Create a new Thenable which is the result of this computation and the
// transformation function herein.
// TODO This needs a way to actually give you a new promise.
Then(func(interface{}) interface{}) Thenable
// Combine this thenable with another thenable.
// Given a function which accepts the value from this thenable, return a
// new Thenable that is resolved with the Thenable that is the result of
// the given function.
Combine(func(interface{}) Thenable) Thenable
// Handle an error which has occurred during processing.
Catch(func(error)) Thenable
// Return the value of this Thenable, or the error which occurred.
// Implementations which are impure must block until the promise is either
// resolved or rejected.
Get() (interface{}, error)
}
// A promise which can be completed.
type Completable interface {
Thenable
// Complete a promise.
Complete(interface{})
// Reject this promise and all of its derivatives.
Reject(error)
}
// Combine the given promises as a single promise which produces a slice of
// values. Given an arbitrarily long list of promises (as variadic arguments)
// combine all of the promises to a single promise which transforms all of the
// results of the promises into a slice (as []interface{}).
func All(thenables ...Thenable) Thenable {
var cursor Thenable
for _, each := range thenables {
// For the first thenable, transform it's value into an array of
// values.
if cursor == nil {
cursor = each.Then(func(value interface{}) interface{} {
return []interface{}{value}
})
continue
}
// Afterward, we combine that promise and the next one, but in order to
// maintain referential integrity given there's no guarantees about
// when the combine function runs, we have to close over the value so
// as to copy the reference.
cursor = func(promise Thenable) Thenable {
return cursor.Combine(func(left interface{}) Thenable {
values, ok := left.([]interface{})
if !ok {
panic("Expected an array in combiner")
}
return promise.Then(func(right interface{}) interface{} {
return append(values, right)
})
})
}(each)
}
return cursor
}