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 }