From f3550c86f6480045d89085cd867c8ead1812694d Mon Sep 17 00:00:00 2001 From: Noah Stride Date: Mon, 27 Jun 2022 10:53:34 +0100 Subject: [PATCH] Switch `aggregate` to iterating directly within `Is` and `As` --- trace.go | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/trace.go b/trace.go index 2ca1c09..ba7f40e 100644 --- a/trace.go +++ b/trace.go @@ -454,35 +454,26 @@ func (r aggregate) Error() string { return output } -// Unwrap implements `errors.Unwrap` in a somewhat unusual way to support -// `errors.Is` and `errors.As`. -// -// One might expect Unwrap to return the error at the head of the slice, but, -// instead we return the slice excluding the head. This, in combination with -// `aggregate.Is` re-invoking `errors.Is` on the head of the slice essentially -// allows for the original `errors.Is` to navigate the tree of error chains -// created by `aggregate`. -// -// Reading the implementation for `errors.Is` and `errors.As` should provide -// some further explanation. -func (r aggregate) Unwrap() error { - if len(r) == 1 { - return nil - } - - return r[1:] -} - -// Is implements the errors.Is interface by re-invoking errors.Is on the error -// at the head of the slice. +// Is implements the `Is` interface, by iterating through each error in the +// aggregate and invoking `errors.Is`. func (r aggregate) Is(t error) bool { - return errors.Is(r[0], t) + for _, err := range r { + if errors.Is(err, t) { + return true + } + } + return false } -// As implements the errors.As interface by re-invoking errors.As on the error -// at the head of the slice. +// As implements the `As` interface, by iterating through each error in the +// aggregate and invoking `errors.As`. func (r aggregate) As(t interface{}) bool { - return errors.As(r[0], t) + for _, err := range r { + if errors.As(err, t) { + return true + } + } + return false } // Errors obtains the list of errors this aggregate combines