// Package watch provides an observable value: a [Value] that can be updated and// one or more [Observer] handles that observe its changes.//// It is the Go analog of iroh's n0_watcher (Watchable + Watcher). An [Observer]// exposes the current value, a one-shot wait for the next change, and an// iterator stream of values. The root package uses Observer for APIs such as// Endpoint.WatchAddr.//// The Go API is not stable before v1 and may change in any v0 release.
package watchimport ()// Value is an observable container holding a T. It is safe for concurrent use.// Updates are published to all [Observer] handles created from it.//// The zero Value holds the zero T and is ready to use.typeValue[ any] struct { mu sync.Mutex val set bool version uint64 notify chanstruct{} // closed and replaced on each Set equal func(a, b ) bool}// NewValue returns a Value initialized to v.func [ any]( ) *Value[] {return &Value[]{val: , set: true}}// NewValueFunc returns a Value initialized to v. The equal function, if non-nil,// suppresses notifications for no-op updates.func [ any]( , func(, ) bool) *Value[] {return &Value[]{val: , set: true, equal: }}// Set updates the value and notifies all watchers if it changed.func ( *Value[]) ( ) { .mu.Lock()defer .mu.Unlock()if .set && .equal != nil && .equal(.val, ) {return } .val = .set = true .version++if .notify != nil {close(.notify) .notify = nil }}// Current returns the current value.func ( *Value[]) () { .mu.Lock()defer .mu.Unlock()return .val}// Watch returns an [Observer] observing this value.func ( *Value[]) () Observer[] {return &watcher[]{src: }}// changed returns the current value, version, and a channel closed on the next// change after the given version.func ( *Value[]) ( uint64) (, uint64, <-chanstruct{}) { .mu.Lock()defer .mu.Unlock()if .version != {return .val, .version, closedChan }if .notify == nil { .notify = make(chanstruct{}) }return .val, .version, .notify}var closedChan = func() chanstruct{} { := make(chanstruct{})close()return}()// Observer observes a [Value]. Multiple observers may observe the same value// independently. It is the Go analog of iroh's n0_watcher::Watcher.typeObserver[ any] interface {// Current returns the current value.Current() // Updated blocks until the value changes after the watcher's last observed // version, returning the new value, or ctx.Err() if the context is done. // The first call returns the current value immediately.Updated(ctx context.Context) (, error)// Stream returns an iterator that yields each new value until ctx is done. // The current value is delivered first.Stream(ctx context.Context) iter.Seq[]}type watcher[ any] struct { src *Value[] seen uint64 once bool}func ( *watcher[]) () { return .src.Current() }func ( *watcher[]) ( context.Context) (, error) {if !.once { .once = true , , := .src.waitChan(^uint64(0)) // force "current" on first call .seen = return , nil }for { , , := .src.waitChan(.seen)if != .seen { .seen = return , nil }select {case<-:case<-.Done():varreturn , .Err() } }}func ( *watcher[]) ( context.Context) iter.Seq[] {// Independent cursor so Stream doesn't disturb Updated on the same watcher. := &watcher[]{src: .src}returnfunc( func() bool) {for { , := .Updated()if != nil {return }if !() {return } } }}
The pages are generated with Goldsv0.8.4. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.