github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zsync/promise.go (about) 1 package zsync 2 3 import ( 4 "context" 5 6 "github.com/sohaha/zlsgo/zutil" 7 ) 8 9 type PromiseState uint8 10 11 type Promise[T any] struct { 12 value T 13 done chan struct{} 14 reason error 15 timeout *zutil.Bool 16 ctx context.Context 17 } 18 19 func (p *Promise[T]) Catch(rejected func(error) (T, error)) *Promise[T] { 20 return p.Then(nil, rejected) 21 } 22 23 func (p *Promise[T]) Finally(finally func()) *Promise[T] { 24 _, _ = p.Done() 25 finally() 26 return p 27 } 28 29 func (p *Promise[T]) Then(fulfilled func(T) (T, error), rejected ...func(error) (T, error)) *Promise[T] { 30 return NewPromiseContext[T](p.ctx, func() (T, error) { 31 value, err := p.Done() 32 if err == nil { 33 return fulfilled(value) 34 } 35 36 if len(rejected) > 0 && rejected[0] != nil { 37 return rejected[0](err) 38 } 39 40 return value, err 41 }) 42 } 43 44 func (p *Promise[T]) Done() (value T, reason error) { 45 if p.timeout.Load() { 46 return value, context.Canceled 47 } 48 49 select { 50 case <-p.done: 51 case <-p.ctx.Done(): 52 p.timeout.Store(true) 53 return value, context.Canceled 54 } 55 56 return p.value, p.reason 57 } 58 59 func NewPromiseContext[T any](ctx context.Context, executor func() (T, error)) *Promise[T] { 60 if executor == nil { 61 return nil 62 } 63 64 p := &Promise[T]{done: make(chan struct{}, 1), ctx: ctx, timeout: zutil.NewBool(false)} 65 66 go func() { 67 value, err := executor() 68 if err != nil { 69 p.reason = err 70 } else { 71 p.value = value 72 } 73 close(p.done) 74 }() 75 76 return p 77 } 78 79 func NewPromise[T any](executor func() (T, error)) *Promise[T] { 80 return NewPromiseContext(context.Background(), executor) 81 }