github.com/searKing/golang/go@v1.2.117/encoding/prettyjson/encode.go (about) 1 // Copyright 2023 The searKing Author. 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 prettyjson 6 7 import ( 8 "bytes" 9 "encoding" 10 "encoding/base64" 11 "encoding/json" 12 "fmt" 13 "math" 14 "net/url" 15 "reflect" 16 "sort" 17 "strconv" 18 "strings" 19 "sync" 20 "unicode" 21 "unicode/utf8" 22 23 bytes_ "github.com/searKing/golang/go/bytes" 24 strings_ "github.com/searKing/golang/go/strings" 25 ) 26 27 // Marshal returns the JSON encoding of v, and support truncate. 28 func Marshal(v any, opts ...EncOptsOption) ([]byte, error) { 29 e := newEncodeState() 30 defer encodeStatePool.Put(e) 31 32 var opt encOpts 33 opt.escapeHTML = true 34 opt.ApplyOptions(opts...) 35 err := e.marshal(v, opt) 36 if err != nil { 37 return nil, err 38 } 39 buf := append([]byte(nil), e.Bytes()...) 40 return buf, nil 41 } 42 43 // MarshalIndent is like Marshal but applies Indent to format the output. 44 // Each JSON element in the output will begin on a new line beginning with prefix 45 // followed by one or more copies of indent according to the indentation nesting. 46 func MarshalIndent(v any, prefix, indent string, opts ...EncOptsOption) ([]byte, error) { 47 b, err := Marshal(v, opts...) 48 if err != nil { 49 return nil, err 50 } 51 var buf bytes.Buffer 52 err = json.Indent(&buf, b, prefix, indent) 53 if err != nil { 54 return nil, err 55 } 56 return buf.Bytes(), nil 57 } 58 59 // Marshaler is the interface implemented by types that 60 // can marshal themselves into valid JSON. 61 type Marshaler = json.Marshaler 62 63 // An UnsupportedTypeError is returned by Marshal when attempting 64 // to encode an unsupported value type. 65 type UnsupportedTypeError = json.UnsupportedTypeError 66 67 // An UnsupportedValueError is returned by Marshal when attempting 68 // to encode an unsupported value. 69 type UnsupportedValueError = json.UnsupportedValueError 70 71 // A MarshalerError represents an error from calling a MarshalJSON or MarshalText method. 72 type MarshalerError = json.MarshalerError 73 74 var hex = "0123456789abcdef" 75 76 // An encodeState encodes JSON into a bytes.Buffer. 77 type encodeState struct { 78 bytes.Buffer // accumulated output 79 80 // Keep track of what pointers we've seen in the current recursive call 81 // path, to avoid cycles that could lead to a stack overflow. Only do 82 // the relatively expensive map operations if ptrLevel is larger than 83 // startDetectingCyclesAfter, so that we skip the work if we're within a 84 // reasonable amount of nested pointers deep. 85 ptrLevel uint 86 ptrSeen map[any]struct{} 87 } 88 89 const startDetectingCyclesAfter = 1000 90 91 var encodeStatePool sync.Pool 92 93 func newEncodeState() *encodeState { 94 if v := encodeStatePool.Get(); v != nil { 95 e := v.(*encodeState) 96 e.Reset() 97 if len(e.ptrSeen) > 0 { 98 panic("ptrEncoder.encode should have emptied ptrSeen via defers") 99 } 100 e.ptrLevel = 0 101 return e 102 } 103 return &encodeState{ptrSeen: make(map[any]struct{})} 104 } 105 106 // jsonError is an error wrapper type for internal use only. 107 // Panics with errors are wrapped in jsonError so that the top-level recover 108 // can distinguish intentional panics from this package. 109 type jsonError struct{ error } 110 111 func (e *encodeState) marshal(v any, opts encOpts) (err error) { 112 defer func() { 113 if r := recover(); r != nil { 114 if je, ok := r.(jsonError); ok { 115 err = je.error 116 } else { 117 panic(r) 118 } 119 } 120 }() 121 e.reflectValue(reflect.ValueOf(v), opts) 122 return nil 123 } 124 125 // error aborts the encoding by panicking with err wrapped in jsonError. 126 func (e *encodeState) error(err error) { 127 panic(jsonError{err}) 128 } 129 130 func isEmptyValue(v reflect.Value) bool { 131 // @diff 132 defer func() { 133 if r := recover(); r != nil { 134 return 135 } 136 }() 137 switch v.Kind() { 138 case reflect.Array, reflect.Map, reflect.Slice, reflect.String: 139 return v.Len() == 0 140 case reflect.Bool: 141 return v.Bool() == false 142 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 143 return v.Int() == 0 144 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 145 return v.Uint() == 0 146 case reflect.Float32, reflect.Float64: 147 return v.Float() == 0 148 case reflect.Interface, reflect.Pointer: 149 return v.IsNil() 150 default: // @diff 151 return v.IsZero() 152 } 153 return false 154 } 155 156 func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) { 157 valueEncoder(v)(e, v, opts) 158 } 159 160 //go:generate go-option -type "encOpts" 161 type encOpts struct { 162 // quoted causes primitive fields to be encoded inside JSON strings. 163 quoted bool 164 // escapeHTML causes '<', '>', and '&' to be escaped in JSON strings. 165 escapeHTML bool 166 167 truncateBytes int 168 truncateString int 169 truncateMap int 170 truncateSliceOrArray int 171 truncateUrl bool // truncate query and fragment in url 172 omitEmpty bool 173 } 174 175 type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts) 176 177 var encoderCache sync.Map // map[reflect.Type]encoderFunc 178 179 func valueEncoder(v reflect.Value) encoderFunc { 180 if !v.IsValid() { 181 return invalidValueEncoder 182 } 183 return typeEncoder(v.Type()) 184 } 185 186 func typeEncoder(t reflect.Type) encoderFunc { 187 if fi, ok := encoderCache.Load(t); ok { 188 return fi.(encoderFunc) 189 } 190 191 // To deal with recursive types, populate the map with an 192 // indirect func before we build it. This type waits on the 193 // real func (f) to be ready and then calls it. This indirect 194 // func is only used for recursive types. 195 var ( 196 wg sync.WaitGroup 197 f encoderFunc 198 ) 199 wg.Add(1) 200 fi, loaded := encoderCache.LoadOrStore(t, encoderFunc(func(e *encodeState, v reflect.Value, opts encOpts) { 201 wg.Wait() 202 f(e, v, opts) 203 })) 204 if loaded { 205 return fi.(encoderFunc) 206 } 207 208 // Compute the real encoder and replace the indirect func with it. 209 f = newTypeEncoder(t, true) 210 wg.Done() 211 encoderCache.Store(t, f) 212 return f 213 } 214 215 var ( 216 marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() 217 textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() 218 ) 219 220 // newTypeEncoder constructs an encoderFunc for a type. 221 // The returned encoder only checks CanAddr when allowAddr is true. 222 func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc { 223 // If we have a non-pointer value whose type implements 224 // Marshaler with a value receiver, then we're better off taking 225 // the address of the value - otherwise we end up with an 226 // allocation as we cast the value to an interface. 227 if t.Kind() != reflect.Pointer && allowAddr && reflect.PointerTo(t).Implements(marshalerType) { 228 return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false)) 229 } 230 if t.Implements(marshalerType) { 231 return marshalerEncoder 232 } 233 if t.Kind() != reflect.Pointer && allowAddr && reflect.PointerTo(t).Implements(textMarshalerType) { 234 return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false)) 235 } 236 if t.Implements(textMarshalerType) { 237 return textMarshalerEncoder 238 } 239 240 switch t.Kind() { 241 case reflect.Bool: 242 return boolEncoder 243 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 244 return intEncoder 245 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 246 return uintEncoder 247 case reflect.Float32: 248 return float32Encoder 249 case reflect.Float64: 250 return float64Encoder 251 case reflect.String: 252 return stringEncoder 253 case reflect.Interface: 254 return interfaceEncoder 255 case reflect.Struct: 256 return newStructEncoder(t) 257 case reflect.Map: 258 return newMapEncoder(t) 259 case reflect.Slice: 260 return newSliceEncoder(t) 261 case reflect.Array: 262 return newArrayEncoder(t) 263 case reflect.Pointer: 264 return newPtrEncoder(t) 265 default: 266 return unsupportedTypeEncoder 267 } 268 } 269 270 func invalidValueEncoder(e *encodeState, v reflect.Value, _ encOpts) { 271 e.WriteString("null") 272 } 273 274 func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { 275 if v.Kind() == reflect.Pointer && v.IsNil() { 276 e.WriteString("null") 277 return 278 } 279 m, ok := v.Interface().(Marshaler) 280 if !ok { 281 e.WriteString("null") 282 return 283 } 284 b, err := m.MarshalJSON() 285 if err == nil { 286 e.Grow(len(b)) 287 out := e.AvailableBuffer() 288 out, err = appendCompact(out, b, opts.escapeHTML) 289 e.Buffer.Write(out) 290 } 291 if err != nil { 292 e.error(&MarshalerError{Type: v.Type(), Err: err}) 293 } 294 } 295 296 func addrMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { 297 va := v.Addr() 298 if va.IsNil() { 299 e.WriteString("null") 300 return 301 } 302 m := va.Interface().(Marshaler) 303 b, err := m.MarshalJSON() 304 if err == nil { 305 e.Grow(len(b)) 306 out := e.AvailableBuffer() 307 out, err = appendCompact(out, b, opts.escapeHTML) 308 e.Buffer.Write(out) 309 } 310 if err != nil { 311 e.error(&MarshalerError{Type: v.Type(), Err: err}) 312 } 313 } 314 315 func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { 316 if v.Kind() == reflect.Pointer && v.IsNil() { 317 e.WriteString("null") 318 return 319 } 320 m, ok := v.Interface().(encoding.TextMarshaler) 321 if !ok { 322 e.WriteString("null") 323 return 324 } 325 b, err := m.MarshalText() 326 if err != nil { 327 e.error(&MarshalerError{Type: v.Type(), Err: err}) 328 } 329 e.Write(appendString(e.AvailableBuffer(), b, opts.escapeHTML)) 330 } 331 332 func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { 333 va := v.Addr() 334 if va.IsNil() { 335 e.WriteString("null") 336 return 337 } 338 m := va.Interface().(encoding.TextMarshaler) 339 b, err := m.MarshalText() 340 if err != nil { 341 e.error(&MarshalerError{Type: v.Type(), Err: err}) 342 } 343 e.Write(appendString(e.AvailableBuffer(), b, opts.escapeHTML)) 344 } 345 346 func boolEncoder(e *encodeState, v reflect.Value, opts encOpts) { 347 b := e.AvailableBuffer() 348 b = mayAppendQuote(b, opts.quoted) 349 b = strconv.AppendBool(b, v.Bool()) 350 b = mayAppendQuote(b, opts.quoted) 351 e.Write(b) 352 } 353 354 func intEncoder(e *encodeState, v reflect.Value, opts encOpts) { 355 b := e.AvailableBuffer() 356 b = mayAppendQuote(b, opts.quoted) 357 b = strconv.AppendInt(b, v.Int(), 10) 358 b = mayAppendQuote(b, opts.quoted) 359 e.Write(b) 360 } 361 362 func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) { 363 b := e.AvailableBuffer() 364 b = mayAppendQuote(b, opts.quoted) 365 b = strconv.AppendUint(b, v.Uint(), 10) 366 b = mayAppendQuote(b, opts.quoted) 367 e.Write(b) 368 } 369 370 type floatEncoder int // number of bits 371 372 func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { 373 f := v.Float() 374 if math.IsInf(f, 0) || math.IsNaN(f) { 375 e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))}) 376 } 377 378 // Convert as if by ES6 number to string conversion. 379 // This matches most other JSON generators. 380 // See golang.org/issue/6384 and golang.org/issue/14135. 381 // Like fmt %g, but the exponent cutoffs are different 382 // and exponents themselves are not padded to two digits. 383 b := e.AvailableBuffer() 384 b = mayAppendQuote(b, opts.quoted) 385 abs := math.Abs(f) 386 fmt := byte('f') 387 // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. 388 if abs != 0 { 389 if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { 390 fmt = 'e' 391 } 392 } 393 b = strconv.AppendFloat(b, f, fmt, -1, int(bits)) 394 if fmt == 'e' { 395 // clean up e-09 to e-9 396 n := len(b) 397 if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' { 398 b[n-2] = b[n-1] 399 b = b[:n-1] 400 } 401 } 402 b = mayAppendQuote(b, opts.quoted) 403 e.Write(b) 404 } 405 406 var ( 407 float32Encoder = (floatEncoder(32)).encode 408 float64Encoder = (floatEncoder(64)).encode 409 ) 410 411 func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) { 412 if v.Type() == numberType { 413 numStr := v.String() 414 // In Go1.5 the empty string encodes to "0", while this is not a valid number literal 415 // we keep compatibility so check validity after this. 416 if numStr == "" { 417 numStr = "0" // Number's zero-val 418 } 419 if !isValidNumber(numStr) { 420 e.error(fmt.Errorf("json: invalid number literal %q", numStr)) 421 } 422 b := e.AvailableBuffer() 423 b = mayAppendQuote(b, opts.quoted) 424 b = append(b, numStr...) 425 b = mayAppendQuote(b, opts.quoted) 426 e.Write(b) 427 return 428 } 429 // @diff 430 s := v.String() 431 var isUrl bool 432 if opts.truncateUrl { 433 u, err := url.Parse(s) 434 if err == nil && u.Scheme != "" { 435 isUrl = true 436 q := u.Query() 437 f := u.Fragment 438 u.Fragment = "" 439 if len(q) > 0 || len(f) > 0 { 440 u.RawQuery = "" 441 u.Fragment = "" 442 u.RawFragment = "" 443 st := u.String() 444 st += fmt.Sprintf(" ...%d chars", len(s)) 445 if len(q) > 0 { 446 st += fmt.Sprintf(",%dQ", len(q)) 447 } 448 if len(f) > 0 { 449 st += fmt.Sprintf("%dF", len(f)) 450 } 451 st += "]" 452 if len(st) < len(s) { 453 s = st 454 } 455 } 456 } 457 } 458 459 if limit := opts.truncateString; !isUrl && limit > 0 && len(s) > limit { 460 st := strings_.Truncate(s, limit) + fmt.Sprintf("...%d chars", len(s)) 461 if len(st) < len(s) { 462 s = st 463 } 464 } 465 if opts.quoted { 466 b := appendString(nil, s, opts.escapeHTML) 467 e.Write(appendString(e.AvailableBuffer(), b, false)) // no need to escape again since it is already escaped 468 } else { 469 e.Write(appendString(e.AvailableBuffer(), s, opts.escapeHTML)) 470 } 471 } 472 473 // isValidNumber reports whether s is a valid JSON number literal. 474 func isValidNumber(s string) bool { 475 // This function implements the JSON numbers grammar. 476 // See https://tools.ietf.org/html/rfc7159#section-6 477 // and https://www.json.org/img/number.png 478 479 if s == "" { 480 return false 481 } 482 483 // Optional - 484 if s[0] == '-' { 485 s = s[1:] 486 if s == "" { 487 return false 488 } 489 } 490 491 // Digits 492 switch { 493 default: 494 return false 495 496 case s[0] == '0': 497 s = s[1:] 498 499 case '1' <= s[0] && s[0] <= '9': 500 s = s[1:] 501 for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { 502 s = s[1:] 503 } 504 } 505 506 // . followed by 1 or more digits. 507 if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { 508 s = s[2:] 509 for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { 510 s = s[1:] 511 } 512 } 513 514 // e or E followed by an optional - or + and 515 // 1 or more digits. 516 if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { 517 s = s[1:] 518 if s[0] == '+' || s[0] == '-' { 519 s = s[1:] 520 if s == "" { 521 return false 522 } 523 } 524 for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { 525 s = s[1:] 526 } 527 } 528 529 // Make sure we are at the end. 530 return s == "" 531 } 532 533 func interfaceEncoder(e *encodeState, v reflect.Value, opts encOpts) { 534 if v.IsNil() { 535 e.WriteString("null") 536 return 537 } 538 e.reflectValue(v.Elem(), opts) 539 } 540 541 func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) { 542 e.error(&UnsupportedTypeError{v.Type()}) 543 } 544 545 type structEncoder struct { 546 fields structFields 547 } 548 549 type structFields struct { 550 list []field 551 byExactName map[string]*field 552 byFoldedName map[string]*field 553 } 554 555 func (se structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { 556 next := byte('{') 557 FieldLoop: 558 for i := range se.fields.list { 559 f := &se.fields.list[i] 560 561 // Find the nested struct field by following f.index. 562 fv := v 563 for _, i := range f.index { 564 if fv.Kind() == reflect.Pointer { 565 if fv.IsNil() { 566 continue FieldLoop 567 } 568 fv = fv.Elem() 569 } 570 fv = fv.Field(i) 571 } 572 573 // @diff 574 if (f.omitEmpty || opts.omitEmpty) && isEmptyValue(fv) { 575 continue 576 } 577 e.WriteByte(next) 578 next = ',' 579 if opts.escapeHTML { 580 e.WriteString(f.nameEscHTML) 581 } else { 582 e.WriteString(f.nameNonEsc) 583 } 584 opts.quoted = f.quoted 585 f.encoder(e, fv, opts) 586 } 587 if next == '{' { 588 e.WriteString("{}") 589 } else { 590 e.WriteByte('}') 591 } 592 } 593 594 func newStructEncoder(t reflect.Type) encoderFunc { 595 se := structEncoder{fields: cachedTypeFields(t)} 596 return se.encode 597 } 598 599 type mapEncoder struct { 600 elemEnc encoderFunc 601 } 602 603 func (me mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { 604 if v.IsNil() { 605 e.WriteString("null") 606 return 607 } 608 if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter { 609 // We're a large number of nested ptrEncoder.encode calls deep; 610 // start checking if we've run into a pointer cycle. 611 ptr := v.UnsafePointer() 612 if _, ok := e.ptrSeen[ptr]; ok { 613 e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())}) 614 } 615 e.ptrSeen[ptr] = struct{}{} 616 defer delete(e.ptrSeen, ptr) 617 } 618 e.WriteByte('{') 619 620 // Extract and sort the keys. 621 sv := make([]reflectWithString, v.Len()) 622 mi := v.MapRange() 623 for i := 0; mi.Next(); i++ { 624 sv[i].k = mi.Key() 625 sv[i].v = mi.Value() 626 if err := sv[i].resolve(); err != nil { 627 e.error(fmt.Errorf("json: encoding error for type %q: %q", v.Type().String(), err.Error())) 628 } 629 } 630 sort.Slice(sv, func(i, j int) bool { return sv[i].ks < sv[j].ks }) 631 632 // @diff 633 n := len(sv) 634 var m string 635 if limit := opts.truncateMap; limit > 0 && n > limit+1 { 636 m = fmt.Sprintf("...%d pairs", n) 637 n = limit 638 } 639 640 var j int 641 for i, kv := range sv { 642 if j >= n { 643 break 644 } 645 j++ 646 if i > 0 { 647 e.WriteByte(',') 648 } 649 e.Write(appendString(e.AvailableBuffer(), kv.ks, opts.escapeHTML)) 650 e.WriteByte(':') 651 me.elemEnc(e, kv.v, opts) 652 } 653 if m != "" { 654 if n > 0 { 655 e.WriteByte(',') 656 } 657 e.Write(appendString(e.AvailableBuffer(), m, opts.escapeHTML)) 658 e.WriteByte(':') 659 e.Write(appendString(e.AvailableBuffer(), fmt.Sprintf("%d", len(sv)), opts.escapeHTML)) 660 } 661 e.WriteByte('}') 662 e.ptrLevel-- 663 } 664 665 func newMapEncoder(t reflect.Type) encoderFunc { 666 switch t.Key().Kind() { 667 case reflect.String, 668 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 669 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 670 default: 671 if !t.Key().Implements(textMarshalerType) { 672 return unsupportedTypeEncoder 673 } 674 } 675 me := mapEncoder{typeEncoder(t.Elem())} 676 return me.encode 677 } 678 679 func encodeByteSlice(e *encodeState, v reflect.Value, opts encOpts) { 680 if v.IsNil() { 681 e.WriteString("null") 682 return 683 } 684 s := v.Bytes() 685 // @diff 686 687 var m string 688 var st []byte 689 var encodedLenT int 690 encodedLenS := base64.StdEncoding.EncodedLen(len(s)) 691 if limit := opts.truncateBytes; limit > 0 && len(s) > limit { 692 m = fmt.Sprintf("...%d bytes", len(s)) 693 st = bytes_.Truncate(s, limit) 694 encodedLenT = base64.StdEncoding.EncodedLen(len(st)) 695 } 696 var encodedLen int 697 if m != "" && len(m)+encodedLenT < encodedLenS { 698 encodedLen = encodedLenT 699 s = st 700 } else { 701 encodedLen = encodedLenS 702 m = "" 703 } 704 705 e.Grow(len(`"`) + encodedLen + len(`"`)) 706 707 // TODO(https://go.dev/issue/53693): Use base64.Encoding.AppendEncode. 708 b := e.AvailableBuffer() 709 b = append(b, '"') 710 base64.StdEncoding.Encode(b[len(b):][:encodedLen], s) 711 b = b[:len(b)+encodedLen] 712 b = append(b, m...) 713 b = append(b, '"') 714 e.Write(b) 715 } 716 717 // sliceEncoder just wraps an arrayEncoder, checking to make sure the value isn't nil. 718 type sliceEncoder struct { 719 arrayEnc encoderFunc 720 } 721 722 func (se sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { 723 if v.IsNil() { 724 e.WriteString("null") 725 return 726 } 727 if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter { 728 // We're a large number of nested ptrEncoder.encode calls deep; 729 // start checking if we've run into a pointer cycle. 730 // Here we use a struct to memorize the pointer to the first element of the slice 731 // and its length. 732 ptr := struct { 733 ptr any // always an unsafe.Pointer, but avoids a dependency on package unsafe 734 len int 735 }{v.UnsafePointer(), v.Len()} 736 if _, ok := e.ptrSeen[ptr]; ok { 737 e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())}) 738 } 739 e.ptrSeen[ptr] = struct{}{} 740 defer delete(e.ptrSeen, ptr) 741 } 742 se.arrayEnc(e, v, opts) 743 e.ptrLevel-- 744 } 745 746 func newSliceEncoder(t reflect.Type) encoderFunc { 747 // Byte slices get special treatment; arrays don't. 748 if t.Elem().Kind() == reflect.Uint8 { 749 p := reflect.PointerTo(t.Elem()) 750 if !p.Implements(marshalerType) && !p.Implements(textMarshalerType) { 751 return encodeByteSlice 752 } 753 } 754 enc := sliceEncoder{newArrayEncoder(t)} 755 return enc.encode 756 } 757 758 type arrayEncoder struct { 759 elemEnc encoderFunc 760 } 761 762 func (ae arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { 763 e.WriteByte('[') 764 n := v.Len() 765 var m string 766 if limit := opts.truncateSliceOrArray; limit > 0 && n > limit+1 { 767 m = fmt.Sprintf(", \"...%d elems\"", n) 768 n = limit 769 } 770 for i := 0; i < n; i++ { 771 if i > 0 { 772 e.WriteByte(',') 773 } 774 ae.elemEnc(e, v.Index(i), opts) 775 } 776 if m != "" { 777 e.WriteString(m) 778 } 779 e.WriteByte(']') 780 } 781 782 func newArrayEncoder(t reflect.Type) encoderFunc { 783 enc := arrayEncoder{typeEncoder(t.Elem())} 784 return enc.encode 785 } 786 787 type ptrEncoder struct { 788 elemEnc encoderFunc 789 } 790 791 func (pe ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { 792 if v.IsNil() { 793 e.WriteString("null") 794 return 795 } 796 if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter { 797 // We're a large number of nested ptrEncoder.encode calls deep; 798 // start checking if we've run into a pointer cycle. 799 ptr := v.Interface() 800 if _, ok := e.ptrSeen[ptr]; ok { 801 e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())}) 802 } 803 e.ptrSeen[ptr] = struct{}{} 804 defer delete(e.ptrSeen, ptr) 805 } 806 pe.elemEnc(e, v.Elem(), opts) 807 e.ptrLevel-- 808 } 809 810 func newPtrEncoder(t reflect.Type) encoderFunc { 811 enc := ptrEncoder{typeEncoder(t.Elem())} 812 return enc.encode 813 } 814 815 type condAddrEncoder struct { 816 canAddrEnc, elseEnc encoderFunc 817 } 818 819 func (ce condAddrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { 820 if v.CanAddr() { 821 ce.canAddrEnc(e, v, opts) 822 } else { 823 ce.elseEnc(e, v, opts) 824 } 825 } 826 827 // newCondAddrEncoder returns an encoder that checks whether its value 828 // CanAddr and delegates to canAddrEnc if so, else to elseEnc. 829 func newCondAddrEncoder(canAddrEnc, elseEnc encoderFunc) encoderFunc { 830 enc := condAddrEncoder{canAddrEnc: canAddrEnc, elseEnc: elseEnc} 831 return enc.encode 832 } 833 834 func isValidTag(s string) bool { 835 if s == "" { 836 return false 837 } 838 for _, c := range s { 839 switch { 840 case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c): 841 // Backslash and quote chars are reserved, but 842 // otherwise any punctuation chars are allowed 843 // in a tag name. 844 case !unicode.IsLetter(c) && !unicode.IsDigit(c): 845 return false 846 } 847 } 848 return true 849 } 850 851 func typeByIndex(t reflect.Type, index []int) reflect.Type { 852 for _, i := range index { 853 if t.Kind() == reflect.Pointer { 854 t = t.Elem() 855 } 856 t = t.Field(i).Type 857 } 858 return t 859 } 860 861 type reflectWithString struct { 862 k reflect.Value 863 v reflect.Value 864 ks string 865 } 866 867 func (w *reflectWithString) resolve() error { 868 if w.k.Kind() == reflect.String { 869 w.ks = w.k.String() 870 return nil 871 } 872 if tm, ok := w.k.Interface().(encoding.TextMarshaler); ok { 873 if w.k.Kind() == reflect.Pointer && w.k.IsNil() { 874 return nil 875 } 876 buf, err := tm.MarshalText() 877 w.ks = string(buf) 878 return err 879 } 880 switch w.k.Kind() { 881 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 882 w.ks = strconv.FormatInt(w.k.Int(), 10) 883 return nil 884 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 885 w.ks = strconv.FormatUint(w.k.Uint(), 10) 886 return nil 887 } 888 panic("unexpected map key type") 889 } 890 891 func appendString[Bytes []byte | string](dst []byte, src Bytes, escapeHTML bool) []byte { 892 dst = append(dst, '"') 893 start := 0 894 for i := 0; i < len(src); { 895 if b := src[i]; b < utf8.RuneSelf { 896 if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) { 897 i++ 898 continue 899 } 900 dst = append(dst, src[start:i]...) 901 switch b { 902 case '\\', '"': 903 dst = append(dst, '\\', b) 904 case '\n': 905 dst = append(dst, '\\', 'n') 906 case '\r': 907 dst = append(dst, '\\', 'r') 908 case '\t': 909 dst = append(dst, '\\', 't') 910 default: 911 // This encodes bytes < 0x20 except for \t, \n and \r. 912 // If escapeHTML is set, it also escapes <, >, and & 913 // because they can lead to security holes when 914 // user-controlled strings are rendered into JSON 915 // and served to some browsers. 916 dst = append(dst, '\\', 'u', '0', '0', hex[b>>4], hex[b&0xF]) 917 } 918 i++ 919 start = i 920 continue 921 } 922 // TODO(https://go.dev/issue/56948): Use generic utf8 functionality. 923 // For now, cast only a small portion of byte slices to a string 924 // so that it can be stack allocated. This slows down []byte slightly 925 // due to the extra copy, but keeps string performance roughly the same. 926 n := len(src) - i 927 if n > utf8.UTFMax { 928 n = utf8.UTFMax 929 } 930 c, size := utf8.DecodeRuneInString(string(src[i : i+n])) 931 if c == utf8.RuneError && size == 1 { 932 dst = append(dst, src[start:i]...) 933 dst = append(dst, `\ufffd`...) 934 i += size 935 start = i 936 continue 937 } 938 // U+2028 is LINE SEPARATOR. 939 // U+2029 is PARAGRAPH SEPARATOR. 940 // They are both technically valid characters in JSON strings, 941 // but don't work in JSONP, which has to be evaluated as JavaScript, 942 // and can lead to security holes there. It is valid JSON to 943 // escape them, so we do so unconditionally. 944 // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. 945 if c == '\u2028' || c == '\u2029' { 946 dst = append(dst, src[start:i]...) 947 dst = append(dst, '\\', 'u', '2', '0', '2', hex[c&0xF]) 948 i += size 949 start = i 950 continue 951 } 952 i += size 953 } 954 dst = append(dst, src[start:]...) 955 dst = append(dst, '"') 956 return dst 957 } 958 959 // A field represents a single field found in a struct. 960 type field struct { 961 name string 962 nameBytes []byte // []byte(name) 963 964 nameNonEsc string // `"` + name + `":` 965 nameEscHTML string // `"` + HTMLEscape(name) + `":` 966 967 tag bool 968 index []int 969 typ reflect.Type 970 omitEmpty bool 971 quoted bool 972 973 encoder encoderFunc 974 } 975 976 // byIndex sorts field by index sequence. 977 type byIndex []field 978 979 func (x byIndex) Len() int { return len(x) } 980 981 func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 982 983 func (x byIndex) Less(i, j int) bool { 984 for k, xik := range x[i].index { 985 if k >= len(x[j].index) { 986 return false 987 } 988 if xik != x[j].index[k] { 989 return xik < x[j].index[k] 990 } 991 } 992 return len(x[i].index) < len(x[j].index) 993 } 994 995 // typeFields returns a list of fields that JSON should recognize for the given type. 996 // The algorithm is breadth-first search over the set of structs to include - the top struct 997 // and then any reachable anonymous structs. 998 func typeFields(t reflect.Type) structFields { 999 // Anonymous fields to explore at the current level and the next. 1000 current := []field{} 1001 next := []field{{typ: t}} 1002 1003 // Count of queued names for current level and the next. 1004 var count, nextCount map[reflect.Type]int 1005 1006 // Types already visited at an earlier level. 1007 visited := map[reflect.Type]bool{} 1008 1009 // Fields found. 1010 var fields []field 1011 1012 // Buffer to run appendHTMLEscape on field names. 1013 var nameEscBuf []byte 1014 1015 for len(next) > 0 { 1016 current, next = next, current[:0] 1017 count, nextCount = nextCount, map[reflect.Type]int{} 1018 1019 for _, f := range current { 1020 if visited[f.typ] { 1021 continue 1022 } 1023 visited[f.typ] = true 1024 1025 // Scan f.typ for fields to include. 1026 for i := 0; i < f.typ.NumField(); i++ { 1027 sf := f.typ.Field(i) 1028 if sf.Anonymous { 1029 t := sf.Type 1030 if t.Kind() == reflect.Pointer { 1031 t = t.Elem() 1032 } 1033 if !sf.IsExported() && t.Kind() != reflect.Struct { 1034 // Ignore embedded fields of unexported non-struct types. 1035 continue 1036 } 1037 // Do not ignore embedded fields of unexported struct types 1038 // since they may have exported fields. 1039 } else if !sf.IsExported() { 1040 // Ignore unexported non-embedded fields. 1041 continue 1042 } 1043 tag := sf.Tag.Get("json") 1044 if tag == "-" { 1045 continue 1046 } 1047 name, opts := parseTag(tag) 1048 if !isValidTag(name) { 1049 name = "" 1050 } 1051 index := make([]int, len(f.index)+1) 1052 copy(index, f.index) 1053 index[len(f.index)] = i 1054 1055 ft := sf.Type 1056 if ft.Name() == "" && ft.Kind() == reflect.Pointer { 1057 // Follow pointer. 1058 ft = ft.Elem() 1059 } 1060 1061 // Only strings, floats, integers, and booleans can be quoted. 1062 quoted := false 1063 if opts.Contains("string") { 1064 switch ft.Kind() { 1065 case reflect.Bool, 1066 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 1067 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, 1068 reflect.Float32, reflect.Float64, 1069 reflect.String: 1070 quoted = true 1071 } 1072 } 1073 1074 // Record found field and index sequence. 1075 if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { 1076 tagged := name != "" 1077 if name == "" { 1078 name = sf.Name 1079 } 1080 field := field{ 1081 name: name, 1082 tag: tagged, 1083 index: index, 1084 typ: ft, 1085 omitEmpty: opts.Contains("omitempty"), 1086 quoted: quoted, 1087 } 1088 field.nameBytes = []byte(field.name) 1089 1090 // Build nameEscHTML and nameNonEsc ahead of time. 1091 nameEscBuf = appendHTMLEscape(nameEscBuf[:0], field.nameBytes) 1092 field.nameEscHTML = `"` + string(nameEscBuf) + `":` 1093 field.nameNonEsc = `"` + field.name + `":` 1094 1095 fields = append(fields, field) 1096 if count[f.typ] > 1 { 1097 // If there were multiple instances, add a second, 1098 // so that the annihilation code will see a duplicate. 1099 // It only cares about the distinction between 1 or 2, 1100 // so don't bother generating any more copies. 1101 fields = append(fields, fields[len(fields)-1]) 1102 } 1103 continue 1104 } 1105 1106 // Record new anonymous struct to explore in next round. 1107 nextCount[ft]++ 1108 if nextCount[ft] == 1 { 1109 next = append(next, field{name: ft.Name(), index: index, typ: ft}) 1110 } 1111 } 1112 } 1113 } 1114 1115 sort.Slice(fields, func(i, j int) bool { 1116 x := fields 1117 // sort field by name, breaking ties with depth, then 1118 // breaking ties with "name came from json tag", then 1119 // breaking ties with index sequence. 1120 if x[i].name != x[j].name { 1121 return x[i].name < x[j].name 1122 } 1123 if len(x[i].index) != len(x[j].index) { 1124 return len(x[i].index) < len(x[j].index) 1125 } 1126 if x[i].tag != x[j].tag { 1127 return x[i].tag 1128 } 1129 return byIndex(x).Less(i, j) 1130 }) 1131 1132 // Delete all fields that are hidden by the Go rules for embedded fields, 1133 // except that fields with JSON tags are promoted. 1134 1135 // The fields are sorted in primary order of name, secondary order 1136 // of field index length. Loop over names; for each name, delete 1137 // hidden fields by choosing the one dominant field that survives. 1138 out := fields[:0] 1139 for advance, i := 0, 0; i < len(fields); i += advance { 1140 // One iteration per name. 1141 // Find the sequence of fields with the name of this first field. 1142 fi := fields[i] 1143 name := fi.name 1144 for advance = 1; i+advance < len(fields); advance++ { 1145 fj := fields[i+advance] 1146 if fj.name != name { 1147 break 1148 } 1149 } 1150 if advance == 1 { // Only one field with this name 1151 out = append(out, fi) 1152 continue 1153 } 1154 dominant, ok := dominantField(fields[i : i+advance]) 1155 if ok { 1156 out = append(out, dominant) 1157 } 1158 } 1159 1160 fields = out 1161 sort.Sort(byIndex(fields)) 1162 1163 for i := range fields { 1164 f := &fields[i] 1165 f.encoder = typeEncoder(typeByIndex(t, f.index)) 1166 } 1167 exactNameIndex := make(map[string]*field, len(fields)) 1168 foldedNameIndex := make(map[string]*field, len(fields)) 1169 for i, field := range fields { 1170 exactNameIndex[field.name] = &fields[i] 1171 // For historical reasons, first folded match takes precedence. 1172 if _, ok := foldedNameIndex[string(foldName(field.nameBytes))]; !ok { 1173 foldedNameIndex[string(foldName(field.nameBytes))] = &fields[i] 1174 } 1175 } 1176 return structFields{fields, exactNameIndex, foldedNameIndex} 1177 } 1178 1179 // dominantField looks through the fields, all of which are known to 1180 // have the same name, to find the single field that dominates the 1181 // others using Go's embedding rules, modified by the presence of 1182 // JSON tags. If there are multiple top-level fields, the boolean 1183 // will be false: This condition is an error in Go and we skip all 1184 // the fields. 1185 func dominantField(fields []field) (field, bool) { 1186 // The fields are sorted in increasing index-length order, then by presence of tag. 1187 // That means that the first field is the dominant one. We need only check 1188 // for error cases: two fields at top level, either both tagged or neither tagged. 1189 if len(fields) > 1 && len(fields[0].index) == len(fields[1].index) && fields[0].tag == fields[1].tag { 1190 return field{}, false 1191 } 1192 return fields[0], true 1193 } 1194 1195 var fieldCache sync.Map // map[reflect.Type]structFields 1196 1197 // cachedTypeFields is like typeFields but uses a cache to avoid repeated work. 1198 func cachedTypeFields(t reflect.Type) structFields { 1199 if f, ok := fieldCache.Load(t); ok { 1200 return f.(structFields) 1201 } 1202 f, _ := fieldCache.LoadOrStore(t, typeFields(t)) 1203 return f.(structFields) 1204 } 1205 1206 func mayAppendQuote(b []byte, quoted bool) []byte { 1207 if quoted { 1208 b = append(b, '"') 1209 } 1210 return b 1211 }