Source file src/errors/wrap.go

Documentation: errors

     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  func Unwrap(err error) error {
    15  	u, ok := err.(interface {
    16  		Unwrap() error
    17  	})
    18  	if !ok {
    19  		return nil
    20  	}
    21  	return u.Unwrap()
    22  }
    23  
    24  // Is reports whether any error in err's chain matches target.
    25  //
    26  // The chain consists of err itself followed by the sequence of errors obtained by
    27  // repeatedly calling Unwrap.
    28  //
    29  // An error is considered to match a target if it is equal to that target or if
    30  // it implements a method Is(error) bool such that Is(target) returns true.
    31  func Is(err, target error) bool {
    32  	if target == nil {
    33  		return err == target
    34  	}
    35  
    36  	isComparable := reflectlite.TypeOf(target).Comparable()
    37  	for {
    38  		if isComparable && err == target {
    39  			return true
    40  		}
    41  		if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
    42  			return true
    43  		}
    44  		// TODO: consider supporing target.Is(err). This would allow
    45  		// user-definable predicates, but also may allow for coping with sloppy
    46  		// APIs, thereby making it easier to get away with them.
    47  		if err = Unwrap(err); err == nil {
    48  			return false
    49  		}
    50  	}
    51  }
    52  
    53  // As finds the first error in err's chain that matches target, and if so, sets
    54  // target to that error value and returns true.
    55  //
    56  // The chain consists of err itself followed by the sequence of errors obtained by
    57  // repeatedly calling Unwrap.
    58  //
    59  // An error matches target if the error's concrete value is assignable to the value
    60  // pointed to by target, or if the error has a method As(interface{}) bool such that
    61  // As(target) returns true. In the latter case, the As method is responsible for
    62  // setting target.
    63  //
    64  // As will panic if target is not a non-nil pointer to either a type that implements
    65  // error, or to any interface type. As returns false if err is nil.
    66  func As(err error, target interface{}) bool {
    67  	if target == nil {
    68  		panic("errors: target cannot be nil")
    69  	}
    70  	val := reflectlite.ValueOf(target)
    71  	typ := val.Type()
    72  	if typ.Kind() != reflectlite.Ptr || val.IsNil() {
    73  		panic("errors: target must be a non-nil pointer")
    74  	}
    75  	if e := typ.Elem(); e.Kind() != reflectlite.Interface && !e.Implements(errorType) {
    76  		panic("errors: *target must be interface or implement error")
    77  	}
    78  	targetType := typ.Elem()
    79  	for err != nil {
    80  		if reflectlite.TypeOf(err).AssignableTo(targetType) {
    81  			val.Elem().Set(reflectlite.ValueOf(err))
    82  			return true
    83  		}
    84  		if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
    85  			return true
    86  		}
    87  		err = Unwrap(err)
    88  	}
    89  	return false
    90  }
    91  
    92  var errorType = reflectlite.TypeOf((*error)(nil)).Elem()
    93  

View as plain text