zen/core/zerr/sequence.go

109 lines
2.3 KiB
Go

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
}
}
}
}
}