1 package jreader 2 3 // Reader is a high-level API for reading JSON data sequentially. 4 // 5 // It is designed to make writing custom unmarshallers for application types as convenient as 6 // possible. The general usage pattern is as follows: 7 // 8 // - Values are parsed in the order that they appear. 9 // 10 // - In general, the caller should know what data type is expected. Since it is common for 11 // properties to be nullable, the methods for reading scalar types have variants for allowing 12 // a null instead of the specified type. If the type is completely unknown, use Any. 13 // 14 // - For reading array or object structures, the Array and Object methods return a struct that 15 // keeps track of additional reader state while that structure is being parsed. 16 // 17 // - If any method encounters an error (due to either malformed JSON, or well-formed JSON that 18 // did not match the caller's data type expectations), the Reader permanently enters a failed 19 // state and remembers that error; all subsequent method calls will return the same error and no 20 // more parsing will happen. This means that the caller does not necessarily have to check the 21 // error return value of any individual method, although it can. 22 type Reader struct { 23 tr tokenReader 24 awaitingReadValue bool // used by ArrayState & ObjectState 25 err error 26 } 27 28 // Error returns the first error that the Reader encountered, if the Reader is in a failed state, 29 // or nil if it is still in a good state. 30 func (r *Reader) Error() error { 31 return r.err 32 } 33 34 // RequireEOF returns nil if all of the input has been consumed (not counting whitespace), or an 35 // error if not. 36 func (r *Reader) RequireEOF() error { 37 if !r.tr.EOF() { 38 return SyntaxError{Message: errMsgDataAfterEnd, Offset: r.tr.LastPos()} 39 } 40 return nil 41 } 42 43 // AddError sets the Reader's error value and puts it into a failed state. If the parameter is nil 44 // or the Reader was already in a failed state, it does nothing. 45 func (r *Reader) AddError(err error) { 46 if r.err == nil { 47 r.err = err 48 } 49 } 50 51 // ReplaceError sets the Reader's error value and puts it into a failed state, replacing any 52 // previously reported error. If the parameter is nil, it does nothing (a failed state cannot be 53 // changed to a non-failed state). 54 func (r *Reader) ReplaceError(err error) { 55 if err != nil { 56 r.err = err 57 } 58 } 59 60 // Null attempts to read a null value, returning an error if the next token is not a null. 61 func (r *Reader) Null() error { 62 r.awaitingReadValue = false 63 if r.err != nil { 64 return r.err 65 } 66 isNull, err := r.tr.Null() 67 if isNull || err != nil { 68 return err 69 } 70 return r.typeErrorForCurrentToken(NullValue, false) 71 } 72 73 // Bool attempts to read a boolean value. 74 // 75 // If there is a parsing error, or the next value is not a boolean, the return value is false 76 // and the Reader enters a failed state, which you can detect with Error(). 77 func (r *Reader) Bool() bool { 78 r.awaitingReadValue = false 79 if r.err != nil { 80 return false 81 } 82 val, err := r.tr.Bool() 83 if err != nil { 84 r.err = err 85 return false 86 } 87 return val 88 } 89 90 // BoolOrNull attempts to read either a boolean value or a null. In the case of a boolean, the return 91 // values are (value, true); for a null, they are (false, false). 92 // 93 // If there is a parsing error, or the next value is neither a boolean nor a null, the return values 94 // are (false, false) and the Reader enters a failed state, which you can detect with Error(). 95 func (r *Reader) BoolOrNull() (value bool, nonNull bool) { 96 r.awaitingReadValue = false 97 if r.err != nil { 98 return false, false 99 } 100 isNull, err := r.tr.Null() 101 if isNull || err != nil { 102 r.err = err 103 return false, false 104 } 105 val, err := r.tr.Bool() 106 if err != nil { 107 r.err = typeErrorForNullableValue(err) 108 return false, false 109 } 110 return val, true 111 } 112 113 // Int attempts to read a numeric value and returns it as an int. 114 // 115 // If there is a parsing error, or the next value is not a number, the return value is zero and 116 // the Reader enters a failed state, which you can detect with Error(). Non-numeric types are never 117 // converted to numbers. 118 func (r *Reader) Int() int { 119 return int(r.Float64()) 120 } 121 122 // IntOrNull attempts to read either an integer numeric value or a null. In the case of a number, the 123 // return values are (value, true); for a null, they are (0, false). 124 // 125 // If there is a parsing error, or the next value is neither a number nor a null, the return values 126 // are (0, false) and the Reader enters a failed state, which you can detect with Error(). 127 func (r *Reader) IntOrNull() (int, bool) { 128 val, nonNull := r.Float64OrNull() 129 return int(val), nonNull 130 } 131 132 // Float64 attempts to read a numeric value and returns it as a float64. 133 // 134 // If there is a parsing error, or the next value is not a number, the return value is zero and 135 // the Reader enters a failed state, which you can detect with Error(). Non-numeric types are never 136 // converted to numbers. 137 func (r *Reader) Float64() float64 { 138 r.awaitingReadValue = false 139 if r.err != nil { 140 return 0 141 } 142 val, err := r.tr.Number() 143 if err != nil { 144 r.err = err 145 return 0 146 } 147 return val 148 } 149 150 // Float64OrNull attempts to read either a numeric value or a null. In the case of a number, the 151 // return values are (value, true); for a null, they are (0, false). 152 // 153 // If there is a parsing error, or the next value is neither a number nor a null, the return values 154 // are (0, false) and the Reader enters a failed state, which you can detect with Error(). 155 func (r *Reader) Float64OrNull() (float64, bool) { 156 r.awaitingReadValue = false 157 if r.err != nil { 158 return 0, false 159 } 160 isNull, err := r.tr.Null() 161 if isNull || err != nil { 162 r.err = err 163 return 0, false 164 } 165 val, err := r.tr.Number() 166 if err != nil { 167 r.err = typeErrorForNullableValue(err) 168 return 0, false 169 } 170 return val, true 171 } 172 173 // String attempts to read a string value. 174 // 175 // If there is a parsing error, or the next value is not a string, the return value is "" and 176 // the Reader enters a failed state, which you can detect with Error(). Types other than string 177 // are never converted to strings. 178 func (r *Reader) String() string { 179 r.awaitingReadValue = false 180 if r.err != nil { 181 return "" 182 } 183 val, err := r.tr.String() 184 if err != nil { 185 r.err = err 186 return "" 187 } 188 return val 189 } 190 191 // StringOrNull attempts to read either a string value or a null. In the case of a string, the 192 // return values are (value, true); for a null, they are ("", false). 193 // 194 // If there is a parsing error, or the next value is neither a string nor a null, the return values 195 // are ("", false) and the Reader enters a failed state, which you can detect with Error(). 196 func (r *Reader) StringOrNull() (string, bool) { 197 r.awaitingReadValue = false 198 if r.err != nil { 199 return "", false 200 } 201 isNull, err := r.tr.Null() 202 if isNull || err != nil { 203 r.err = err 204 return "", false 205 } 206 val, err := r.tr.String() 207 if err != nil { 208 r.err = typeErrorForNullableValue(err) 209 return "", false 210 } 211 return val, true 212 } 213 214 // Array attempts to begin reading a JSON array value. If successful, the return value will be an 215 // ArrayState containing the necessary state for iterating through the array elements. 216 // 217 // The ArrayState is used only for the iteration state; to read the value of each array element, you 218 // will still use the Reader's methods. 219 // 220 // If there is a parsing error, or the next value is not an array, the returned ArrayState is a stub 221 // whose Next() method always returns false, and the Reader enters a failed state, which you can 222 // detect with Error(). 223 // 224 // See ArrayState for example code. 225 func (r *Reader) Array() ArrayState { 226 return r.tryArray(false) 227 } 228 229 // ArrayOrNull attempts to either begin reading an JSON array value, or read a null. In the case of an 230 // array, the return value will be an ArrayState containing the necessary state for iterating through 231 // the array elements; the ArrayState's IsDefined() method will return true. In the case of a null, the 232 // returned ArrayState will be a stub whose Next() and IsDefined() methods always returns false. 233 // 234 // The ArrayState is used only for the iteration state; to read the value of each array element, you 235 // will still use the Reader's methods. 236 // 237 // If there is a parsing error, or the next value is neither an array nor a null, the return value is 238 // the same as for a null but the Reader enters a failed state, which you can detect with Error(). 239 // 240 // See ArrayState for example code. 241 func (r *Reader) ArrayOrNull() ArrayState { 242 return r.tryArray(true) 243 } 244 245 func (r *Reader) tryArray(allowNull bool) ArrayState { 246 r.awaitingReadValue = false 247 if r.err != nil { 248 return ArrayState{} 249 } 250 if allowNull { 251 isNull, err := r.tr.Null() 252 if err != nil { 253 r.err = err 254 return ArrayState{} 255 } 256 if isNull { 257 return ArrayState{} 258 } 259 } 260 gotDelim, err := r.tr.Delimiter('[') 261 if err != nil { 262 r.err = err 263 return ArrayState{} 264 } 265 if gotDelim { 266 return ArrayState{r: r} 267 } 268 r.err = r.typeErrorForCurrentToken(ArrayValue, allowNull) 269 return ArrayState{} 270 } 271 272 // Object attempts to begin reading a JSON object value. If successful, the return value will be an 273 // ObjectState containing the necessary state for iterating through the object properties. 274 // 275 // The ObjectState is used only for the iteration state; to read the value of each property, you 276 // will still use the Reader's methods. 277 // 278 // If there is a parsing error, or the next value is not an object, the returned ObjectState is a stub 279 // whose Next() method always returns false, and the Reader enters a failed state, which you can 280 // detect with Error(). 281 // 282 // See ObjectState for example code. 283 func (r *Reader) Object() ObjectState { 284 return r.tryObject(false) 285 } 286 287 // ObjectOrNull attempts to either begin reading an JSON object value, or read a null. In the case of an 288 // object, the return value will be an ObjectState containing the necessary state for iterating through 289 // the object properties; the ObjectState's IsDefined() method will return true. In the case of a null, 290 // the returned ObjectState will be a stub whose Next() and IsDefined() methods always returns false. 291 // 292 // The ObjectState is used only for the iteration state; to read the value of each property, you 293 // will still use the Reader's methods. 294 // 295 // If there is a parsing error, or the next value is neither an object nor a null, the return value is 296 // the same as for a null but the Reader enters a failed state, which you can detect with Error(). 297 // 298 // See ObjectState for example code. 299 func (r *Reader) ObjectOrNull() ObjectState { 300 return r.tryObject(true) 301 } 302 303 func (r *Reader) tryObject(allowNull bool) ObjectState { 304 r.awaitingReadValue = false 305 if r.err != nil { 306 return ObjectState{} 307 } 308 if allowNull { 309 isNull, err := r.tr.Null() 310 if err != nil || isNull { 311 r.err = err 312 return ObjectState{} 313 } 314 } 315 gotDelim, err := r.tr.Delimiter('{') 316 if err != nil { 317 r.err = err 318 return ObjectState{} 319 } 320 if gotDelim { 321 return ObjectState{r: r} 322 } 323 r.err = r.typeErrorForCurrentToken(ObjectValue, allowNull) 324 return ObjectState{} 325 } 326 327 // Any reads a single value of any type, if it is a scalar value or a null, or prepares to read 328 // the value if it is an array or object. 329 // 330 // The returned AnyValue's Kind field indicates the value type. If it is BoolValue, NumberValue, 331 // or StringValue, check the corresponding Bool, Number, or String property. If it is ArrayValue 332 // or ObjectValue, the AnyValue's Array or Object field has been initialized with an ArrayState or 333 // ObjectState just as if you had called the Reader's Array or Object method. 334 // 335 // If there is a parsing error, the return value is the same as for a null and the Reader enters 336 // a failed state, which you can detect with Error(). 337 func (r *Reader) Any() AnyValue { 338 r.awaitingReadValue = false 339 if r.err != nil { 340 return AnyValue{} 341 } 342 v, err := r.tr.Any() 343 if err != nil { 344 r.err = err 345 return AnyValue{} 346 } 347 switch v.Kind { 348 case BoolValue: 349 return AnyValue{Kind: v.Kind, Bool: v.Bool} 350 case NumberValue: 351 return AnyValue{Kind: v.Kind, Number: v.Number} 352 case StringValue: 353 return AnyValue{Kind: v.Kind, String: v.String} 354 case ArrayValue: 355 return AnyValue{Kind: v.Kind, Array: ArrayState{r: r}} 356 case ObjectValue: 357 return AnyValue{Kind: v.Kind, Object: ObjectState{r: r}} 358 default: 359 return AnyValue{Kind: NullValue} 360 } 361 } 362 363 // SkipValue consumes and discards the next JSON value of any type. For an array or object value, it 364 // recurses to also consume and discard all array elements or object properties. 365 func (r *Reader) SkipValue() error { 366 r.awaitingReadValue = false 367 if r.err != nil { 368 return r.err 369 } 370 v := r.Any() 371 if v.Kind == ArrayValue { 372 for v.Array.Next() { 373 } 374 } else if v.Kind == ObjectValue { 375 for v.Object.Next() { 376 } 377 } 378 return r.err 379 } 380 381 func typeErrorForNullableValue(err error) error { 382 if err != nil { 383 switch e := err.(type) { //nolint:gocritic 384 case TypeError: 385 e.Nullable = true 386 return e 387 } 388 } 389 return err 390 } 391 392 func (r *Reader) typeErrorForCurrentToken(expected ValueKind, nullable bool) error { 393 v, err := r.tr.Any() 394 if err != nil { 395 return err 396 } 397 return TypeError{Expected: expected, Actual: v.Kind, Offset: r.tr.LastPos(), Nullable: nullable} 398 } 399