You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

wrap.go 3.1 kB

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