-
Notifications
You must be signed in to change notification settings - Fork 0
/
routine.go
61 lines (54 loc) · 1.38 KB
/
routine.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
package relax
import (
"fmt"
"errors"
)
// Routine is a handle to a goroutine's error response.
// Panics that occur in this routine are converted into errors.
type Routine struct {
errChan chan error
}
// Wait blocks until the goroutine corresponding to the Routine instance returns an error.
// Once an error is returned, all subsequent calls to Wait will return nil.
func (r *Routine) Wait() error {
return <-r.errChan
}
// Release will call the handler against an error returned by this routine.
// Once a routine is released, waiting on it will return nil.
func (r *Routine) Release(handler func(error)) {
Go(func() error {
handler(r.Wait())
return nil
})
}
// Go launches a goroutine that will return an error if the provided func panics or
// an error is returned by the provided func.
func Go(f func() error) *Routine {
routine := &Routine{
errChan: make(chan error, 1),
}
go func() {
// Always close
defer close(routine.errChan)
// Handle panics
defer func() {
if r := recover(); r != nil {
routine.errChan <- recoverError(r)
}
}()
// Call the provided func
routine.errChan <- f()
}()
return routine
}
// recoverError will transform a recovered panic datum to an error
func recoverError(r any) error {
switch x := r.(type) {
case error:
return errors.Join(x, PanicError)
case nil:
return nil
default:
return fmt.Errorf("%w: %v", PanicError, r)
}
}