package utils
import (
"context"
"sync"
)
var closedPromiseChan = make(chan struct{})
func init() {
close(closedPromiseChan)
}
type Promise[T any] struct {
mu sync.Mutex
done chan struct{}
Result T
Err error
}
func NewPromise[T any]() *Promise[T] {
return &Promise[T]{
done: make(chan struct{}),
}
}
func GoPromise[T any](f func() (T, error)) *Promise[T] {
p := NewPromise[T]()
go func() { p.Resolve(f()) }()
return p
}
func NewResolvedPromise[T any](result T, err error) *Promise[T] {
return &Promise[T]{
Result: result,
Err: err,
done: closedPromiseChan,
}
}
func (p *Promise[T]) Resolve(result T, err error) {
p.mu.Lock()
defer p.mu.Unlock()
if p.done == closedPromiseChan {
return
}
p.Result = result
p.Err = err
if p.done != nil {
close(p.done)
}
p.done = closedPromiseChan
}
func (p *Promise[T]) Done() <-chan struct{} {
p.mu.Lock()
defer p.mu.Unlock()
if p.done == nil {
p.done = make(chan struct{})
}
return p.done
}
func (p *Promise[T]) Resolved() bool {
p.mu.Lock()
defer p.mu.Unlock()
return p.done == closedPromiseChan
}
func AwaitPromise[T any](ctx context.Context, p *Promise[T]) (T, error) {
select {
case <-ctx.Done():
var v T
return v, ctx.Err()
case <-p.Done():
return p.Result, p.Err
}
}