-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathfuture.go
84 lines (71 loc) · 2.28 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
// Package future provides implementations for futures & promises.
//
// Each Future/Promise creates a goroutinue to execute each one (or
// multiple when Promises are chained), and a channel to block on results.
// These are cleaned up when the original Func calls complete. Note that
// panics are not recovered explicitly, but you can recover then in your
// Func blocks.
package future
import (
"time"
"golang.org/x/net/context"
)
// Value type to allow returning arbitrary results.
type Value interface{}
// A Future is a result to an asynchronous call that cal be blocked on
// for a result when needed.
type Future interface {
// Blocks on Future awaiting result
Get() (Value, error)
// Blocks on Future awaiting result, but returns a ErrTimeout if
// the timeout Duration is hit before result returns.
// Note that the execution still continues in Future after timeout.
GetWithTimeout(timeout time.Duration) (Value, error)
// Blocks on Future awaiting result as well as provided Context.
// Execution continues in Future, even if Context hits deadline
// or is canceled.
GetWithContext(context.Context) (Value, error)
}
// Returned when a Future has timed out
var ErrTimeout = context.DeadlineExceeded
// Returned when a Future has be canceled
var ErrCanceled = context.Canceled
// Creates a new Future. Func is asynchronously called and it is
// resolved with a Get or GetWithTimeout call on the Future.
func NewFuture(Func func() (Value, error)) Future {
return newFutureResult(Func)
}
type futureResult struct {
result chan *result
}
type result struct {
value Value
err error
}
func newFutureResult(Func func() (Value, error)) *futureResult {
f := &futureResult{
result: make(chan *result),
}
go func() {
defer close(f.result)
value, err := Func()
f.result <- &result{value, err}
}()
return f
}
func (f *futureResult) Get() (Value, error) {
return f.GetWithContext(context.Background())
}
func (f *futureResult) GetWithTimeout(timeout time.Duration) (Value, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return f.GetWithContext(ctx)
}
func (f *futureResult) GetWithContext(ctx context.Context) (Value, error) {
select {
case <-ctx.Done():
return nil, ctx.Err()
case result := <-f.result:
return result.value, result.err
}
}