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  }