github.com/haraldrudell/parl@v0.4.176/go-result.go (about) 1 /* 2 © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package parl 7 8 // GoResult makes any number of goroutines awaitable 9 // - number of goroutines must be known at time of new 10 // - [NewGoResult] is the simplest, goroutines are awaited by [GoResult.ReceiveError] 11 // - [NewGoResult2] also has [IsError] method indicating if any goroutine 12 // exited with fatal error 13 // - [GoResult.IsValid] true if the GoResult is initialized 14 // - [GoResult.SendError](errp *error) deferrable, how goroutine sends results 15 // - [GoResult.ReceiveError](errp *error, n ...int) (err error) 16 // - [GoResult.Count]() (count int) number of buffered errors 17 // - [NewGoResult2] also has: 18 // - — [GoResult.IsError]() (isError bool) true if any goroutine returned error 19 // - — [GoResult.SetIsError]() sets the error flag manually 20 // - — [GoResult.Remaining]() (remaining int) number of goroutines that have yet to exit 21 // - — 22 // - passed by value 23 // - getting around that receiver cannot be interface 24 // - receiver is value struct with pointer in the form of an interface 25 type GoResult struct{ goResult } 26 27 func (g GoResult) IsValid() (isValid bool) { return g.goResult != nil } 28 29 type goResult interface { 30 // SendError sends error as the final action of a goroutine 31 // - SendError makes a goroutine: 32 // - — awaitable and 33 // - — able to return a fatal error 34 // - — other needs of a goroutine is to initiate and detect cancel and 35 // submit non-fatal errors 36 // - errCh should be a buffered channel large enough for all its goroutines 37 // - — this prevents goroutines from blocking in channel send 38 // - SendError only panics from structural coding problems 39 // - deferrable thread-safe 40 SendError(errp *error) 41 // ReceiveError is a deferrable function receiving error values from goroutines 42 // - n is number of goroutines to wait for, default 1 43 // - — for [NewGoResult2] default wait for all remaining threads 44 // - errp may be nil 45 // - ReceiveError makes a goroutine: 46 // - — awaitable and 47 // - — able to return a fatal error 48 // - — other needs of a goroutine is to initiate and detect cancel and 49 // submit non-fatal errors 50 // - GoRoutine should have enough capacity for all its goroutines 51 // - — this prevents goroutines from blocking in channel send 52 // - ReceiveError only panics from structural coding problems 53 // - deferrable thread-safe 54 ReceiveError(errp *error, n ...int) (err error) 55 // Count returns number of results that can be currently collected 56 // - Thread-safe 57 Count() (count int) 58 // IsError returns if any goroutine has returned an error 59 // - only for [NewGoResult2] 60 IsError() (isError bool) 61 SetIsError() 62 // Remaining returns the number of goroutines that have yet to exit 63 // - only for [NewGoResult2] 64 Remaining() (remaining int) 65 } 66 67 // NewGoResult returns the minimum mechanic to make a goroutine awaitable 68 // - n is goroutine capacity, default 1 69 // - mechanic is buffered channel 70 // - a thread-launcher provides a GoResult value of sufficient capacity to its launched threads 71 // - exiting threads send an error value that may be nil 72 // - the thread-launcher awaits results one by one 73 // - to avoid threads blocking prior to exiting, the channel must have sufficient capacity 74 // 75 // Usage: 76 // 77 // func someFunc(text string) (err error) { 78 // var g = parl.NewGoResult() 79 // go goroutine(text, g) 80 // defer g.ReceiveError(&err) 81 // … 82 // func goroutine(text string, g parl.GoResult) { 83 // var err error 84 // defer g.SendError(&err) 85 // defer parl.RecoverErr(func() parl.DA { return parl.A() }, &err) 86 // 87 // err = … 88 func NewGoResult(n ...int) (goResult GoResult) { return GoResult{goResult: newGoResultChan(n...)} } 89 90 // NewGoResult2 also has [GoResult.IsError] [GoResult.Remaining] 91 func NewGoResult2(n ...int) (goResult GoResult) { 92 return GoResult{goResult: newGoResultStruct(newGoResultChan(n...))} 93 }