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