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 struct { parent *Sequence children []*Sequence err Error } // WrapBy prepends the next Sequence to the current Sequence. func (se *Sequence) WrapBy(parent *Sequence) { parent.children = append(parent.children, se) se.parent = parent } // Outer returns the error that wraps this Error. // Return nil if this Error is not wrapped // or wrapping outer is not a zerr.Error. func (se *Sequence) Outer() Error { if se.parent != nil { return se.parent.err } return nil } // Root returns the outermost Error in the sequence. // // Returns self if there is no outermost. func (se *Sequence) Root() *Sequence { root := se for root.parent != nil { root = root.parent } return root } // 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 } } } } }