github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/errors/wrap.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package errors 6 7 import ( 8 "internal/reflectlite" 9 ) 10 11 // Unwrap returns the result of calling the Unwrap method on err, if err's 12 // type contains an Unwrap method returning error. 13 // Otherwise, Unwrap returns nil. 14 // 15 // Unwrap returns nil if the Unwrap method returns []error. 16 func Unwrap(err error) error { 17 u, ok := err.(interface { 18 Unwrap() error 19 }) 20 if !ok { 21 return nil 22 } 23 return u.Unwrap() 24 } 25 26 // Is reports whether any error in err's tree matches target. 27 // 28 // The tree consists of err itself, followed by the errors obtained by repeatedly 29 // calling Unwrap. When err wraps multiple errors, Is examines err followed by a 30 // depth-first traversal of its children. 31 // 32 // An error is considered to match a target if it is equal to that target or if 33 // it implements a method Is(error) bool such that Is(target) returns true. 34 // 35 // An error type might provide an Is method so it can be treated as equivalent 36 // to an existing error. For example, if MyError defines 37 // 38 // func (m MyError) Is(target error) bool { return target == fs.ErrExist } 39 // 40 // then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for 41 // an example in the standard library. An Is method should only shallowly 42 // compare err and the target and not call Unwrap on either. 43 func Is(err, target error) bool { 44 if target == nil { 45 return err == target 46 } 47 48 isComparable := reflectlite.TypeOf(target).Comparable() 49 for { 50 if isComparable && err == target { 51 return true 52 } 53 if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) { 54 return true 55 } 56 switch x := err.(type) { 57 case interface{ Unwrap() error }: 58 err = x.Unwrap() 59 if err == nil { 60 return false 61 } 62 case interface{ Unwrap() []error }: 63 for _, err := range x.Unwrap() { 64 if Is(err, target) { 65 return true 66 } 67 } 68 return false 69 default: 70 return false 71 } 72 } 73 } 74 75 // As finds the first error in err's tree that matches target, and if one is found, sets 76 // target to that error value and returns true. Otherwise, it returns false. 77 // 78 // The tree consists of err itself, followed by the errors obtained by repeatedly 79 // calling Unwrap. When err wraps multiple errors, As examines err followed by a 80 // depth-first traversal of its children. 81 // 82 // An error matches target if the error's concrete value is assignable to the value 83 // pointed to by target, or if the error has a method As(interface{}) bool such that 84 // As(target) returns true. In the latter case, the As method is responsible for 85 // setting target. 86 // 87 // An error type might provide an As method so it can be treated as if it were a 88 // different error type. 89 // 90 // As panics if target is not a non-nil pointer to either a type that implements 91 // error, or to any interface type. 92 func As(err error, target any) bool { 93 if err == nil { 94 return false 95 } 96 if target == nil { 97 panic("errors: target cannot be nil") 98 } 99 val := reflectlite.ValueOf(target) 100 typ := val.Type() 101 if typ.Kind() != reflectlite.Ptr || val.IsNil() { 102 panic("errors: target must be a non-nil pointer") 103 } 104 targetType := typ.Elem() 105 if targetType.Kind() != reflectlite.Interface && !targetType.Implements(errorType) { 106 panic("errors: *target must be interface or implement error") 107 } 108 for { 109 if reflectlite.TypeOf(err).AssignableTo(targetType) { 110 val.Elem().Set(reflectlite.ValueOf(err)) 111 return true 112 } 113 if x, ok := err.(interface{ As(any) bool }); ok && x.As(target) { 114 return true 115 } 116 switch x := err.(type) { 117 case interface{ Unwrap() error }: 118 err = x.Unwrap() 119 if err == nil { 120 return false 121 } 122 case interface{ Unwrap() []error }: 123 for _, err := range x.Unwrap() { 124 if As(err, target) { 125 return true 126 } 127 } 128 return false 129 default: 130 return false 131 } 132 } 133 } 134 135 var errorType = reflectlite.TypeOf((*error)(nil)).Elem()