wrap.go raw

   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  //
  39  // Deprecated: As of Go 1.13, use errors.Unwrap instead.
  40  func Unwrap(err error) error {
  41  	u, ok := err.(Wrapper)
  42  	if !ok {
  43  		return nil
  44  	}
  45  	return u.Unwrap()
  46  }
  47  
  48  // Is reports whether any error in err's chain matches target.
  49  //
  50  // An error is considered to match a target if it is equal to that target or if
  51  // it implements a method Is(error) bool such that Is(target) returns true.
  52  //
  53  // Deprecated: As of Go 1.13, use errors.Is instead.
  54  func Is(err, target error) bool {
  55  	if target == nil {
  56  		return err == target
  57  	}
  58  
  59  	isComparable := reflect.TypeOf(target).Comparable()
  60  	for {
  61  		if isComparable && err == target {
  62  			return true
  63  		}
  64  		if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
  65  			return true
  66  		}
  67  		// TODO: consider supporing target.Is(err). This would allow
  68  		// user-definable predicates, but also may allow for coping with sloppy
  69  		// APIs, thereby making it easier to get away with them.
  70  		if err = Unwrap(err); err == nil {
  71  			return false
  72  		}
  73  	}
  74  }
  75  
  76  // As finds the first error in err's chain that matches the type to which target
  77  // points, and if so, sets the target to its value and returns true. An error
  78  // matches a type if it is assignable to the target type, or if it has a method
  79  // As(interface{}) bool such that As(target) returns true. As will panic if target
  80  // is not a non-nil pointer to a type which implements error or is of interface type.
  81  //
  82  // The As method should set the target to its value and return true if err
  83  // matches the type to which target points.
  84  //
  85  // Deprecated: As of Go 1.13, use errors.As instead.
  86  func As(err error, target interface{}) bool {
  87  	if target == nil {
  88  		panic("errors: target cannot be nil")
  89  	}
  90  	val := reflect.ValueOf(target)
  91  	typ := val.Type()
  92  	if typ.Kind() != reflect.Ptr || val.IsNil() {
  93  		panic("errors: target must be a non-nil pointer")
  94  	}
  95  	if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) {
  96  		panic("errors: *target must be interface or implement error")
  97  	}
  98  	targetType := typ.Elem()
  99  	for err != nil {
 100  		if reflect.TypeOf(err).AssignableTo(targetType) {
 101  			val.Elem().Set(reflect.ValueOf(err))
 102  			return true
 103  		}
 104  		if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
 105  			return true
 106  		}
 107  		err = Unwrap(err)
 108  	}
 109  	return false
 110  }
 111  
 112  var errorType = reflect.TypeOf((*error)(nil)).Elem()
 113