| // Copyright 2018 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package errors | |
| import ( | |
| "internal/reflectlite" | |
| ) | |
| // Unwrap returns the result of calling the Unwrap method on err, if err's | |
| // type contains an Unwrap method returning error. | |
| // Otherwise, Unwrap returns nil. | |
| func Unwrap(err error) error { | |
| u, ok := err.(interface { | |
| Unwrap() error | |
| }) | |
| if !ok { | |
| return nil | |
| } | |
| return u.Unwrap() | |
| } | |
| // Is reports whether any error in err's chain matches target. | |
| // | |
| // The chain consists of err itself followed by the sequence of errors obtained by | |
| // repeatedly calling Unwrap. | |
| // | |
| // An error is considered to match a target if it is equal to that target or if | |
| // it implements a method Is(error) bool such that Is(target) returns true. | |
| // | |
| // An error type might provide an Is method so it can be treated as equivalent | |
| // to an existing error. For example, if MyError defines | |
| // | |
| // func (m MyError) Is(target error) bool { return target == fs.ErrExist } | |
| // | |
| // then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for | |
| // an example in the standard library. An Is method should only shallowly | |
| // compare err and the target and not call Unwrap on either. | |
| func Is(err, target error) bool { | |
| if target == nil { | |
| return err == target | |
| } | |
| isComparable := reflectlite.TypeOf(target).Comparable() | |
| for { | |
| if isComparable && err == target { | |
| return true | |
| } | |
| if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) { | |
| return true | |
| } | |
| // TODO: consider supporting target.Is(err). This would allow | |
| // user-definable predicates, but also may allow for coping with sloppy | |
| // APIs, thereby making it easier to get away with them. | |
| if err = Unwrap(err); err == nil { | |
| return false | |
| } | |
| } | |
| } | |
| // As finds the first error in err's chain that matches target, and if one is found, sets | |
| // target to that error value and returns true. Otherwise, it returns false. | |
| // | |
| // The chain consists of err itself followed by the sequence of errors obtained by | |
| // repeatedly calling Unwrap. | |
| // | |
| // An error matches target if the error's concrete value is assignable to the value | |
| // pointed to by target, or if the error has a method As(interface{}) bool such that | |
| // As(target) returns true. In the latter case, the As method is responsible for | |
| // setting target. | |
| // | |
| // An error type might provide an As method so it can be treated as if it were a | |
| // different error type. | |
| // | |
| // As panics if target is not a non-nil pointer to either a type that implements | |
| // error, or to any interface type. | |
| func As(err error, target any) bool { | |
| if target == nil { | |
| panic("errors: target cannot be nil") | |
| } | |
| val := reflectlite.ValueOf(target) | |
| typ := val.Type() | |
| if typ.Kind() != reflectlite.Ptr || val.IsNil() { | |
| panic("errors: target must be a non-nil pointer") | |
| } | |
| targetType := typ.Elem() | |
| if targetType.Kind() != reflectlite.Interface && !targetType.Implements(errorType) { | |
| panic("errors: *target must be interface or implement error") | |
| } | |
| for err != nil { | |
| if reflectlite.TypeOf(err).AssignableTo(targetType) { | |
| val.Elem().Set(reflectlite.ValueOf(err)) | |
| return true | |
| } | |
| if x, ok := err.(interface{ As(any) bool }); ok && x.As(target) { | |
| return true | |
| } | |
| err = Unwrap(err) | |
| } | |
| return false | |
| } | |
| var errorType = reflectlite.TypeOf((*error)(nil)).Elem() |