github.com/haraldrudell/parl@v0.4.176/once-waiter.go (about) 1 /* 2 © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package parl 7 8 import ( 9 "context" 10 11 "github.com/haraldrudell/parl/perrors" 12 ) 13 14 // OnceWaiter allows any number of threads to wait for a single next occurrence. 15 // - the occurrence is trigger in any of two ways: 16 // - — a parent context may be passed in that on cancel triggers the wait 17 // - — the Cancel method is invoked 18 // - Ch returns a channel that sends one item on the occurrence 19 // but never closes 20 // - Done returns a channel that closes on the occurrence happens, similar 21 // to a context 22 // - Wait awaits the occurrence 23 // - a did-occurer object can be obtained that returns true once the cycle 24 // trigs. 25 // - a context can be obtained that cancels on the next trig 26 // - the cycles can be permanently canceled or trigged and rearmed 27 type OnceWaiter struct { 28 ctx context.Context 29 } 30 31 // NewOnceWaiter returns a channel that will send one item 32 // when the context cancels or immediately if the context was already canceled. 33 func NewOnceWaiter(ctx context.Context) (onceReceiver *OnceWaiter) { 34 if ctx == nil { 35 panic(perrors.NewPF("ctx cannot be nil")) 36 } 37 return &OnceWaiter{ 38 ctx: NewCancelContext(ctx), 39 } 40 } 41 42 // Ch returns a channel that will send one item on the occurrence. 43 // - the channel will not send anything else 44 // - the channel never closes. 45 func (ow *OnceWaiter) Ch() (ch <-chan struct{}) { 46 c := make(chan struct{}, 1) 47 go onceWaiterSender(ow.ctx.Done(), c) 48 return c 49 } 50 51 // Done returns a channel that will close on the occurrence. 52 // - Done is similar to the Done method of a context 53 func (ow *OnceWaiter) Done() (done <-chan struct{}) { 54 return ow.ctx.Done() 55 } 56 57 // Wait waits until the ocurrence 58 func (ow *OnceWaiter) Wait() { 59 done := ow.Done() 60 <-done 61 } 62 63 // DidOccur returns true when the occurrence has taken place 64 func (ow *OnceWaiter) DidOccur() (didOccur bool) { 65 return ow.ctx.Err() != nil 66 } 67 68 // Context returns a context that cancels on the occurrence 69 func (cw *OnceWaiter) Context() (ctx context.Context) { 70 return NewCancelContext(cw.ctx) 71 } 72 73 // Cancel triggers the occurrence 74 func (ow *OnceWaiter) Cancel() { 75 invokeCancel(ow.ctx) 76 } 77 78 func onceWaiterSender(done <-chan struct{}, ch chan<- struct{}) { 79 Recover(func() DA { return A() }, nil, Infallible) // panic prints to stderr 80 81 <-done 82 ch <- struct{}{} 83 }