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

     1  package errors
     2  
     3  import "strings"
     4  
     5  type ContextError interface {
     6  	CallError
     7  	ContextError() ContextError
     8  }
     9  
    10  type ContextErrorBuilder interface {
    11  	ContextError
    12  
    13  	// Desc returns a copy with descriptor is set to desc.
    14  	Desc(desc ErrorDescriptor) ContextErrorBuilder
    15  
    16  	// DescMsg sets the descriptor with the provided string. For the best
    17  	// experience, descMsg should be defined as a constant so that the error
    18  	// users could use it to identify an error. For non-constant descriptor
    19  	// use the Wrap method.
    20  	DescMsg(descMsg string) ContextErrorBuilder
    21  
    22  	// Wrap returns a copy with wrapped error is set to detailingError.
    23  	Wrap(detailingError error) ContextErrorBuilder
    24  
    25  	Fieldset(fields ...NamedError) ContextErrorBuilder
    26  }
    27  
    28  func IsContextError(err error) bool {
    29  	_, ok := err.(ContextError)
    30  	return ok
    31  }
    32  
    33  func Context() ContextErrorBuilder {
    34  	return &contextError{}
    35  }
    36  
    37  func ContextUnspecified() ContextErrorBuilder {
    38  	return Context().Wrap(ErrValueUnspecified)
    39  }
    40  
    41  func IsContextUnspecifiedError(err error) bool {
    42  	if !IsContextError(err) {
    43  		return false
    44  	}
    45  	if desc := UnwrapDescriptor(err); desc != nil {
    46  		return desc == ErrValueUnspecified
    47  	}
    48  	return false
    49  }
    50  
    51  type contextError struct {
    52  	descriptor ErrorDescriptor
    53  	wrapped    error
    54  	fields     []NamedError
    55  }
    56  
    57  var (
    58  	_ error               = &contextError{}
    59  	_ CallError           = &contextError{}
    60  	_ ContextError        = &contextError{}
    61  	_ ContextErrorBuilder = &contextError{}
    62  	_ Unwrappable         = &contextError{}
    63  )
    64  
    65  func (e *contextError) Error() string {
    66  	suffix := e.fieldErrorsAsString()
    67  	if suffix != "" {
    68  		suffix = ": " + suffix
    69  	}
    70  	var descStr string
    71  	if e.descriptor != nil {
    72  		descStr = e.descriptor.Error()
    73  	}
    74  	causeStr := errorString(e.wrapped)
    75  	if causeStr == "" {
    76  		causeStr = descStr
    77  	} else if descStr != "" {
    78  		causeStr = descStr + ": " + causeStr
    79  	}
    80  
    81  	if causeStr != "" {
    82  		return "context " + causeStr + suffix
    83  	}
    84  	return "context invalid" + suffix
    85  }
    86  
    87  func (e *contextError) CallError() CallError       { return e }
    88  func (e *contextError) ContextError() ContextError { return e }
    89  func (e *contextError) Unwrap() error              { return e.wrapped }
    90  
    91  func (e contextError) fieldErrorsAsString() string {
    92  	if flen := len(e.fields); flen > 0 {
    93  		parts := make([]string, 0, flen)
    94  		for _, sub := range e.fields {
    95  			parts = append(parts, sub.Error())
    96  		}
    97  		return strings.Join(parts, ", ")
    98  	}
    99  	return ""
   100  }
   101  
   102  func (e contextError) Descriptor() ErrorDescriptor {
   103  	if e.descriptor != nil {
   104  		return e.descriptor
   105  	}
   106  	if desc, ok := e.wrapped.(ErrorDescriptor); ok {
   107  		return desc
   108  	}
   109  	return nil
   110  }
   111  
   112  func (e contextError) Desc(desc ErrorDescriptor) ContextErrorBuilder {
   113  	e.descriptor = desc
   114  	return &e
   115  }
   116  
   117  func (e contextError) DescMsg(descMsg string) ContextErrorBuilder {
   118  	e.descriptor = constantErrorDescriptor(descMsg)
   119  	return &e
   120  }
   121  
   122  func (e contextError) Fieldset(fields ...NamedError) ContextErrorBuilder {
   123  	e.fields = fields // copy?
   124  	return &e
   125  }
   126  
   127  func (e contextError) Wrap(detailingError error) ContextErrorBuilder {
   128  	e.wrapped = detailingError
   129  	return &e
   130  }