package zerr import "iter" // Sequence keeps track of the sequence of errors. // // The implementation is reversed linked list. // // When wrapping errors, the wrapping error // will be the parent of the wrapped Error // if the wrapped Error is a zerr.Error. type Sequence interface { // WrapBy prepends the next Sequence to the current Sequence. WrapBy(parent Sequence) // Parent returns the parent Sequence. // Return nil if this Sequence is Root. Parent() Sequence // Root returns the outermost Sequence in the sequence. // // Returns self if current Sequence is the outermost. Root() Sequence // IsRoot checks if the Sequence is the outermost Sequence in the sequence. IsRoot() bool // Error returns the Error in the sequence. Error() Error // Iter returns an iterator to traverse Errors in the sequence. Iter() iter.Seq[Error] // AppendChild appends a child Sequence to the current Sequence. AppendChild(child Sequence) } type sequence struct { parent Sequence children []Sequence err Error } func (se *sequence) WrapBy(parent Sequence) { parent.AppendChild(se) se.parent = parent } func (se *sequence) AppendChild(child Sequence) { se.children = append(se.children, child) } func (se *sequence) Parent() Sequence { if se.parent != nil { return se.parent } return nil } // Root returns the outermost Error in the sequence. // // Returns self if there is no outermost. func (se *sequence) Root() Sequence { var root Sequence = se for { if root.Parent() == nil { return root } root = root.Parent() } } // IsRoot checks if the Error is the outermost Error in the sequence. func (se *sequence) IsRoot() bool { return se.parent == nil } // Error returns the Error in the sequence. func (se *sequence) Error() Error { return se.err } // Iter returns an iterator to traverse the sequence. // // Iterator will skip any nil values in the sequence. // // Iteration is traversed depth first. // // Example: // // for e := range err.Sequence().Iter() { // // e is zerr.Error // // do something with e // } func (se *sequence) Iter() iter.Seq[Error] { return func(yield func(Error) bool) { if se.err != nil && !yield(se.err) { return } for _, child := range se.children { for e := range child.Iter() { if !yield(e) { return } } } } }