-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfuture.go
121 lines (107 loc) · 3.31 KB
/
future.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
110
111
112
113
114
115
116
117
118
119
120
121
package future
import (
"context"
"fmt"
"reflect"
)
// Future is the consumer interface for futures.
type Future interface {
Done() <-chan struct{}
Err() error
Value() interface{}
Result() (interface{}, error)
Wait(context.Context) (interface{}, error)
Then(interface{}) Future
Catch(func(error)) Future
}
// SettableFuture is the complete interface, including the Set method.
// It may be downcast to a Future.
// This is sometimes referred to as a promise, but that would be
// confusing in a library called future.
type SettableFuture struct {
value interface{}
err error
done chan struct{}
}
// New creates a new Future that can be Set or waited on.
func New() *SettableFuture {
return &SettableFuture{
value: nil,
err: nil,
done: make(chan struct{}),
}
}
// Set provides the value or error associated for a Future.
// Set may only be called once, or it will panic.
func (f *SettableFuture) Set(value interface{}, err error) {
f.value = value
f.err = err
close(f.done)
}
// Done returns a channel which is closed when the result is set.
// This mimics the context.Context interface.
func (f *SettableFuture) Done() <-chan struct{} {
return f.done
}
// Err returns an error after a value is set.
// This is useful in cases where the result value is not needed.
// This mimics the context.Context interface.
func (f *SettableFuture) Err() error {
return f.err
}
// Value returns the value after a value is set.
func (f *SettableFuture) Value() interface{} {
return f.value
}
// Result returns the result and error after a value is set.
func (f *SettableFuture) Result() (interface{}, error) {
return f.value, f.err
}
// Wait blocks until the provided context expires or the Future's value is set,
// then returns the associated value and error.
// It returns the context's Err() value if the context expires first.
func (f *SettableFuture) Wait(ctx context.Context) (interface{}, error) {
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-f.Done():
return f.Value(), f.Err()
}
}
// Then blocks until the Future's value is set, then invokes
// the callback if a nil error was set.
// The callback must be a function accepting a single argument of the Future's value type.
// Then returns after the callback was invoked or skipped.
func (f *SettableFuture) Then(callback interface{}) Future {
fnType := reflect.TypeOf(callback)
fnValue := reflect.ValueOf(callback)
if fnType.Kind() != reflect.Func {
panic(fmt.Sprintf("callback %s is not a function", callback))
}
if fnType.NumIn() != 1 {
panic(fmt.Sprintf("callback %s does not take exactly one argument", callback))
}
if fnType.NumOut() != 0 {
panic(fmt.Sprintf("callback %s has more than 0 return values", callback))
}
<-f.Done()
if err := f.Err(); err == nil {
fnValue.Call([]reflect.Value{reflect.ValueOf(f.Value())})
}
return f
}
// Catch blocks until the Future's value is set, then invokes
// the callback if a non-nil error was set.
// Catch returns after the callback was invoked or skipped.
func (f *SettableFuture) Catch(callback func(err error)) Future {
<-f.Done()
if err := f.Err(); err != nil {
callback(err)
}
return f
}
// String converts the settable future to a string representation,
// otherwise most testing frameworks will throw a data race
func (f *SettableFuture) String() string {
return fmt.Sprintf("SettableFuture<%p>", f)
}