k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/internal/third_party/go-json-experiment/json/token.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package json 6 7 import ( 8 "math" 9 "strconv" 10 ) 11 12 // NOTE: Token is analogous to v1 json.Token. 13 14 const ( 15 maxInt64 = math.MaxInt64 16 minInt64 = math.MinInt64 17 maxUint64 = math.MaxUint64 18 minUint64 = 0 // for consistency and readability purposes 19 20 invalidTokenPanic = "invalid json.Token; it has been voided by a subsequent json.Decoder call" 21 ) 22 23 // Token represents a lexical JSON token, which may be one of the following: 24 // - a JSON literal (i.e., null, true, or false) 25 // - a JSON string (e.g., "hello, world!") 26 // - a JSON number (e.g., 123.456) 27 // - a start or end delimiter for a JSON object (i.e., { or } ) 28 // - a start or end delimiter for a JSON array (i.e., [ or ] ) 29 // 30 // A Token cannot represent entire array or object values, while a RawValue can. 31 // There is no Token to represent commas and colons since 32 // these structural tokens can be inferred from the surrounding context. 33 type Token struct { 34 nonComparable 35 36 // Tokens can exist in either a "raw" or an "exact" form. 37 // Tokens produced by the Decoder are in the "raw" form. 38 // Tokens returned by constructors are usually in the "exact" form. 39 // The Encoder accepts Tokens in either the "raw" or "exact" form. 40 // 41 // The following chart shows the possible values for each Token type: 42 // ╔═════════════════╦════════════╤════════════╤════════════╗ 43 // ║ Token type ║ raw field │ str field │ num field ║ 44 // ╠═════════════════╬════════════╪════════════╪════════════╣ 45 // ║ null (raw) ║ "null" │ "" │ 0 ║ 46 // ║ false (raw) ║ "false" │ "" │ 0 ║ 47 // ║ true (raw) ║ "true" │ "" │ 0 ║ 48 // ║ string (raw) ║ non-empty │ "" │ offset ║ 49 // ║ string (string) ║ nil │ non-empty │ 0 ║ 50 // ║ number (raw) ║ non-empty │ "" │ offset ║ 51 // ║ number (float) ║ nil │ "f" │ non-zero ║ 52 // ║ number (int64) ║ nil │ "i" │ non-zero ║ 53 // ║ number (uint64) ║ nil │ "u" │ non-zero ║ 54 // ║ object (delim) ║ "{" or "}" │ "" │ 0 ║ 55 // ║ array (delim) ║ "[" or "]" │ "" │ 0 ║ 56 // ╚═════════════════╩════════════╧════════════╧════════════╝ 57 // 58 // Notes: 59 // - For tokens stored in "raw" form, the num field contains the 60 // absolute offset determined by raw.previousOffsetStart(). 61 // The buffer itself is stored in raw.previousBuffer(). 62 // - JSON literals and structural characters are always in the "raw" form. 63 // - JSON strings and numbers can be in either "raw" or "exact" forms. 64 // - The exact zero value of JSON strings and numbers in the "exact" forms 65 // have ambiguous representation. Thus, they are always represented 66 // in the "raw" form. 67 68 // raw contains a reference to the raw decode buffer. 69 // If non-nil, then its value takes precedence over str and num. 70 // It is only valid if num == raw.previousOffsetStart(). 71 raw *decodeBuffer 72 73 // str is the unescaped JSON string if num is zero. 74 // Otherwise, it is "f", "i", or "u" if num should be interpreted 75 // as a float64, int64, or uint64, respectively. 76 str string 77 78 // num is a float64, int64, or uint64 stored as a uint64 value. 79 // It is non-zero for any JSON number in the "exact" form. 80 num uint64 81 } 82 83 // TODO: Does representing 1-byte delimiters as *decodeBuffer cause performance issues? 84 85 var ( 86 Null Token = rawToken("null") 87 False Token = rawToken("false") 88 True Token = rawToken("true") 89 90 ObjectStart Token = rawToken("{") 91 ObjectEnd Token = rawToken("}") 92 ArrayStart Token = rawToken("[") 93 ArrayEnd Token = rawToken("]") 94 95 zeroString Token = rawToken(`""`) 96 zeroNumber Token = rawToken(`0`) 97 98 nanString Token = String("NaN") 99 pinfString Token = String("Infinity") 100 ninfString Token = String("-Infinity") 101 ) 102 103 func rawToken(s string) Token { 104 return Token{raw: &decodeBuffer{buf: []byte(s), prevStart: 0, prevEnd: len(s)}} 105 } 106 107 // Bool constructs a Token representing a JSON boolean. 108 func Bool(b bool) Token { 109 if b { 110 return True 111 } 112 return False 113 } 114 115 // String constructs a Token representing a JSON string. 116 // The provided string should contain valid UTF-8, otherwise invalid characters 117 // may be mangled as the Unicode replacement character. 118 func String(s string) Token { 119 if len(s) == 0 { 120 return zeroString 121 } 122 return Token{str: s} 123 } 124 125 // Float constructs a Token representing a JSON number. 126 // The values NaN, +Inf, and -Inf will be represented 127 // as a JSON string with the values "NaN", "Infinity", and "-Infinity". 128 func Float(n float64) Token { 129 switch { 130 case math.Float64bits(n) == 0: 131 return zeroNumber 132 case math.IsNaN(n): 133 return nanString 134 case math.IsInf(n, +1): 135 return pinfString 136 case math.IsInf(n, -1): 137 return ninfString 138 } 139 return Token{str: "f", num: math.Float64bits(n)} 140 } 141 142 // Int constructs a Token representing a JSON number from an int64. 143 func Int(n int64) Token { 144 if n == 0 { 145 return zeroNumber 146 } 147 return Token{str: "i", num: uint64(n)} 148 } 149 150 // Uint constructs a Token representing a JSON number from a uint64. 151 func Uint(n uint64) Token { 152 if n == 0 { 153 return zeroNumber 154 } 155 return Token{str: "u", num: uint64(n)} 156 } 157 158 // Clone makes a copy of the Token such that its value remains valid 159 // even after a subsequent Decoder.Read call. 160 func (t Token) Clone() Token { 161 // TODO: Allow caller to avoid any allocations? 162 if raw := t.raw; raw != nil { 163 // Avoid copying globals. 164 if t.raw.prevStart == 0 { 165 switch t.raw { 166 case Null.raw: 167 return Null 168 case False.raw: 169 return False 170 case True.raw: 171 return True 172 case ObjectStart.raw: 173 return ObjectStart 174 case ObjectEnd.raw: 175 return ObjectEnd 176 case ArrayStart.raw: 177 return ArrayStart 178 case ArrayEnd.raw: 179 return ArrayEnd 180 } 181 } 182 183 if uint64(raw.previousOffsetStart()) != t.num { 184 panic(invalidTokenPanic) 185 } 186 // TODO(https://go.dev/issue/45038): Use bytes.Clone. 187 buf := append([]byte(nil), raw.previousBuffer()...) 188 return Token{raw: &decodeBuffer{buf: buf, prevStart: 0, prevEnd: len(buf)}} 189 } 190 return t 191 } 192 193 // Bool returns the value for a JSON boolean. 194 // It panics if the token kind is not a JSON boolean. 195 func (t Token) Bool() bool { 196 switch t.raw { 197 case True.raw: 198 return true 199 case False.raw: 200 return false 201 default: 202 panic("invalid JSON token kind: " + t.Kind().String()) 203 } 204 } 205 206 // appendString appends a JSON string to dst and returns it. 207 // It panics if t is not a JSON string. 208 func (t Token) appendString(dst []byte, validateUTF8, preserveRaw bool, escapeRune func(rune) bool) ([]byte, error) { 209 if raw := t.raw; raw != nil { 210 // Handle raw string value. 211 buf := raw.previousBuffer() 212 if Kind(buf[0]) == '"' { 213 if escapeRune == nil && consumeSimpleString(buf) == len(buf) { 214 return append(dst, buf...), nil 215 } 216 dst, _, err := reformatString(dst, buf, validateUTF8, preserveRaw, escapeRune) 217 return dst, err 218 } 219 } else if len(t.str) != 0 && t.num == 0 { 220 // Handle exact string value. 221 return appendString(dst, t.str, validateUTF8, escapeRune) 222 } 223 224 panic("invalid JSON token kind: " + t.Kind().String()) 225 } 226 227 // String returns the unescaped string value for a JSON string. 228 // For other JSON kinds, this returns the raw JSON representation. 229 func (t Token) String() string { 230 // This is inlinable to take advantage of "function outlining". 231 // This avoids an allocation for the string(b) conversion 232 // if the caller does not use the string in an escaping manner. 233 // See https://blog.filippo.io/efficient-go-apis-with-the-inliner/ 234 s, b := t.string() 235 if len(b) > 0 { 236 return string(b) 237 } 238 return s 239 } 240 func (t Token) string() (string, []byte) { 241 if raw := t.raw; raw != nil { 242 if uint64(raw.previousOffsetStart()) != t.num { 243 panic(invalidTokenPanic) 244 } 245 buf := raw.previousBuffer() 246 if buf[0] == '"' { 247 // TODO: Preserve valueFlags in Token? 248 isVerbatim := consumeSimpleString(buf) == len(buf) 249 return "", unescapeStringMayCopy(buf, isVerbatim) 250 } 251 // Handle tokens that are not JSON strings for fmt.Stringer. 252 return "", buf 253 } 254 if len(t.str) != 0 && t.num == 0 { 255 return t.str, nil 256 } 257 // Handle tokens that are not JSON strings for fmt.Stringer. 258 if t.num > 0 { 259 switch t.str[0] { 260 case 'f': 261 return string(appendNumber(nil, math.Float64frombits(t.num), 64)), nil 262 case 'i': 263 return strconv.FormatInt(int64(t.num), 10), nil 264 case 'u': 265 return strconv.FormatUint(uint64(t.num), 10), nil 266 } 267 } 268 return "<invalid json.Token>", nil 269 } 270 271 // appendNumber appends a JSON number to dst and returns it. 272 // It panics if t is not a JSON number. 273 func (t Token) appendNumber(dst []byte, canonicalize bool) ([]byte, error) { 274 if raw := t.raw; raw != nil { 275 // Handle raw number value. 276 buf := raw.previousBuffer() 277 if Kind(buf[0]).normalize() == '0' { 278 if !canonicalize { 279 return append(dst, buf...), nil 280 } 281 dst, _, err := reformatNumber(dst, buf, canonicalize) 282 return dst, err 283 } 284 } else if t.num != 0 { 285 // Handle exact number value. 286 switch t.str[0] { 287 case 'f': 288 return appendNumber(dst, math.Float64frombits(t.num), 64), nil 289 case 'i': 290 return strconv.AppendInt(dst, int64(t.num), 10), nil 291 case 'u': 292 return strconv.AppendUint(dst, uint64(t.num), 10), nil 293 } 294 } 295 296 panic("invalid JSON token kind: " + t.Kind().String()) 297 } 298 299 // Float returns the floating-point value for a JSON number. 300 // It returns a NaN, +Inf, or -Inf value for any JSON string 301 // with the values "NaN", "Infinity", or "-Infinity". 302 // It panics for all other cases. 303 func (t Token) Float() float64 { 304 if raw := t.raw; raw != nil { 305 // Handle raw number value. 306 if uint64(raw.previousOffsetStart()) != t.num { 307 panic(invalidTokenPanic) 308 } 309 buf := raw.previousBuffer() 310 if Kind(buf[0]).normalize() == '0' { 311 fv, _ := parseFloat(buf, 64) 312 return fv 313 } 314 } else if t.num != 0 { 315 // Handle exact number value. 316 switch t.str[0] { 317 case 'f': 318 return math.Float64frombits(t.num) 319 case 'i': 320 return float64(int64(t.num)) 321 case 'u': 322 return float64(uint64(t.num)) 323 } 324 } 325 326 // Handle string values with "NaN", "Infinity", or "-Infinity". 327 if t.Kind() == '"' { 328 switch t.String() { 329 case "NaN": 330 return math.NaN() 331 case "Infinity": 332 return math.Inf(+1) 333 case "-Infinity": 334 return math.Inf(-1) 335 } 336 } 337 338 panic("invalid JSON token kind: " + t.Kind().String()) 339 } 340 341 // Int returns the signed integer value for a JSON number. 342 // The fractional component of any number is ignored (truncation toward zero). 343 // Any number beyond the representation of an int64 will be saturated 344 // to the closest representable value. 345 // It panics if the token kind is not a JSON number. 346 func (t Token) Int() int64 { 347 if raw := t.raw; raw != nil { 348 // Handle raw integer value. 349 if uint64(raw.previousOffsetStart()) != t.num { 350 panic(invalidTokenPanic) 351 } 352 neg := false 353 buf := raw.previousBuffer() 354 if len(buf) > 0 && buf[0] == '-' { 355 neg, buf = true, buf[1:] 356 } 357 if numAbs, ok := parseDecUint(buf); ok { 358 if neg { 359 if numAbs > -minInt64 { 360 return minInt64 361 } 362 return -1 * int64(numAbs) 363 } else { 364 if numAbs > +maxInt64 { 365 return maxInt64 366 } 367 return +1 * int64(numAbs) 368 } 369 } 370 } else if t.num != 0 { 371 // Handle exact integer value. 372 switch t.str[0] { 373 case 'i': 374 return int64(t.num) 375 case 'u': 376 if t.num > maxInt64 { 377 return maxInt64 378 } 379 return int64(t.num) 380 } 381 } 382 383 // Handle JSON number that is a floating-point value. 384 if t.Kind() == '0' { 385 switch fv := t.Float(); { 386 case fv >= maxInt64: 387 return maxInt64 388 case fv <= minInt64: 389 return minInt64 390 default: 391 return int64(fv) // truncation toward zero 392 } 393 } 394 395 panic("invalid JSON token kind: " + t.Kind().String()) 396 } 397 398 // Uint returns the unsigned integer value for a JSON number. 399 // The fractional component of any number is ignored (truncation toward zero). 400 // Any number beyond the representation of an uint64 will be saturated 401 // to the closest representable value. 402 // It panics if the token kind is not a JSON number. 403 func (t Token) Uint() uint64 { 404 // NOTE: This accessor returns 0 for any negative JSON number, 405 // which might be surprising, but is at least consistent with the behavior 406 // of saturating out-of-bounds numbers to the closest representable number. 407 408 if raw := t.raw; raw != nil { 409 // Handle raw integer value. 410 if uint64(raw.previousOffsetStart()) != t.num { 411 panic(invalidTokenPanic) 412 } 413 neg := false 414 buf := raw.previousBuffer() 415 if len(buf) > 0 && buf[0] == '-' { 416 neg, buf = true, buf[1:] 417 } 418 if num, ok := parseDecUint(buf); ok { 419 if neg { 420 return minUint64 421 } 422 return num 423 } 424 } else if t.num != 0 { 425 // Handle exact integer value. 426 switch t.str[0] { 427 case 'u': 428 return t.num 429 case 'i': 430 if int64(t.num) < minUint64 { 431 return minUint64 432 } 433 return uint64(int64(t.num)) 434 } 435 } 436 437 // Handle JSON number that is a floating-point value. 438 if t.Kind() == '0' { 439 switch fv := t.Float(); { 440 case fv >= maxUint64: 441 return maxUint64 442 case fv <= minUint64: 443 return minUint64 444 default: 445 return uint64(fv) // truncation toward zero 446 } 447 } 448 449 panic("invalid JSON token kind: " + t.Kind().String()) 450 } 451 452 // Kind returns the token kind. 453 func (t Token) Kind() Kind { 454 switch { 455 case t.raw != nil: 456 raw := t.raw 457 if uint64(raw.previousOffsetStart()) != t.num { 458 panic(invalidTokenPanic) 459 } 460 return Kind(t.raw.buf[raw.prevStart]).normalize() 461 case t.num != 0: 462 return '0' 463 case len(t.str) != 0: 464 return '"' 465 default: 466 return invalidKind 467 } 468 } 469 470 // Kind represents each possible JSON token kind with a single byte, 471 // which is conveniently the first byte of that kind's grammar 472 // with the restriction that numbers always be represented with '0': 473 // 474 // - 'n': null 475 // - 'f': false 476 // - 't': true 477 // - '"': string 478 // - '0': number 479 // - '{': object start 480 // - '}': object end 481 // - '[': array start 482 // - ']': array end 483 // 484 // An invalid kind is usually represented using 0, 485 // but may be non-zero due to invalid JSON data. 486 type Kind byte 487 488 const invalidKind Kind = 0 489 490 // String prints the kind in a humanly readable fashion. 491 func (k Kind) String() string { 492 switch k { 493 case 'n': 494 return "null" 495 case 'f': 496 return "false" 497 case 't': 498 return "true" 499 case '"': 500 return "string" 501 case '0': 502 return "number" 503 case '{': 504 return "{" 505 case '}': 506 return "}" 507 case '[': 508 return "[" 509 case ']': 510 return "]" 511 default: 512 return "<invalid json.Kind: " + quoteRune([]byte{byte(k)}) + ">" 513 } 514 } 515 516 // normalize coalesces all possible starting characters of a number as just '0'. 517 func (k Kind) normalize() Kind { 518 if k == '-' || ('0' <= k && k <= '9') { 519 return '0' 520 } 521 return k 522 }