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

     1  package errors
     2  
     3  //TODO: ArgSet
     4  
     5  // ArgumentError abstracts all errors which was caused by error in
     6  // one of the arguments in a function call. This class of error
     7  // has the similar concept as 4xx status codes in HTTP, and thus can
     8  // be mapped into one of these code when used in HTTP request handlers.
     9  type ArgumentError interface {
    10  	CallError
    11  	Unwrappable
    12  
    13  	// ArgumentName returns the name of the offending argument. It might
    14  	// be empty if there's only one argument.
    15  	ArgumentName() string
    16  
    17  	Descriptor() ErrorDescriptor
    18  	FieldErrors() []NamedError
    19  }
    20  
    21  type ArgumentErrorBuilder interface {
    22  	ArgumentError
    23  
    24  	// Desc returns a copy with descriptor is set to desc.
    25  	Desc(desc ErrorDescriptor) ArgumentErrorBuilder
    26  
    27  	// DescMsg sets the descriptor with the provided string. For the best
    28  	// experience, descMsg should be defined as a constant so that the error
    29  	// users could use it to identify an error. For non-constant descriptor
    30  	// use the Wrap method.
    31  	DescMsg(descMsg string) ArgumentErrorBuilder
    32  
    33  	// Hint provides a clue for the developers on how to fix the error.
    34  	Hint(hintText string) ArgumentErrorBuilder
    35  
    36  	Fieldset(fields ...NamedError) ArgumentErrorBuilder
    37  
    38  	// Rewrap collects descriptor, wrapped, and fields from err and include
    39  	// them into the new error.
    40  	Rewrap(err error) ArgumentErrorBuilder
    41  
    42  	// Wrap returns a copy with wrapped error is set to detailingError.
    43  	Wrap(detailingError error) ArgumentErrorBuilder
    44  }
    45  
    46  func IsArgumentError(err error) bool {
    47  	_, ok := err.(ArgumentError)
    48  	return ok
    49  }
    50  
    51  // AsArgumentError returns non-nil if err is indeed an ArgumentError.
    52  func AsArgumentError(err error) ArgumentError {
    53  	if e, ok := err.(ArgumentError); ok {
    54  		return e
    55  	}
    56  	return nil
    57  }
    58  
    59  func Arg(argName string) ArgumentErrorBuilder {
    60  	return &argumentError{
    61  		argName: argName,
    62  	}
    63  }
    64  
    65  // Arg1 is used when there's only one argument for a function.
    66  func Arg1() ArgumentErrorBuilder {
    67  	return Arg("")
    68  }
    69  
    70  // ArgUnspecified describes that argument with name argName is unspecified.
    71  func ArgUnspecified(argName string) ArgumentErrorBuilder {
    72  	return &argumentError{
    73  		argName:    argName,
    74  		descriptor: ErrValueUnspecified,
    75  	}
    76  }
    77  
    78  func IsArgumentUnspecifiedError(err error) bool {
    79  	if !IsArgumentError(err) {
    80  		return false
    81  	}
    82  	if desc := UnwrapDescriptor(err); desc != nil {
    83  		return desc == ErrValueUnspecified
    84  	}
    85  	return false
    86  }
    87  
    88  // ArgValueUnsupported creates an ArgumentError with name is set to the value
    89  // of argName and descriptor is set to ErrValueUnsupported.
    90  func ArgValueUnsupported(argName string) ArgumentErrorBuilder {
    91  	return &argumentError{
    92  		argName:    argName,
    93  		descriptor: ErrValueUnsupported,
    94  	}
    95  }
    96  
    97  // IsArgumentUnspecified checks if an error describes about unspecifity of an argument.
    98  //
    99  //TODO: ArgSet
   100  func IsArgumentUnspecified(err error, argName string) bool {
   101  	if err == nil {
   102  		return false
   103  	}
   104  	argErr, ok := err.(ArgumentError)
   105  	if !ok {
   106  		return false
   107  	}
   108  	if argErr.ArgumentName() != argName {
   109  		return false
   110  	}
   111  	if desc := UnwrapDescriptor(err); desc != nil {
   112  		return desc == ErrValueUnspecified
   113  	}
   114  	return false
   115  }
   116  
   117  type argumentError struct {
   118  	argName    string
   119  	descriptor ErrorDescriptor
   120  	hintText   string
   121  	fields     []NamedError
   122  	wrapped    error
   123  }
   124  
   125  var (
   126  	_ error                = &argumentError{}
   127  	_ Unwrappable          = &argumentError{}
   128  	_ CallError            = &argumentError{}
   129  	_ ArgumentError        = &argumentError{}
   130  	_ ArgumentErrorBuilder = &argumentError{}
   131  	_ hasDescriptor        = &argumentError{}
   132  	_ hasFieldErrors       = &argumentError{}
   133  )
   134  
   135  func (e *argumentError) ArgumentName() string {
   136  	return e.argName
   137  }
   138  
   139  func (e *argumentError) CallError() CallError { return e }
   140  
   141  func (e *argumentError) Error() string {
   142  	suffix := namedSetToString(e.fields)
   143  	if suffix != "" {
   144  		suffix = ": " + suffix
   145  	}
   146  	if e.hintText != "" {
   147  		suffix = suffix + ". " + e.hintText
   148  	}
   149  	var descStr string
   150  	if e.descriptor != nil {
   151  		descStr = e.descriptor.Error()
   152  	}
   153  	causeStr := errorString(e.wrapped)
   154  	if causeStr == "" {
   155  		causeStr = descStr
   156  	} else if descStr != "" {
   157  		causeStr = descStr + ": " + causeStr
   158  	}
   159  
   160  	if e.argName != "" {
   161  		if causeStr != "" {
   162  			return "arg " + e.argName + ": " + causeStr + suffix
   163  		}
   164  		return "arg " + e.argName + suffix
   165  	}
   166  	if causeStr != "" {
   167  		return "arg " + causeStr + suffix
   168  	}
   169  	if suffix != "" {
   170  		return "arg" + suffix
   171  	}
   172  	return "arg error"
   173  }
   174  
   175  func (e argumentError) Descriptor() ErrorDescriptor { return e.descriptor }
   176  func (e argumentError) Unwrap() error               { return e.wrapped }
   177  func (e argumentError) FieldErrors() []NamedError   { return copyNamedSet(e.fields) }
   178  
   179  func (e argumentError) Desc(desc ErrorDescriptor) ArgumentErrorBuilder {
   180  	e.descriptor = desc
   181  	return &e
   182  }
   183  
   184  func (e argumentError) DescMsg(descMsg string) ArgumentErrorBuilder {
   185  	e.descriptor = constantErrorDescriptor(descMsg)
   186  	return &e
   187  }
   188  
   189  func (e argumentError) Hint(hintText string) ArgumentErrorBuilder {
   190  	e.hintText = hintText
   191  	return &e
   192  }
   193  
   194  func (e argumentError) Fieldset(fields ...NamedError) ArgumentErrorBuilder {
   195  	e.fields = copyNamedSet(fields)
   196  	return &e
   197  }
   198  
   199  func (e argumentError) Rewrap(err error) ArgumentErrorBuilder {
   200  	if err != nil {
   201  		if descErr, _ := err.(ErrorDescriptor); descErr != nil {
   202  			e.descriptor = descErr
   203  			e.wrapped = nil
   204  			e.fields = nil
   205  		} else {
   206  			e.descriptor = UnwrapDescriptor(err)
   207  			e.wrapped = Unwrap(err)
   208  			e.fields = UnwrapFieldErrors(err)
   209  		}
   210  	}
   211  	return &e
   212  }
   213  
   214  func (e argumentError) Wrap(detailingError error) ArgumentErrorBuilder {
   215  	e.wrapped = detailingError
   216  	return &e
   217  }
   218  
   219  type ArgumentErrorChecker struct {
   220  	errToCheck ArgumentError
   221  	truthState bool
   222  }
   223  
   224  func ArgumentErrorCheck(err error) ArgumentErrorChecker {
   225  	argErr, ok := err.(ArgumentError)
   226  	return ArgumentErrorChecker{
   227  		errToCheck: argErr,
   228  		truthState: ok,
   229  	}
   230  }
   231  
   232  func (checker ArgumentErrorChecker) IsTrue() bool { return checker.truthState }
   233  
   234  func (checker ArgumentErrorChecker) HasName(argName string) ArgumentErrorChecker {
   235  	if err := checker.errToCheck; err == nil || err.ArgumentName() != argName {
   236  		checker.truthState = false
   237  	}
   238  	return checker
   239  }
   240  
   241  func (checker ArgumentErrorChecker) HasDesc(desc ErrorDescriptor) ArgumentErrorChecker {
   242  	if !HasDescriptor(checker.errToCheck, desc) {
   243  		checker.truthState = false
   244  	}
   245  	return checker
   246  }
   247  
   248  func (checker ArgumentErrorChecker) HasWrapped(err error) ArgumentErrorChecker {
   249  	if !Is(err, Unwrap(checker.errToCheck)) {
   250  		checker.truthState = false
   251  	}
   252  	return checker
   253  }