github.com/alloyzeus/go-azfl@v0.0.0-20231220071816-9740126a2d07/errors/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 &argumentError{
    68  		argName: "",
    69  	}
    70  }
    71  
    72  func ArgFields(argName string, fields ...NamedError) ArgumentErrorBuilder {
    73  	return &argumentError{
    74  		argName: argName,
    75  		fields:  fields,
    76  	}
    77  }
    78  
    79  func ArgMsg(argName, errMsg string, fields ...NamedError) ArgumentErrorBuilder {
    80  	return &argumentError{
    81  		argName: argName,
    82  		wrapped: Msg(errMsg),
    83  		fields:  fields,
    84  	}
    85  }
    86  
    87  func ArgWrap(argName, contextMessage string, err error, fields ...NamedError) ArgumentErrorBuilder {
    88  	return &argumentError{
    89  		argName: argName,
    90  		wrapped: Wrap(contextMessage, err),
    91  		fields:  fields,
    92  	}
    93  }
    94  
    95  // ArgUnspecified describes that argument with name argName is unspecified.
    96  func ArgUnspecified(argName string) ArgumentErrorBuilder {
    97  	return &argumentError{
    98  		argName:    argName,
    99  		descriptor: ErrValueUnspecified,
   100  	}
   101  }
   102  
   103  func IsArgumentUnspecifiedError(err error) bool {
   104  	if !IsArgumentError(err) {
   105  		return false
   106  	}
   107  	if desc := UnwrapDescriptor(err); desc != nil {
   108  		return desc == ErrValueUnspecified
   109  	}
   110  	return false
   111  }
   112  
   113  // ArgValueUnsupported creates an ArgumentError with name is set to the value
   114  // of argName and descriptor is set to ErrValueUnsupported.
   115  func ArgValueUnsupported(argName string) ArgumentErrorBuilder {
   116  	return &argumentError{
   117  		argName:    argName,
   118  		descriptor: ErrValueUnsupported,
   119  	}
   120  }
   121  
   122  // IsArgumentUnspecified checks if an error describes about unspecifity of an argument.
   123  //
   124  //TODO: ArgSet
   125  func IsArgumentUnspecified(err error, argName string) bool {
   126  	if err == nil {
   127  		return false
   128  	}
   129  	argErr, ok := err.(ArgumentError)
   130  	if !ok {
   131  		return false
   132  	}
   133  	if argErr.ArgumentName() != argName {
   134  		return false
   135  	}
   136  	if desc := UnwrapDescriptor(err); desc != nil {
   137  		return desc == ErrValueUnspecified
   138  	}
   139  	return false
   140  }
   141  
   142  func IsArgUnspecified(err error, argName string) bool {
   143  	if err == nil {
   144  		return false
   145  	}
   146  	argErr, ok := err.(ArgumentError)
   147  	if !ok {
   148  		return false
   149  	}
   150  	if argErr.ArgumentName() != argName {
   151  		return false
   152  	}
   153  	if desc := UnwrapDescriptor(err); desc != nil {
   154  		return desc == ErrValueUnspecified
   155  	}
   156  	return false
   157  }
   158  
   159  type argumentError struct {
   160  	argName    string
   161  	descriptor ErrorDescriptor
   162  	hintText   string
   163  	fields     []NamedError
   164  	wrapped    error
   165  }
   166  
   167  var (
   168  	_ error                = &argumentError{}
   169  	_ Unwrappable          = &argumentError{}
   170  	_ CallError            = &argumentError{}
   171  	_ ArgumentError        = &argumentError{}
   172  	_ ArgumentErrorBuilder = &argumentError{}
   173  	_ hasDescriptor        = &argumentError{}
   174  	_ hasFieldErrors       = &argumentError{}
   175  )
   176  
   177  func (e *argumentError) ArgumentName() string {
   178  	return e.argName
   179  }
   180  
   181  func (e *argumentError) CallError() CallError { return e }
   182  
   183  func (e *argumentError) Error() string {
   184  	suffix := namedSetToString(e.fields)
   185  	if suffix != "" {
   186  		suffix = ": " + suffix
   187  	}
   188  	if e.hintText != "" {
   189  		suffix = suffix + ". " + e.hintText
   190  	}
   191  	var descStr string
   192  	if e.descriptor != nil {
   193  		descStr = e.descriptor.Error()
   194  	}
   195  	causeStr := errorString(e.wrapped)
   196  	if causeStr == "" {
   197  		causeStr = descStr
   198  	} else if descStr != "" {
   199  		causeStr = descStr + ": " + causeStr
   200  	}
   201  
   202  	if e.argName != "" {
   203  		if causeStr != "" {
   204  			return "arg " + e.argName + ": " + causeStr + suffix
   205  		}
   206  		return "arg " + e.argName + suffix
   207  	}
   208  	if causeStr != "" {
   209  		return "arg " + causeStr + suffix
   210  	}
   211  	if suffix != "" {
   212  		return "arg" + suffix
   213  	}
   214  	return "arg error"
   215  }
   216  
   217  func (e argumentError) Descriptor() ErrorDescriptor { return e.descriptor }
   218  func (e argumentError) Unwrap() error               { return e.wrapped }
   219  func (e argumentError) FieldErrors() []NamedError   { return copyNamedSet(e.fields) }
   220  
   221  func (e argumentError) Desc(desc ErrorDescriptor) ArgumentErrorBuilder {
   222  	e.descriptor = desc
   223  	return &e
   224  }
   225  
   226  func (e argumentError) DescMsg(descMsg string) ArgumentErrorBuilder {
   227  	e.descriptor = constantErrorDescriptor(descMsg)
   228  	return &e
   229  }
   230  
   231  func (e argumentError) Hint(hintText string) ArgumentErrorBuilder {
   232  	e.hintText = hintText
   233  	return &e
   234  }
   235  
   236  func (e argumentError) Fieldset(fields ...NamedError) ArgumentErrorBuilder {
   237  	e.fields = copyNamedSet(fields)
   238  	return &e
   239  }
   240  
   241  func (e argumentError) Rewrap(err error) ArgumentErrorBuilder {
   242  	if err != nil {
   243  		if descErr, _ := err.(ErrorDescriptor); descErr != nil {
   244  			e.descriptor = descErr
   245  			e.wrapped = nil
   246  			e.fields = nil
   247  		} else {
   248  			e.descriptor = UnwrapDescriptor(err)
   249  			e.wrapped = Unwrap(err)
   250  			e.fields = UnwrapFieldErrors(err)
   251  		}
   252  	}
   253  	return &e
   254  }
   255  
   256  func (e argumentError) Wrap(detailingError error) ArgumentErrorBuilder {
   257  	e.wrapped = detailingError
   258  	return &e
   259  }
   260  
   261  type ArgumentErrorChecker struct {
   262  	errToCheck ArgumentError
   263  	truthState bool
   264  }
   265  
   266  func ArgumentErrorCheck(err error) ArgumentErrorChecker {
   267  	argErr, ok := err.(ArgumentError)
   268  	return ArgumentErrorChecker{
   269  		errToCheck: argErr,
   270  		truthState: ok,
   271  	}
   272  }
   273  
   274  func (checker ArgumentErrorChecker) IsTrue() bool { return checker.truthState }
   275  
   276  func (checker ArgumentErrorChecker) HasName(argName string) ArgumentErrorChecker {
   277  	if err := checker.errToCheck; err == nil || err.ArgumentName() != argName {
   278  		checker.truthState = false
   279  	}
   280  	return checker
   281  }
   282  
   283  func (checker ArgumentErrorChecker) HasDesc(desc ErrorDescriptor) ArgumentErrorChecker {
   284  	if !HasDescriptor(checker.errToCheck, desc) {
   285  		checker.truthState = false
   286  	}
   287  	return checker
   288  }
   289  
   290  func (checker ArgumentErrorChecker) HasWrapped(err error) ArgumentErrorChecker {
   291  	if !Is(err, Unwrap(checker.errToCheck)) {
   292  		checker.truthState = false
   293  	}
   294  	return checker
   295  }