-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfuture.go
113 lines (94 loc) · 1.77 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
// Package future represents an async Task call.
package future
import (
"errors"
"sync"
)
// Future represents a task which executes async work.
type Future struct {
task Task
done chan struct{}
result interface{}
err error
canceled bool
on bool
lock sync.RWMutex
}
// Run executes the Task async.
func (f *Future) Run() {
f.lock.Lock()
if f.on {
f.lock.Unlock()
return
}
f.on = true
f.lock.Unlock()
go f.run()
}
// Wait blocks until task is done.
func (f *Future) Wait() {
f.lock.RLock()
if !f.on {
f.lock.RUnlock()
return
}
f.lock.RUnlock()
<-f.done
}
// Result returns task result and error. Blocks until task is done.
func (f *Future) Result() (interface{}, error) {
f.lock.RLock()
if !f.on {
f.lock.RUnlock()
return f.result, f.err
}
f.lock.RUnlock()
<-f.done
return f.result, f.err
}
// Cancel asks the task to stop.
func (f *Future) Cancel() {
f.lock.Lock()
f.canceled = true
f.lock.Unlock()
}
// IsCanceled returns true if task was canceled.
func (f *Future) IsCanceled() bool {
f.lock.RLock()
defer f.lock.RUnlock()
return f.canceled
}
func (f *Future) run() {
defer close(f.done)
f.result, f.err = f.task.Run(f.IsCanceled)
if task, ok := f.task.(CanceledTask); ok {
f.lock.RLock()
if f.canceled {
f.lock.RUnlock()
task.OnCancel()
return
}
f.lock.RUnlock()
}
if task, ok := f.task.(SuccessfulTask); ok {
if f.err == nil {
task.OnSuccess(f.result)
}
}
if task, ok := f.task.(FailedTask); ok {
if f.err != nil {
task.OnError(f.err)
}
}
}
// New creates a new future with a given task.
func New(task Task) (*Future, error) {
if task == nil {
return nil, errors.New("nil task passed")
}
future := &Future{
task: task,
done: make(chan struct{}),
}
return future, nil
}