Skip to content

Commit 6d948a5

Browse files
authored
refactor!: generic types; encapsulate internal structures (#34)
1 parent 1648eed commit 6d948a5

File tree

9 files changed

+153
-140
lines changed

9 files changed

+153
-140
lines changed

examples/future/main.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"time"
66

77
"github.com/reugn/async"
8-
"github.com/reugn/async/internal/util"
98
)
109

1110
func main() {
@@ -21,7 +20,7 @@ func asyncAction() async.Future[string] {
2120
promise := async.NewPromise[string]()
2221
go func() {
2322
time.Sleep(time.Second)
24-
promise.Success(util.Ptr("OK"))
23+
promise.Success("OK")
2524
}()
2625

2726
return promise.Future()

future.go

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,54 +13,54 @@ type Future[T any] interface {
1313

1414
// Map creates a new Future by applying a function to the successful
1515
// result of this Future.
16-
Map(func(*T) (*T, error)) Future[T]
16+
Map(func(T) (T, error)) Future[T]
1717

1818
// FlatMap creates a new Future by applying a function to the successful
1919
// result of this Future.
20-
FlatMap(func(*T) (Future[T], error)) Future[T]
20+
FlatMap(func(T) (Future[T], error)) Future[T]
2121

2222
// Join blocks until the Future is completed and returns either a result
2323
// or an error.
24-
Join() (*T, error)
24+
Join() (T, error)
2525

2626
// Get blocks for at most the given time duration for this Future to
2727
// complete and returns either a result or an error.
28-
Get(time.Duration) (*T, error)
28+
Get(time.Duration) (T, error)
2929

3030
// Recover handles any error that this Future might contain using a
3131
// resolver function.
32-
Recover(func() (*T, error)) Future[T]
32+
Recover(func() (T, error)) Future[T]
3333

3434
// RecoverWith handles any error that this Future might contain using
3535
// another Future.
3636
RecoverWith(Future[T]) Future[T]
3737

3838
// complete completes the Future with either a value or an error.
39-
// Is used by Promise internally.
40-
complete(*T, error)
39+
// It is used by [Promise] internally.
40+
complete(T, error)
4141
}
4242

43-
// FutureImpl implements the Future interface.
44-
type FutureImpl[T any] struct {
43+
// futureImpl implements the Future interface.
44+
type futureImpl[T any] struct {
4545
acceptOnce sync.Once
4646
completeOnce sync.Once
4747
done chan any
48-
value *T
48+
value T
4949
err error
5050
}
5151

52-
// Verify FutureImpl satisfies the Future interface.
53-
var _ Future[any] = (*FutureImpl[any])(nil)
52+
// Verify futureImpl satisfies the Future interface.
53+
var _ Future[any] = (*futureImpl[any])(nil)
5454

55-
// NewFuture returns a new Future.
56-
func NewFuture[T any]() Future[T] {
57-
return &FutureImpl[T]{
55+
// newFuture returns a new Future.
56+
func newFuture[T any]() Future[T] {
57+
return &futureImpl[T]{
5858
done: make(chan any, 1),
5959
}
6060
}
6161

6262
// accept blocks once, until the Future result is available.
63-
func (fut *FutureImpl[T]) accept() {
63+
func (fut *futureImpl[T]) accept() {
6464
fut.acceptOnce.Do(func() {
6565
result := <-fut.done
6666
fut.setResult(result)
@@ -69,7 +69,7 @@ func (fut *FutureImpl[T]) accept() {
6969

7070
// acceptTimeout blocks once, until the Future result is available or until
7171
// the timeout expires.
72-
func (fut *FutureImpl[T]) acceptTimeout(timeout time.Duration) {
72+
func (fut *futureImpl[T]) acceptTimeout(timeout time.Duration) {
7373
fut.acceptOnce.Do(func() {
7474
timer := time.NewTimer(timeout)
7575
defer timer.Stop()
@@ -83,23 +83,24 @@ func (fut *FutureImpl[T]) acceptTimeout(timeout time.Duration) {
8383
}
8484

8585
// setResult assigns a value to the Future instance.
86-
func (fut *FutureImpl[T]) setResult(result any) {
86+
func (fut *futureImpl[T]) setResult(result any) {
8787
switch value := result.(type) {
8888
case error:
8989
fut.err = value
9090
default:
91-
fut.value = value.(*T)
91+
fut.value = value.(T)
9292
}
9393
}
9494

9595
// Map creates a new Future by applying a function to the successful result
9696
// of this Future and returns the result of the function as a new Future.
97-
func (fut *FutureImpl[T]) Map(f func(*T) (*T, error)) Future[T] {
98-
next := NewFuture[T]()
97+
func (fut *futureImpl[T]) Map(f func(T) (T, error)) Future[T] {
98+
next := newFuture[T]()
9999
go func() {
100100
fut.accept()
101101
if fut.err != nil {
102-
next.complete(nil, fut.err)
102+
var zero T
103+
next.complete(zero, fut.err)
103104
} else {
104105
next.complete(f(fut.value))
105106
}
@@ -109,16 +110,18 @@ func (fut *FutureImpl[T]) Map(f func(*T) (*T, error)) Future[T] {
109110

110111
// FlatMap creates a new Future by applying a function to the successful result
111112
// of this Future and returns the result of the function as a new Future.
112-
func (fut *FutureImpl[T]) FlatMap(f func(*T) (Future[T], error)) Future[T] {
113-
next := NewFuture[T]()
113+
func (fut *futureImpl[T]) FlatMap(f func(T) (Future[T], error)) Future[T] {
114+
next := newFuture[T]()
114115
go func() {
115116
fut.accept()
116117
if fut.err != nil {
117-
next.complete(nil, fut.err)
118+
var zero T
119+
next.complete(zero, fut.err)
118120
} else {
119121
tfut, terr := f(fut.value)
120122
if terr != nil {
121-
next.complete(nil, terr)
123+
var zero T
124+
next.complete(zero, terr)
122125
} else {
123126
next.complete(tfut.Join())
124127
}
@@ -129,23 +132,23 @@ func (fut *FutureImpl[T]) FlatMap(f func(*T) (Future[T], error)) Future[T] {
129132

130133
// Join blocks until the Future is completed and returns either
131134
// a result or an error.
132-
func (fut *FutureImpl[T]) Join() (*T, error) {
135+
func (fut *futureImpl[T]) Join() (T, error) {
133136
fut.accept()
134137
return fut.value, fut.err
135138
}
136139

137140
// Get blocks for at most the given time duration for this Future to
138141
// complete and returns either a result or an error.
139-
func (fut *FutureImpl[T]) Get(timeout time.Duration) (*T, error) {
142+
func (fut *futureImpl[T]) Get(timeout time.Duration) (T, error) {
140143
fut.acceptTimeout(timeout)
141144
return fut.value, fut.err
142145
}
143146

144147
// Recover handles any error that this Future might contain using
145148
// a given resolver function.
146149
// Returns the result as a new Future.
147-
func (fut *FutureImpl[T]) Recover(f func() (*T, error)) Future[T] {
148-
next := NewFuture[T]()
150+
func (fut *futureImpl[T]) Recover(f func() (T, error)) Future[T] {
151+
next := newFuture[T]()
149152
go func() {
150153
fut.accept()
151154
if fut.err != nil {
@@ -160,8 +163,8 @@ func (fut *FutureImpl[T]) Recover(f func() (*T, error)) Future[T] {
160163
// RecoverWith handles any error that this Future might contain using
161164
// another Future.
162165
// Returns the result as a new Future.
163-
func (fut *FutureImpl[T]) RecoverWith(rf Future[T]) Future[T] {
164-
next := NewFuture[T]()
166+
func (fut *futureImpl[T]) RecoverWith(rf Future[T]) Future[T] {
167+
next := newFuture[T]()
165168
go func() {
166169
fut.accept()
167170
if fut.err != nil {
@@ -174,14 +177,12 @@ func (fut *FutureImpl[T]) RecoverWith(rf Future[T]) Future[T] {
174177
}
175178

176179
// complete completes the Future with either a value or an error.
177-
func (fut *FutureImpl[T]) complete(value *T, err error) {
180+
func (fut *futureImpl[T]) complete(value T, err error) {
178181
fut.completeOnce.Do(func() {
179-
go func() {
180-
if err != nil {
181-
fut.done <- err
182-
} else {
183-
fut.done <- value
184-
}
185-
}()
182+
if err != nil {
183+
fut.done <- err
184+
} else {
185+
fut.done <- value
186+
}
186187
})
187188
}

future_test.go

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ func TestFuture(t *testing.T) {
1616
p := NewPromise[bool]()
1717
go func() {
1818
time.Sleep(100 * time.Millisecond)
19-
p.Success(util.Ptr(true))
19+
p.Success(true)
2020
}()
2121
res, err := p.Future().Join()
2222

23-
assert.Equal(t, true, *res)
23+
assert.Equal(t, true, res)
2424
assert.IsNil(t, err)
2525
}
2626

27-
func TestFutureUtils(t *testing.T) {
28-
p1 := NewPromise[int]()
29-
p2 := NewPromise[int]()
30-
p3 := NewPromise[int]()
27+
func TestFuture_Utils(t *testing.T) {
28+
p1 := NewPromise[*int]()
29+
p2 := NewPromise[*int]()
30+
p3 := NewPromise[*int]()
3131

3232
res1 := util.Ptr(1)
3333
res2 := util.Ptr(2)
@@ -41,38 +41,38 @@ func TestFutureUtils(t *testing.T) {
4141
time.Sleep(300 * time.Millisecond)
4242
p3.Failure(err3)
4343
}()
44-
arr := []Future[int]{p1.Future(), p2.Future(), p3.Future()}
44+
arr := []Future[*int]{p1.Future(), p2.Future(), p3.Future()}
4545
res := []any{res1, res2, err3}
4646
futRes, _ := FutureSeq(arr).Join()
4747

48-
assert.Equal(t, res, *futRes)
48+
assert.Equal(t, res, futRes)
4949
}
5050

51-
func TestFutureFirstCompleted(t *testing.T) {
52-
p := NewPromise[bool]()
51+
func TestFuture_FirstCompleted(t *testing.T) {
52+
p := NewPromise[*bool]()
5353
go func() {
5454
time.Sleep(100 * time.Millisecond)
5555
p.Success(util.Ptr(true))
5656
}()
57-
timeout := FutureTimer[bool](10 * time.Millisecond)
57+
timeout := FutureTimer[*bool](10 * time.Millisecond)
5858
futRes, futErr := FutureFirstCompletedOf(p.Future(), timeout).Join()
5959

6060
assert.IsNil(t, futRes)
6161
assert.NotEqual(t, futErr, nil)
6262
}
6363

64-
func TestFutureTransform(t *testing.T) {
65-
p1 := NewPromise[int]()
64+
func TestFuture_Transform(t *testing.T) {
65+
p1 := NewPromise[*int]()
6666
go func() {
6767
time.Sleep(100 * time.Millisecond)
6868
p1.Success(util.Ptr(1))
6969
}()
7070
future := p1.Future().Map(func(v *int) (*int, error) {
7171
inc := *v + 1
7272
return &inc, nil
73-
}).FlatMap(func(v *int) (Future[int], error) {
73+
}).FlatMap(func(v *int) (Future[*int], error) {
7474
inc := *v + 1
75-
p2 := NewPromise[int]()
75+
p2 := NewPromise[*int]()
7676
p2.Success(&inc)
7777
return p2.Future(), nil
7878
}).Recover(func() (*int, error) {
@@ -86,37 +86,37 @@ func TestFutureTransform(t *testing.T) {
8686
assert.Equal(t, 3, *res)
8787
}
8888

89-
func TestFutureRecover(t *testing.T) {
89+
func TestFuture_Recover(t *testing.T) {
9090
p1 := NewPromise[int]()
9191
p2 := NewPromise[int]()
9292
go func() {
9393
time.Sleep(10 * time.Millisecond)
94-
p1.Success(util.Ptr(1))
94+
p1.Success(1)
9595
time.Sleep(10 * time.Millisecond)
9696
p2.Failure(errors.New("recover Future failure"))
9797
}()
98-
future := p1.Future().Map(func(_ *int) (*int, error) {
99-
return nil, errors.New("map error")
100-
}).FlatMap(func(_ *int) (Future[int], error) {
98+
future := p1.Future().Map(func(_ int) (int, error) {
99+
return 0, errors.New("map error")
100+
}).FlatMap(func(_ int) (Future[int], error) {
101101
p2 := NewPromise[int]()
102102
p2.Failure(errors.New("flatMap Future failure"))
103103
return p2.Future(), nil
104-
}).FlatMap(func(_ *int) (Future[int], error) {
104+
}).FlatMap(func(_ int) (Future[int], error) {
105105
return nil, errors.New("flatMap error")
106-
}).Recover(func() (*int, error) {
107-
return nil, errors.New("recover error")
108-
}).RecoverWith(p2.Future()).Recover(func() (*int, error) {
109-
return util.Ptr(2), nil
106+
}).Recover(func() (int, error) {
107+
return 0, errors.New("recover error")
108+
}).RecoverWith(p2.Future()).Recover(func() (int, error) {
109+
return 2, nil
110110
})
111111

112112
res, err := future.Join()
113-
assert.Equal(t, 2, *res)
113+
assert.Equal(t, 2, res)
114114
assert.IsNil(t, err)
115115
}
116116

117-
func TestFutureFailure(t *testing.T) {
118-
p1 := NewPromise[int]()
119-
p2 := NewPromise[int]()
117+
func TestFuture_Failure(t *testing.T) {
118+
p1 := NewPromise[*int]()
119+
p2 := NewPromise[*int]()
120120
go func() {
121121
time.Sleep(10 * time.Millisecond)
122122
p1.Failure(errors.New("Future error"))
@@ -128,11 +128,11 @@ func TestFutureFailure(t *testing.T) {
128128
assert.Equal(t, 2, *res)
129129
}
130130

131-
func TestFutureTimeout(t *testing.T) {
131+
func TestFuture_Timeout(t *testing.T) {
132132
p := NewPromise[bool]()
133133
go func() {
134134
time.Sleep(100 * time.Millisecond)
135-
p.Success(util.Ptr(true))
135+
p.Success(true)
136136
}()
137137
future := p.Future()
138138

@@ -143,14 +143,14 @@ func TestFutureTimeout(t *testing.T) {
143143
assert.ErrorContains(t, err, "timeout")
144144
}
145145

146-
func TestFutureGoroutineLeak(t *testing.T) {
146+
func TestFuture_GoroutineLeak(t *testing.T) {
147147
var wg sync.WaitGroup
148148

149149
fmt.Println(runtime.NumGoroutine())
150150

151151
numFuture := 100
152152
for i := 0; i < numFuture; i++ {
153-
promise := NewPromise[string]()
153+
promise := NewPromise[*string]()
154154
wg.Add(1)
155155
go func() {
156156
defer wg.Done()

0 commit comments

Comments
 (0)