github.com/alloyzeus/go-azfl@v0.0.0-20231220071816-9740126a2d07/errors/descriptor.go (about)

     1  package errors
     2  
     3  // A ErrorDescriptor provides the description-part of an error.
     4  //
     5  // In a good practice, an error contains an information about *what* and *why*.
     6  // A ErrorDescriptor abstracts the answers to the *why*.
     7  //
     8  // "User is not found" could be break down into "User" as the answer to the
     9  // *what*, and "not found" as the answer to the *why*. Here, the ErrorDescriptor
    10  // will contain the "not found".
    11  //
    12  // This interface could be used to describe any *what*, like the method
    13  // in "method not implemented". For specific to data, see DataDescriptorError.
    14  type ErrorDescriptor interface {
    15  	error
    16  	ErrorDescriptorString() string
    17  }
    18  
    19  type hasDescriptor interface {
    20  	Descriptor() ErrorDescriptor
    21  }
    22  
    23  func DescWrap(descriptor ErrorDescriptor, details error) error {
    24  	return descriptorDetailsError{descriptor: descriptor, details: details}
    25  }
    26  
    27  type descriptorDetailsError struct {
    28  	descriptor ErrorDescriptor
    29  	details    error
    30  }
    31  
    32  var (
    33  	_ error         = descriptorDetailsError{}
    34  	_ hasDescriptor = descriptorDetailsError{}
    35  	_ Unwrappable   = descriptorDetailsError{}
    36  )
    37  
    38  func (e descriptorDetailsError) Error() string {
    39  	if e.descriptor != nil {
    40  		if e.details != nil {
    41  			return e.descriptor.Error() + ": " + e.details.Error()
    42  		}
    43  		return e.descriptor.Error()
    44  	}
    45  	if e.details != nil {
    46  		return e.details.Error()
    47  	}
    48  	return ""
    49  }
    50  
    51  func (e descriptorDetailsError) Descriptor() ErrorDescriptor { return e.descriptor }
    52  func (e descriptorDetailsError) Unwrap() error               { return e.details }
    53  
    54  // constantErrorDescriptor is a generic error that designed to be declared
    55  // as constant so that an instance could be easily compared by value to
    56  // its original definiton.
    57  //
    58  // A constantErrorDescriptor is not providing a full context about an error,
    59  // instead it's designed to be wrapped to provide context to the parent error.
    60  type constantErrorDescriptor string
    61  
    62  var (
    63  	_ error           = constantErrorDescriptor("")
    64  	_ ErrorDescriptor = constantErrorDescriptor("")
    65  )
    66  
    67  func (e constantErrorDescriptor) Error() string                 { return string(e) }
    68  func (e constantErrorDescriptor) ErrorDescriptorString() string { return string(e) }
    69  
    70  func UnwrapDescriptor(err error) ErrorDescriptor {
    71  	if err != nil {
    72  		if d, ok := err.(hasDescriptor); ok {
    73  			return d.Descriptor()
    74  		}
    75  	}
    76  	return nil
    77  }
    78  
    79  func HasDescriptor(err error, desc ErrorDescriptor) bool {
    80  	d := UnwrapDescriptor(err)
    81  	//TODO: use other strategies. even reflect as the last resort
    82  	return d == desc
    83  }
    84  
    85  func HasDescriptorText(err error, descText string) bool {
    86  	d := UnwrapDescriptor(err)
    87  	return d.Error() == descText
    88  }
    89  
    90  func errorDescriptorString(err error) string {
    91  	if err != nil {
    92  		if desc, ok := err.(ErrorDescriptor); ok {
    93  			return desc.ErrorDescriptorString()
    94  		}
    95  	}
    96  	return ""
    97  }