descent

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 24, 2025 License: MIT Imports: 1 Imported by: 0

README

descent

Functions that iterate over trees of errors defined using

interface { Unwrap()   error }
interface { Unwrap() []error }

These interfaces are how the errors package implements error comparison via errors.Is and errors.As.

Documentation

Overview

Iterators over the error tree used by errors.Is and errors.As.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func BreadthFirst

func BreadthFirst(err error) iter.Seq[error]

Iterates from the root error over the tree of errors defined by `Unwrap() error` and `Unwrap() []error` interfaces. Yields each error's siblings before moving to their children.

This is a different order than errors.Is errors.As.

Example
package main

import (
	"errors"
	"fmt"

	descent "github.com/skalt/descent.go"
)

func main() {
	err := errors.Join(
		errors.New("a"),
		fmt.Errorf("b: %w",
			errors.Join(
				fmt.Errorf("d: %w", errors.New("f")),
				nil,
				errors.New("e"),
			),
		),
		errors.New("c"),
	)
	i := 0
	for e := range descent.BreadthFirst(err) {
		fmt.Printf("%d %T(%#v)\n", i, e, e.Error())
		if e.Error() == "e" {
			break
		}
		i += 1
	}
}
Output:

0 *errors.joinError("a\nb: d: f\ne\nc")
1 *errors.errorString("a")
2 *fmt.wrapError("b: d: f\ne")
3 *errors.errorString("c")
4 *errors.joinError("d: f\ne")
5 *fmt.wrapError("d: f")
6 *errors.errorString("e")
Example (NoChildren)
package main

import (
	"errors"
	"fmt"

	descent "github.com/skalt/descent.go"
)

type noChildren string

func (err noChildren) Error() string { return string(err) }
func (noChildren) Unwrap() []error   { return nil }

func main() {
	err := errors.Join(
		errors.New("a"),
		noChildren("b"),
		errors.Join(errors.New("c")),
	)
	for e := range descent.BreadthFirst(err) {
		switch t := e.(type) {
		case interface{ Unwrap() []error }:
			{
				children := t.Unwrap()
				fmt.Printf("%q: %d children\n", e.Error(), len(children))
				for i, child := range children {
					fmt.Printf("  %d. %q\n", i, child.Error())
				}
			}
		case interface{ Unwrap() error }:
			{
				fmt.Printf("%q: 1 child\n", e.Error())
				child := t.Unwrap()
				fmt.Printf("  0. %q\n", child.Error())
			}
		default:
			fmt.Printf("%q (no children)\n", e.Error())
		}
	}
}
Output:

"a\nb\nc": 3 children
  0. "a"
  1. "b"
  2. "c"
"a" (no children)
"b": 0 children
"c": 1 children
  0. "c"
"c" (no children)

func DepthFirst

func DepthFirst(err error) iter.Seq[error]

Iterates from the root error over the tree of errors defined by `Unwrap() error` and `Unwrap() []error` interfaces. Yields each error and its children before moving to the next sibling.

This is the same order used by errors.Is errors.As.

Example
package main

import (
	"errors"
	"fmt"

	descent "github.com/skalt/descent.go"
)

func main() {
	err := errors.Join(
		errors.New("a"),
		fmt.Errorf("b: %w",
			errors.Join(
				fmt.Errorf("c: %w", errors.New("d")),
				nil,
				errors.New("e"),
			),
		),
		errors.New("f"),
	)
	i := 0
	for e := range descent.DepthFirst(err) {
		fmt.Printf("%d %T(%#v)\n", i, e, e.Error())
		i += 1
	}
}
Output:

0 *errors.joinError("a\nb: c: d\ne\nf")
1 *errors.errorString("a")
2 *fmt.wrapError("b: c: d\ne")
3 *errors.joinError("c: d\ne")
4 *fmt.wrapError("c: d")
5 *errors.errorString("d")
6 *errors.errorString("e")
7 *errors.errorString("f")

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL