github.com/neilotoole/jsoncolor@v0.7.2-0.20231115150201-1637fae69be1/encode.go (about) 1 package jsoncolor 2 3 import ( 4 "bytes" 5 "encoding" 6 "encoding/base64" 7 "errors" 8 "math" 9 "reflect" 10 "sort" 11 "strconv" 12 "sync" 13 "time" 14 "unicode/utf8" 15 "unsafe" 16 ) 17 18 const hex = "0123456789abcdef" 19 20 func (e encoder) encodeNull(b []byte, _ unsafe.Pointer) ([]byte, error) { 21 return e.clrs.appendNull(b), nil 22 } 23 24 func (e encoder) encodeBool(b []byte, p unsafe.Pointer) ([]byte, error) { 25 return e.clrs.appendBool(b, *(*bool)(p)), nil 26 } 27 28 func (e encoder) encodeInt(b []byte, p unsafe.Pointer) ([]byte, error) { 29 return e.clrs.appendInt64(b, int64(*(*int)(p))), nil 30 } 31 32 func (e encoder) encodeInt8(b []byte, p unsafe.Pointer) ([]byte, error) { 33 return e.clrs.appendInt64(b, int64(*(*int8)(p))), nil 34 } 35 36 func (e encoder) encodeInt16(b []byte, p unsafe.Pointer) ([]byte, error) { 37 return e.clrs.appendInt64(b, int64(*(*int16)(p))), nil 38 } 39 40 func (e encoder) encodeInt32(b []byte, p unsafe.Pointer) ([]byte, error) { 41 return e.clrs.appendInt64(b, int64(*(*int32)(p))), nil 42 } 43 44 func (e encoder) encodeInt64(b []byte, p unsafe.Pointer) ([]byte, error) { 45 return e.clrs.appendInt64(b, *(*int64)(p)), nil 46 } 47 48 func (e encoder) encodeUint(b []byte, p unsafe.Pointer) ([]byte, error) { 49 return e.clrs.appendUint64(b, uint64(*(*uint)(p))), nil 50 } 51 52 func (e encoder) encodeUintptr(b []byte, p unsafe.Pointer) ([]byte, error) { 53 return e.clrs.appendUint64(b, uint64(*(*uintptr)(p))), nil 54 } 55 56 func (e encoder) encodeUint8(b []byte, p unsafe.Pointer) ([]byte, error) { 57 return e.clrs.appendUint64(b, uint64(*(*uint8)(p))), nil 58 } 59 60 func (e encoder) encodeUint16(b []byte, p unsafe.Pointer) ([]byte, error) { 61 return e.clrs.appendUint64(b, uint64(*(*uint16)(p))), nil 62 } 63 64 func (e encoder) encodeUint32(b []byte, p unsafe.Pointer) ([]byte, error) { 65 return e.clrs.appendUint64(b, uint64(*(*uint32)(p))), nil 66 } 67 68 func (e encoder) encodeUint64(b []byte, p unsafe.Pointer) ([]byte, error) { 69 return e.clrs.appendUint64(b, *(*uint64)(p)), nil 70 } 71 72 func (e encoder) encodeFloat32(b []byte, p unsafe.Pointer) ([]byte, error) { 73 if e.clrs == nil { 74 return e.encodeFloat(b, float64(*(*float32)(p)), 32) 75 } 76 77 b = append(b, e.clrs.Number...) 78 var err error 79 b, err = e.encodeFloat(b, float64(*(*float32)(p)), 32) 80 b = append(b, ansiReset...) 81 return b, err 82 } 83 84 func (e encoder) encodeFloat64(b []byte, p unsafe.Pointer) ([]byte, error) { 85 if e.clrs == nil { 86 return e.encodeFloat(b, *(*float64)(p), 64) 87 } 88 89 b = append(b, e.clrs.Number...) 90 var err error 91 b, err = e.encodeFloat(b, *(*float64)(p), 64) 92 b = append(b, ansiReset...) 93 return b, err 94 } 95 96 func (e encoder) encodeFloat(b []byte, f float64, bits int) ([]byte, error) { 97 switch { 98 case math.IsNaN(f): 99 return b, &UnsupportedValueError{Value: reflect.ValueOf(f), Str: "NaN"} 100 case math.IsInf(f, 0): 101 return b, &UnsupportedValueError{Value: reflect.ValueOf(f), Str: "inf"} 102 } 103 104 // Convert as if by ES6 number to string conversion. 105 // This matches most other JSON generators. 106 // See golang.org/issue/6384 and golang.org/issue/14135. 107 // Like fmt %g, but the exponent cutoffs are different 108 // and exponents themselves are not padded to two digits. 109 abs := math.Abs(f) 110 fmt := byte('f') 111 // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. 112 if abs != 0 { 113 if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { 114 fmt = 'e' 115 } 116 } 117 118 b = strconv.AppendFloat(b, f, fmt, -1, bits) 119 120 if fmt == 'e' { 121 // clean up e-09 to e-9 122 n := len(b) 123 if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' { 124 b[n-2] = b[n-1] 125 b = b[:n-1] 126 } 127 } 128 129 return b, nil 130 } 131 132 func (e encoder) encodeNumber(b []byte, p unsafe.Pointer) ([]byte, error) { 133 n := *(*Number)(p) 134 if n == "" { 135 n = "0" 136 } 137 138 _, _, err := parseNumber(stringToBytes(string(n))) 139 if err != nil { 140 return b, err 141 } 142 143 if e.clrs == nil { 144 return append(b, n...), nil 145 } 146 147 b = append(b, e.clrs.Number...) 148 b = append(b, n...) 149 b = append(b, ansiReset...) 150 return b, nil 151 } 152 153 func (e encoder) encodeKey(b []byte, p unsafe.Pointer) ([]byte, error) { 154 if e.clrs == nil { 155 return e.doEncodeString(b, p) 156 } 157 158 b = append(b, e.clrs.Key...) 159 var err error 160 b, err = e.doEncodeString(b, p) 161 b = append(b, ansiReset...) 162 return b, err 163 } 164 165 func (e encoder) encodeString(b []byte, p unsafe.Pointer) ([]byte, error) { 166 if e.clrs == nil { 167 return e.doEncodeString(b, p) 168 } 169 170 b = append(b, e.clrs.String...) 171 var err error 172 b, err = e.doEncodeString(b, p) 173 b = append(b, ansiReset...) 174 return b, err 175 } 176 177 func (e encoder) doEncodeString(b []byte, p unsafe.Pointer) ([]byte, error) { 178 s := *(*string)(p) 179 i := 0 180 j := 0 181 escapeHTML := (e.flags & EscapeHTML) != 0 182 183 b = append(b, '"') 184 185 for j < len(s) { 186 c := s[j] 187 188 if c >= 0x20 && c <= 0x7f && c != '\\' && c != '"' && (!escapeHTML || (c != '<' && c != '>' && c != '&')) { 189 // fast path: most of the time, printable ascii characters are used 190 j++ 191 continue 192 } 193 194 switch c { 195 case '\\', '"': 196 b = append(b, s[i:j]...) 197 b = append(b, '\\', c) 198 i = j + 1 199 j = i 200 continue 201 202 case '\n': 203 b = append(b, s[i:j]...) 204 b = append(b, '\\', 'n') 205 i = j + 1 206 j = i 207 continue 208 209 case '\r': 210 b = append(b, s[i:j]...) 211 b = append(b, '\\', 'r') 212 i = j + 1 213 j = i 214 continue 215 216 case '\t': 217 b = append(b, s[i:j]...) 218 b = append(b, '\\', 't') 219 i = j + 1 220 j = i 221 continue 222 223 case '<', '>', '&': 224 b = append(b, s[i:j]...) 225 b = append(b, `\u00`...) 226 b = append(b, hex[c>>4], hex[c&0xF]) 227 i = j + 1 228 j = i 229 continue 230 } 231 232 // This encodes bytes < 0x20 except for \t, \n and \r. 233 if c < 0x20 { 234 b = append(b, s[i:j]...) 235 b = append(b, `\u00`...) 236 b = append(b, hex[c>>4], hex[c&0xF]) 237 i = j + 1 238 j = i 239 continue 240 } 241 242 r, size := utf8.DecodeRuneInString(s[j:]) 243 244 if r == utf8.RuneError && size == 1 { 245 b = append(b, s[i:j]...) 246 b = append(b, `\ufffd`...) 247 i = j + size 248 j = i 249 continue 250 } 251 252 switch r { 253 case '\u2028', '\u2029': 254 // U+2028 is LINE SEPARATOR. 255 // U+2029 is PARAGRAPH SEPARATOR. 256 // They are both technically valid characters in JSON strings, 257 // but don't work in JSONP, which has to be evaluated as JavaScript, 258 // and can lead to security holes there. It is valid JSON to 259 // escape them, so we do so unconditionally. 260 // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. 261 b = append(b, s[i:j]...) 262 b = append(b, `\u202`...) 263 b = append(b, hex[r&0xF]) 264 i = j + size 265 j = i 266 continue 267 } 268 269 j += size 270 } 271 272 b = append(b, s[i:]...) 273 b = append(b, '"') 274 return b, nil 275 } 276 277 func (e encoder) encodeToString(b []byte, p unsafe.Pointer, encode encodeFunc) ([]byte, error) { 278 i := len(b) 279 280 b, err := encode(e, b, p) 281 if err != nil { 282 return b, err 283 } 284 285 j := len(b) 286 s := b[i:] 287 288 if b, err = e.doEncodeString(b, unsafe.Pointer(&s)); err != nil { 289 return b, err 290 } 291 292 n := copy(b[i:], b[j:]) 293 return b[:i+n], nil 294 } 295 296 func (e encoder) encodeBytes(b []byte, p unsafe.Pointer) ([]byte, error) { 297 if e.clrs == nil { 298 return e.doEncodeBytes(b, p) 299 } 300 301 b = append(b, e.clrs.Bytes...) 302 var err error 303 b, err = e.doEncodeBytes(b, p) 304 return append(b, ansiReset...), err 305 } 306 307 func (e encoder) doEncodeBytes(b []byte, p unsafe.Pointer) ([]byte, error) { 308 v := *(*[]byte)(p) 309 if v == nil { 310 return e.clrs.appendNull(b), nil 311 } 312 313 n := base64.StdEncoding.EncodedLen(len(v)) + 2 314 315 if avail := cap(b) - len(b); avail < n { 316 newB := make([]byte, cap(b)+(n-avail)) 317 copy(newB, b) 318 b = newB[:len(b)] 319 } 320 321 i := len(b) 322 j := len(b) + n 323 324 b = b[:j] 325 b[i] = '"' 326 base64.StdEncoding.Encode(b[i+1:j-1], v) 327 b[j-1] = '"' 328 return b, nil 329 } 330 331 func (e encoder) encodeDuration(b []byte, p unsafe.Pointer) ([]byte, error) { 332 // NOTE: The segmentj encoder does special handling for time.Duration (converts to string). 333 // The stdlib encoder does not. It just outputs the int64 value. 334 // We choose to follow the stdlib pattern, for fuller compatibility. 335 336 b = e.clrs.appendInt64(b, int64(*(*time.Duration)(p))) 337 return b, nil 338 339 // NOTE: if we were to follow the segmentj pattern, we'd execute the code below. 340 // if e.clrs == nil { 341 // b = append(b, '"') 342 // 343 // b = appendDuration(b, *(*time.Duration)(p)) 344 // b = append(b, '"') 345 // return b, nil 346 // } 347 // 348 // b = append(b, e.clrs.Time...) 349 // b = append(b, '"') 350 // b = appendDuration(b, *(*time.Duration)(p)) 351 // b = append(b, '"') 352 // b = append(b, ansiReset...) 353 // return b, nil 354 } 355 356 func (e encoder) encodeTime(b []byte, p unsafe.Pointer) ([]byte, error) { 357 if e.clrs == nil { 358 t := *(*time.Time)(p) 359 b = append(b, '"') 360 b = t.AppendFormat(b, time.RFC3339Nano) 361 b = append(b, '"') 362 return b, nil 363 } 364 365 t := *(*time.Time)(p) 366 b = append(b, e.clrs.Time...) 367 b = append(b, '"') 368 b = t.AppendFormat(b, time.RFC3339Nano) 369 b = append(b, '"') 370 b = append(b, ansiReset...) 371 return b, nil 372 } 373 374 func (e encoder) encodeArray(b []byte, p unsafe.Pointer, n int, size uintptr, _ reflect.Type, encode encodeFunc) ([]byte, error) { 375 start := len(b) 376 var err error 377 378 b = e.clrs.appendPunc(b, '[') 379 380 if n > 0 { 381 e.indentr.push() 382 for i := 0; i < n; i++ { 383 if i != 0 { 384 b = e.clrs.appendPunc(b, ',') 385 } 386 387 b = e.indentr.appendByte(b, '\n') 388 b = e.indentr.appendIndent(b) 389 390 if b, err = encode(e, b, unsafe.Pointer(uintptr(p)+(uintptr(i)*size))); err != nil { 391 return b[:start], err 392 } 393 } 394 e.indentr.pop() 395 b = e.indentr.appendByte(b, '\n') 396 b = e.indentr.appendIndent(b) 397 } 398 399 b = e.clrs.appendPunc(b, ']') 400 401 return b, nil 402 } 403 404 func (e encoder) encodeSlice(b []byte, p unsafe.Pointer, size uintptr, t reflect.Type, encode encodeFunc) ([]byte, error) { 405 s := (*slice)(p) 406 407 if s.data == nil && s.len == 0 && s.cap == 0 { 408 return e.clrs.appendNull(b), nil 409 } 410 411 return e.encodeArray(b, s.data, s.len, size, t, encode) 412 } 413 414 func (e encoder) encodeMap(b []byte, p unsafe.Pointer, t reflect.Type, encodeKey, encodeValue encodeFunc, sortKeys sortFunc) ([]byte, error) { 415 m := reflect.NewAt(t, p).Elem() 416 if m.IsNil() { 417 return e.clrs.appendNull(b), nil 418 } 419 420 keys := m.MapKeys() 421 if sortKeys != nil && (e.flags&SortMapKeys) != 0 { 422 sortKeys(keys) 423 } 424 425 start := len(b) 426 var err error 427 b = e.clrs.appendPunc(b, '{') 428 429 if len(keys) != 0 { 430 b = e.indentr.appendByte(b, '\n') 431 432 e.indentr.push() 433 for i := range keys { 434 k := keys[i] 435 v := m.MapIndex(k) 436 437 if i != 0 { 438 b = e.clrs.appendPunc(b, ',') 439 b = e.indentr.appendByte(b, '\n') 440 } 441 442 b = e.indentr.appendIndent(b) 443 if b, err = encodeKey(e, b, (*iface)(unsafe.Pointer(&k)).ptr); err != nil { 444 return b[:start], err 445 } 446 447 b = e.clrs.appendPunc(b, ':') 448 b = e.indentr.appendByte(b, ' ') 449 450 if b, err = encodeValue(e, b, (*iface)(unsafe.Pointer(&v)).ptr); err != nil { 451 return b[:start], err 452 } 453 } 454 b = e.indentr.appendByte(b, '\n') 455 e.indentr.pop() 456 b = e.indentr.appendIndent(b) 457 } 458 459 b = e.clrs.appendPunc(b, '}') 460 return b, nil 461 } 462 463 type element struct { 464 key string 465 val interface{} 466 raw RawMessage 467 } 468 469 type mapslice struct { 470 elements []element 471 } 472 473 func (m *mapslice) Len() int { return len(m.elements) } 474 func (m *mapslice) Less(i, j int) bool { return m.elements[i].key < m.elements[j].key } 475 func (m *mapslice) Swap(i, j int) { m.elements[i], m.elements[j] = m.elements[j], m.elements[i] } 476 477 var mapslicePool = sync.Pool{ 478 New: func() interface{} { return new(mapslice) }, 479 } 480 481 func (e encoder) encodeMapStringInterface(b []byte, p unsafe.Pointer) ([]byte, error) { 482 m := *(*map[string]interface{})(p) 483 if m == nil { 484 return e.clrs.appendNull(b), nil 485 } 486 487 if (e.flags & SortMapKeys) == 0 { 488 // Optimized code path when the program does not need the map keys to be 489 // sorted. 490 b = e.clrs.appendPunc(b, '{') 491 492 if len(m) != 0 { 493 b = e.indentr.appendByte(b, '\n') 494 495 var err error 496 i := 0 497 498 e.indentr.push() 499 for k, v := range m { 500 if i != 0 { 501 b = e.clrs.appendPunc(b, ',') 502 b = e.indentr.appendByte(b, '\n') 503 } 504 505 b = e.indentr.appendIndent(b) 506 507 b, err = e.encodeKey(b, unsafe.Pointer(&k)) 508 if err != nil { 509 return b, err 510 } 511 512 b = e.clrs.appendPunc(b, ':') 513 b = e.indentr.appendByte(b, ' ') 514 515 b, err = Append(b, v, e.flags, e.clrs, e.indentr) 516 if err != nil { 517 return b, err 518 } 519 520 i++ 521 } 522 b = e.indentr.appendByte(b, '\n') 523 e.indentr.pop() 524 b = e.indentr.appendIndent(b) 525 } 526 527 b = e.clrs.appendPunc(b, '}') 528 return b, nil 529 } 530 531 s := mapslicePool.Get().(*mapslice) //nolint:errcheck 532 if cap(s.elements) < len(m) { 533 s.elements = make([]element, 0, align(10, uintptr(len(m)))) 534 } 535 for key, val := range m { 536 s.elements = append(s.elements, element{key: key, val: val}) 537 } 538 sort.Sort(s) 539 540 start := len(b) 541 var err error 542 b = e.clrs.appendPunc(b, '{') 543 544 if len(s.elements) > 0 { 545 b = e.indentr.appendByte(b, '\n') 546 547 e.indentr.push() 548 for i := range s.elements { 549 elem := s.elements[i] 550 if i != 0 { 551 b = e.clrs.appendPunc(b, ',') 552 b = e.indentr.appendByte(b, '\n') 553 } 554 555 b = e.indentr.appendIndent(b) 556 557 b, _ = e.encodeKey(b, unsafe.Pointer(&elem.key)) 558 b = e.clrs.appendPunc(b, ':') 559 b = e.indentr.appendByte(b, ' ') 560 561 b, err = Append(b, elem.val, e.flags, e.clrs, e.indentr) 562 if err != nil { 563 break 564 } 565 } 566 b = e.indentr.appendByte(b, '\n') 567 e.indentr.pop() 568 b = e.indentr.appendIndent(b) 569 } 570 571 for i := range s.elements { 572 s.elements[i] = element{} 573 } 574 575 s.elements = s.elements[:0] 576 mapslicePool.Put(s) 577 578 if err != nil { 579 return b[:start], err 580 } 581 582 b = e.clrs.appendPunc(b, '}') 583 return b, nil 584 } 585 586 func (e encoder) encodeMapStringRawMessage(b []byte, p unsafe.Pointer) ([]byte, error) { 587 m := *(*map[string]RawMessage)(p) 588 if m == nil { 589 return e.clrs.appendNull(b), nil 590 } 591 592 if (e.flags & SortMapKeys) == 0 { 593 // Optimized code path when the program does not need the map keys to be 594 // sorted. 595 b = e.clrs.appendPunc(b, '{') 596 597 if len(m) != 0 { 598 b = e.indentr.appendByte(b, '\n') 599 600 var err error 601 i := 0 602 603 e.indentr.push() 604 for k := range m { 605 if i != 0 { 606 b = e.clrs.appendPunc(b, ',') 607 b = e.indentr.appendByte(b, '\n') 608 } 609 610 b = e.indentr.appendIndent(b) 611 612 b, _ = e.encodeKey(b, unsafe.Pointer(&k)) 613 614 b = e.clrs.appendPunc(b, ':') 615 b = e.indentr.appendByte(b, ' ') 616 617 v := m[k] 618 b, err = e.encodeRawMessage(b, unsafe.Pointer(&v)) 619 if err != nil { 620 break 621 } 622 623 i++ 624 } 625 b = e.indentr.appendByte(b, '\n') 626 e.indentr.pop() 627 b = e.indentr.appendIndent(b) 628 } 629 630 b = e.clrs.appendPunc(b, '}') 631 return b, nil 632 } 633 634 s := mapslicePool.Get().(*mapslice) //nolint:errcheck 635 if cap(s.elements) < len(m) { 636 s.elements = make([]element, 0, align(10, uintptr(len(m)))) 637 } 638 for key, raw := range m { 639 s.elements = append(s.elements, element{key: key, raw: raw}) 640 } 641 sort.Sort(s) 642 643 start := len(b) 644 var err error 645 b = e.clrs.appendPunc(b, '{') 646 647 if len(s.elements) > 0 { 648 b = e.indentr.appendByte(b, '\n') 649 650 e.indentr.push() 651 652 for i := range s.elements { 653 if i != 0 { 654 b = e.clrs.appendPunc(b, ',') 655 b = e.indentr.appendByte(b, '\n') 656 } 657 658 b = e.indentr.appendIndent(b) 659 660 elem := s.elements[i] 661 b, _ = e.encodeKey(b, unsafe.Pointer(&elem.key)) 662 b = e.clrs.appendPunc(b, ':') 663 b = e.indentr.appendByte(b, ' ') 664 665 b, err = e.encodeRawMessage(b, unsafe.Pointer(&elem.raw)) 666 if err != nil { 667 break 668 } 669 } 670 b = e.indentr.appendByte(b, '\n') 671 e.indentr.pop() 672 b = e.indentr.appendIndent(b) 673 } 674 675 for i := range s.elements { 676 s.elements[i] = element{} 677 } 678 679 s.elements = s.elements[:0] 680 mapslicePool.Put(s) 681 682 if err != nil { 683 return b[:start], err 684 } 685 686 b = e.clrs.appendPunc(b, '}') 687 return b, nil 688 } 689 690 func (e encoder) encodeStruct(b []byte, p unsafe.Pointer, st *structType) ([]byte, error) { 691 var err error 692 var k string 693 var n int 694 start := len(b) 695 696 b = e.clrs.appendPunc(b, '{') 697 698 if len(st.fields) > 0 { 699 b = e.indentr.appendByte(b, '\n') 700 } 701 702 e.indentr.push() 703 704 for i := range st.fields { 705 f := &st.fields[i] 706 v := unsafe.Pointer(uintptr(p) + f.offset) 707 708 if f.omitempty && f.empty(v) { 709 continue 710 } 711 712 if n != 0 { 713 b = e.clrs.appendPunc(b, ',') 714 b = e.indentr.appendByte(b, '\n') 715 } 716 717 if (e.flags & EscapeHTML) != 0 { 718 k = f.html 719 } else { 720 k = f.json 721 } 722 723 lengthBeforeKey := len(b) 724 b = e.indentr.appendIndent(b) 725 726 if e.clrs == nil { 727 b = append(b, k...) 728 } else { 729 b = append(b, e.clrs.Key...) 730 b = append(b, k...) 731 b = append(b, ansiReset...) 732 } 733 734 b = e.clrs.appendPunc(b, ':') 735 736 b = e.indentr.appendByte(b, ' ') 737 738 if b, err = f.codec.encode(e, b, v); err != nil { 739 if errors.Is(err, rollback{}) { 740 b = b[:lengthBeforeKey] 741 continue 742 } 743 return b[:start], err 744 } 745 746 n++ 747 } 748 749 if n > 0 { 750 b = e.indentr.appendByte(b, '\n') 751 } 752 753 e.indentr.pop() 754 b = e.indentr.appendIndent(b) 755 756 b = e.clrs.appendPunc(b, '}') 757 return b, nil 758 } 759 760 type rollback struct{} 761 762 func (rollback) Error() string { return "rollback" } 763 764 func (e encoder) encodeEmbeddedStructPointer(b []byte, p unsafe.Pointer, _ reflect.Type, _ bool, offset uintptr, encode encodeFunc) ([]byte, error) { 765 p = *(*unsafe.Pointer)(p) 766 if p == nil { 767 return b, rollback{} 768 } 769 return encode(e, b, unsafe.Pointer(uintptr(p)+offset)) 770 } 771 772 func (e encoder) encodePointer(b []byte, p unsafe.Pointer, _ reflect.Type, encode encodeFunc) ([]byte, error) { 773 if p = *(*unsafe.Pointer)(p); p != nil { 774 return encode(e, b, p) 775 } 776 return e.encodeNull(b, nil) 777 } 778 779 func (e encoder) encodeInterface(b []byte, p unsafe.Pointer) ([]byte, error) { 780 return Append(b, *(*interface{})(p), e.flags, e.clrs, e.indentr) 781 } 782 783 func (e encoder) encodeMaybeEmptyInterface(b []byte, p unsafe.Pointer, t reflect.Type) ([]byte, error) { 784 return Append(b, reflect.NewAt(t, p).Elem().Interface(), e.flags, e.clrs, e.indentr) 785 } 786 787 func (e encoder) encodeUnsupportedTypeError(b []byte, _ unsafe.Pointer, t reflect.Type) ([]byte, error) { 788 return b, &UnsupportedTypeError{Type: t} 789 } 790 791 // encodeRawMessage encodes a RawMessage to bytes. Unfortunately, this 792 // implementation has a deficiency: it uses Unmarshal to build an 793 // object from the RawMessage, which in the case of a struct, results 794 // in a map being constructed, and thus the order of the keys is not 795 // guaranteed to be maintained. A superior implementation would decode and 796 // then re-encode (with color/indentation) the basic JSON tokens on the fly. 797 // Note also that if TrustRawMessage is set, and the RawMessage is 798 // invalid JSON (cannot be parsed by Unmarshal), then this function 799 // falls back to encodeRawMessageNoParseTrusted, which seems to exhibit the 800 // correct behavior. It's a bit of a mess, but seems to do the trick. 801 func (e encoder) encodeRawMessage(b []byte, p unsafe.Pointer) ([]byte, error) { 802 v := *(*RawMessage)(p) 803 804 if v == nil { 805 return e.clrs.appendNull(b), nil 806 } 807 808 var s []byte 809 810 if (e.flags & TrustRawMessage) != 0 { 811 s = v 812 } else { 813 var err error 814 s, _, err = parseValue(v) 815 if err != nil { 816 return b, &UnsupportedValueError{Value: reflect.ValueOf(v), Str: err.Error()} 817 } 818 } 819 820 var x interface{} 821 if err := Unmarshal(s, &x); err != nil { 822 return e.encodeRawMessageNoParseTrusted(b, p) 823 } 824 825 return Append(b, x, e.flags, e.clrs, e.indentr) 826 } 827 828 // encodeRawMessageNoParseTrusted is a fallback method that is 829 // used by encodeRawMessage if it fails to parse a trusted RawMessage. 830 // The (invalid) JSON produced by this method is not colorized. 831 // This method may have wonky logic or even bugs in it; little effort 832 // has been expended on it because it's a rarely visited edge case. 833 func (e encoder) encodeRawMessageNoParseTrusted(b []byte, p unsafe.Pointer) ([]byte, error) { 834 v := *(*RawMessage)(p) 835 836 if v == nil { 837 return e.clrs.appendNull(b), nil 838 } 839 840 var s []byte 841 842 if (e.flags & TrustRawMessage) != 0 { 843 s = v 844 } else { 845 var err error 846 s, _, err = parseValue(v) 847 if err != nil { 848 return b, &UnsupportedValueError{Value: reflect.ValueOf(v), Str: err.Error()} 849 } 850 } 851 852 if e.indentr == nil { 853 if (e.flags & EscapeHTML) != 0 { 854 return appendCompactEscapeHTML(b, s), nil 855 } 856 857 return append(b, s...), nil 858 } 859 860 // In order to get the tests inherited from the original segmentio 861 // encoder to work, we need to support indentation. 862 863 // This below is sloppy, but seems to work. 864 if (e.flags & EscapeHTML) != 0 { 865 s = appendCompactEscapeHTML(nil, s) 866 } 867 868 // The "prefix" arg to Indent is the current indentation. 869 pre := e.indentr.appendIndent(nil) 870 871 buf := &bytes.Buffer{} 872 // And now we just make use of the existing Indent function. 873 err := Indent(buf, s, string(pre), e.indentr.indent) 874 if err != nil { 875 return b, err 876 } 877 878 s = buf.Bytes() 879 880 return append(b, s...), nil 881 } 882 883 // encodeJSONMarshaler suffers from the same defect as encodeRawMessage; it 884 // can result in keys being reordered. 885 func (e encoder) encodeJSONMarshaler(b []byte, p unsafe.Pointer, t reflect.Type, pointer bool) ([]byte, error) { 886 v := reflect.NewAt(t, p) 887 888 if !pointer { 889 v = v.Elem() 890 } 891 892 switch v.Kind() { 893 case reflect.Ptr, reflect.Interface: 894 if v.IsNil() { 895 return e.clrs.appendNull(b), nil 896 } 897 } 898 899 j, err := v.Interface().(Marshaler).MarshalJSON() 900 if err != nil { 901 return b, err 902 } 903 904 // We effectively delegate to the encodeRawMessage method. 905 return Append(b, RawMessage(j), e.flags, e.clrs, e.indentr) 906 } 907 908 func (e encoder) encodeTextMarshaler(b []byte, p unsafe.Pointer, t reflect.Type, pointer bool) ([]byte, error) { 909 v := reflect.NewAt(t, p) 910 911 if !pointer { 912 v = v.Elem() 913 } 914 915 switch v.Kind() { 916 case reflect.Ptr, reflect.Interface: 917 if v.IsNil() { 918 return e.clrs.appendNull(b), nil 919 } 920 } 921 922 s, err := v.Interface().(encoding.TextMarshaler).MarshalText() 923 if err != nil { 924 return b, err 925 } 926 927 if e.clrs == nil { 928 return e.doEncodeString(b, unsafe.Pointer(&s)) 929 } 930 931 b = append(b, e.clrs.TextMarshaler...) 932 b, err = e.doEncodeString(b, unsafe.Pointer(&s)) 933 b = append(b, ansiReset...) 934 return b, err 935 } 936 937 func appendCompactEscapeHTML(dst, src []byte) []byte { 938 start := 0 939 escape := false 940 inString := false 941 942 for i, c := range src { 943 if !inString { 944 switch c { 945 case '"': // enter string 946 inString = true 947 case ' ', '\n', '\r', '\t': // skip space 948 if start < i { 949 dst = append(dst, src[start:i]...) 950 } 951 start = i + 1 952 } 953 continue 954 } 955 956 if escape { 957 escape = false 958 continue 959 } 960 961 if c == '\\' { 962 escape = true 963 continue 964 } 965 966 if c == '"' { 967 inString = false 968 continue 969 } 970 971 if c == '<' || c == '>' || c == '&' { 972 if start < i { 973 dst = append(dst, src[start:i]...) 974 } 975 dst = append(dst, `\u00`...) 976 dst = append(dst, hex[c>>4], hex[c&0xF]) 977 start = i + 1 978 continue 979 } 980 981 // Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9). 982 if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 { 983 if start < i { 984 dst = append(dst, src[start:i]...) 985 } 986 dst = append(dst, `\u202`...) 987 dst = append(dst, hex[src[i+2]&0xF]) 988 start = i + 3 989 continue 990 } 991 } 992 993 if start < len(src) { 994 dst = append(dst, src[start:]...) 995 } 996 997 return dst 998 } 999 1000 // indenter is used to indent JSON. The push and pop methods 1001 // change indentation level. The appendIndent method appends the 1002 // computed indentation. The appendByte method appends a byte. All 1003 // methods are safe to use with a nil receiver. 1004 type indenter struct { 1005 disabled bool 1006 prefix string 1007 indent string 1008 depth int 1009 } 1010 1011 // newIndenter returns a new indenter instance. If prefix and 1012 // indent are both empty, the indenter is effectively disabled, 1013 // and the appendIndent and appendByte methods are no-op. 1014 func newIndenter(prefix, indent string) *indenter { 1015 return &indenter{ 1016 disabled: prefix == "" && indent == "", 1017 prefix: prefix, 1018 indent: indent, 1019 } 1020 } 1021 1022 // push increases the indentation level. 1023 func (in *indenter) push() { 1024 if in != nil { 1025 in.depth++ 1026 } 1027 } 1028 1029 // pop decreases the indentation level. 1030 func (in *indenter) pop() { 1031 if in != nil { 1032 in.depth-- 1033 } 1034 } 1035 1036 // appendByte appends a to b if the indenter is non-nil and enabled. 1037 // Otherwise b is returned unmodified. 1038 func (in *indenter) appendByte(b []byte, a byte) []byte { 1039 if in == nil || in.disabled { 1040 return b 1041 } 1042 1043 return append(b, a) 1044 } 1045 1046 // appendIndent writes indentation to b, returning the resulting slice. 1047 // If the indenter is nil or disabled b is returned unchanged. 1048 func (in *indenter) appendIndent(b []byte) []byte { 1049 if in == nil || in.disabled { 1050 return b 1051 } 1052 1053 b = append(b, in.prefix...) 1054 for i := 0; i < in.depth; i++ { 1055 b = append(b, in.indent...) 1056 } 1057 return b 1058 }