-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpromise.go
121 lines (92 loc) · 1.94 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
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 abuse
import (
"sync"
)
type Promise[T any] struct {
result T
exception interface{}
callable func() T
isLazy bool
once sync.Once
lock sync.Mutex
wait sync.WaitGroup
}
func (p *Promise[T]) Do() {
p.once.Do(func() {
go func() {
defer func() {
if exception := recover(); exception != nil {
p.lock.Lock()
defer p.lock.Unlock()
p.exception = exception
p.wait.Done()
}
}()
result := p.callable()
p.lock.Lock()
defer p.lock.Unlock()
p.result = result
p.wait.Done()
}()
})
}
func newInternal[T any](callable func() T, isLazy bool) *Promise[T] {
p := Promise[T]{
callable: callable,
isLazy: isLazy,
}
p.wait.Add(1)
if !p.isLazy {
p.Do()
}
return &p
}
func New[T any](callable func() T) *Promise[T] {
return newInternal(callable, true)
}
func NewLazy[T any](callable func() T) *Promise[T] {
return newInternal(callable, false)
}
func NewChild[T any](parent *Promise[T], callable func() T) *Promise[T] {
var resultingPromise *Promise[T]
// If the original one is lazy, than the whole chain should be lazy, right?
if parent.IsLazy() {
resultingPromise = NewLazy(callable)
} else {
resultingPromise = New(callable)
}
return resultingPromise
}
func (p *Promise[T]) IsLazy() bool {
return p.isLazy
}
func (p *Promise[T]) Await() (T, interface{}) {
p.Do()
p.wait.Wait()
return p.result, p.exception
}
func (p *Promise[T]) Result() T {
result, exception := p.Await()
if exception != nil {
panic(exception)
}
return result
}
func (p *Promise[T]) Exception() interface{} {
_, exception := p.Await()
return exception
}
func (p *Promise[T]) Then(callback func(T) T) *Promise[T] {
return NewChild(p, func() T {
return callback(p.Result())
})
}
func (p *Promise[T]) Else(callback func(interface{}) T) *Promise[T] {
return NewChild(p, func() T {
result, exception := p.Await()
if exception != nil {
return callback(exception)
}
return result
})
}