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 xerrors
|
---|
6 |
|
---|
7 | import (
|
---|
8 | "reflect"
|
---|
9 | )
|
---|
10 |
|
---|
11 | // A Wrapper provides context around another error.
|
---|
12 | type Wrapper interface {
|
---|
13 | // Unwrap returns the next error in the error chain.
|
---|
14 | // If there is no next error, Unwrap returns nil.
|
---|
15 | Unwrap() error
|
---|
16 | }
|
---|
17 |
|
---|
18 | // Opaque returns an error with the same error formatting as err
|
---|
19 | // but that does not match err and cannot be unwrapped.
|
---|
20 | func Opaque(err error) error {
|
---|
21 | return noWrapper{err}
|
---|
22 | }
|
---|
23 |
|
---|
24 | type noWrapper struct {
|
---|
25 | error
|
---|
26 | }
|
---|
27 |
|
---|
28 | func (e noWrapper) FormatError(p Printer) (next error) {
|
---|
29 | if f, ok := e.error.(Formatter); ok {
|
---|
30 | return f.FormatError(p)
|
---|
31 | }
|
---|
32 | p.Print(e.error)
|
---|
33 | return nil
|
---|
34 | }
|
---|
35 |
|
---|
36 | // Unwrap returns the result of calling the Unwrap method on err, if err implements
|
---|
37 | // Unwrap. Otherwise, Unwrap returns nil.
|
---|
38 | func Unwrap(err error) error {
|
---|
39 | u, ok := err.(Wrapper)
|
---|
40 | if !ok {
|
---|
41 | return nil
|
---|
42 | }
|
---|
43 | return u.Unwrap()
|
---|
44 | }
|
---|
45 |
|
---|
46 | // Is reports whether any error in err's chain matches target.
|
---|
47 | //
|
---|
48 | // An error is considered to match a target if it is equal to that target or if
|
---|
49 | // it implements a method Is(error) bool such that Is(target) returns true.
|
---|
50 | func Is(err, target error) bool {
|
---|
51 | if target == nil {
|
---|
52 | return err == target
|
---|
53 | }
|
---|
54 |
|
---|
55 | isComparable := reflect.TypeOf(target).Comparable()
|
---|
56 | for {
|
---|
57 | if isComparable && err == target {
|
---|
58 | return true
|
---|
59 | }
|
---|
60 | if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
|
---|
61 | return true
|
---|
62 | }
|
---|
63 | // TODO: consider supporing target.Is(err). This would allow
|
---|
64 | // user-definable predicates, but also may allow for coping with sloppy
|
---|
65 | // APIs, thereby making it easier to get away with them.
|
---|
66 | if err = Unwrap(err); err == nil {
|
---|
67 | return false
|
---|
68 | }
|
---|
69 | }
|
---|
70 | }
|
---|
71 |
|
---|
72 | // As finds the first error in err's chain that matches the type to which target
|
---|
73 | // points, and if so, sets the target to its value and returns true. An error
|
---|
74 | // matches a type if it is assignable to the target type, or if it has a method
|
---|
75 | // As(interface{}) bool such that As(target) returns true. As will panic if target
|
---|
76 | // is not a non-nil pointer to a type which implements error or is of interface type.
|
---|
77 | //
|
---|
78 | // The As method should set the target to its value and return true if err
|
---|
79 | // matches the type to which target points.
|
---|
80 | func As(err error, target interface{}) bool {
|
---|
81 | if target == nil {
|
---|
82 | panic("errors: target cannot be nil")
|
---|
83 | }
|
---|
84 | val := reflect.ValueOf(target)
|
---|
85 | typ := val.Type()
|
---|
86 | if typ.Kind() != reflect.Ptr || val.IsNil() {
|
---|
87 | panic("errors: target must be a non-nil pointer")
|
---|
88 | }
|
---|
89 | if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) {
|
---|
90 | panic("errors: *target must be interface or implement error")
|
---|
91 | }
|
---|
92 | targetType := typ.Elem()
|
---|
93 | for err != nil {
|
---|
94 | if reflect.TypeOf(err).AssignableTo(targetType) {
|
---|
95 | val.Elem().Set(reflect.ValueOf(err))
|
---|
96 | return true
|
---|
97 | }
|
---|
98 | if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
|
---|
99 | return true
|
---|
100 | }
|
---|
101 | err = Unwrap(err)
|
---|
102 | }
|
---|
103 | return false
|
---|
104 | }
|
---|
105 |
|
---|
106 | var errorType = reflect.TypeOf((*error)(nil)).Elem()
|
---|