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 }