Skip to content

Commit

Permalink
doc: add comments
Browse files Browse the repository at this point in the history
Signed-off-by: jizhuozhi <[email protected]>
  • Loading branch information
jizhuozhi committed Nov 4, 2024
1 parent 09a81f8 commit fab0c88
Showing 1 changed file with 52 additions and 18 deletions.
70 changes: 52 additions & 18 deletions future.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,32 @@ const (

const flagLazy uint64 = 1 << 63

type state[T any] struct {
noCopy noCopy

state uint64 // high 30 bits are flags, mid 2 bits are state, low 32 bits are waiter count.
sema uint32

val T
err error
f func() (T, error)

stack unsafe.Pointer // *callback[T]
}

type callback[T any] struct {
f func(T, error)
next *callback[T]
}

// Promise The Promise provides a facility to store a value or an error that is later acquired asynchronously via a Future
// created by the Promise. Note that the Promise object is meant to be set only once.
//
// Each Promise is associated with a shared state, which contains some state information and a result which may be not yet evaluated,
// evaluated to a value (possibly nil) or evaluated to an error.
//
// The Promise is the "push" end of the promise-future communication channel: the operation that stores a value in the shared state
// synchronizes-with (as defined in Go's memory model) the successful return from any function that is waiting on the shared state
// (such as Future.Get).
//
// A Promise must not be copied after first use.
type Promise[T any] struct {
state state[T]
}

// Future The Future provides a mechanism to access the result of asynchronous operations:
//
// 1. An asynchronous operation (Async, Lazy or Promise) can provide a Future to the creator of that asynchronous operation.
//
// 2. The creator of the asynchronous operation can then use a variety of methods to query, wait for, or extract a value from the Future.
// These methods may block if the asynchronous operation has not yet provided a value.
//
// 3. When the asynchronous operation is ready to send a result to the creator, it can do so by modifying shared state (e.g. Promise.Set)
// that is linked to the creator's std::future.
//
// The Future also has the ability to register a callback to be called when the asynchronous operation is ready to send a result to the creator.
type Future[T any] struct {
state *state[T]
}
Expand Down Expand Up @@ -130,32 +134,39 @@ func (s *state[T]) subscribe(cb func(T, error)) {
}
}

// NewPromise creates a new Promise object.
func NewPromise[T any]() *Promise[T] {
return &Promise[T]{}
}

// Set sets the value and error of the Promise.
func (p *Promise[T]) Set(val T, err error) {
if !p.state.set(val, err) {
panic("promise already satisfied")
}
}

// SetSafety sets the value and error of the Promise, and it will return false if already set.
func (p *Promise[T]) SetSafety(val T, err error) bool {
return p.state.set(val, err)
}

// Future returns a Future object associated with the Promise.
func (p *Promise[T]) Future() *Future[T] {
return &Future[T]{state: &p.state}
}

// Free returns true if the Promise is not set.
func (p *Promise[T]) Free() bool {
return isFree(atomic.LoadUint64(&p.state.state))
}

// Get returns the value and error of the Future.
func (f *Future[T]) Get() (T, error) {
return f.state.get()
}

// GetOrDefault returns the value of the Future. If error has been set, it returns the default value.
func (f *Future[T]) GetOrDefault(defaultVal T) T {
val, err := f.state.get()
if err != nil {
Expand All @@ -164,10 +175,15 @@ func (f *Future[T]) GetOrDefault(defaultVal T) T {
return val
}

// Subscribe registers a callback to be called when the Future is done.
//
// NOTE: The callback will be called in goroutine that is the same as the goroutine which changed Future state.
// The callback should not contain any blocking operations.
func (f *Future[T]) Subscribe(cb func(val T, err error)) {
f.state.subscribe(cb)
}

// Done returns true if the Future is done.
func (f *Future[T]) Done() bool {
return isDone(atomic.LoadUint64(&f.state.state))
}
Expand All @@ -180,6 +196,24 @@ func isDone(st uint64) bool {
return ((st & maskState) >> 32) == stateDone
}

type state[T any] struct {
noCopy noCopy

state uint64 // high 30 bits are flags, mid 2 bits are state, low 32 bits are waiter count.
sema uint32

val T
err error
f func() (T, error)

stack unsafe.Pointer // *callback[T]
}

type callback[T any] struct {
f func(T, error)
next *callback[T]
}

// noCopy may be embedded into structs which must not be copied
// after the first use.
//
Expand Down

0 comments on commit fab0c88

Please sign in to comment.