codekingpro/portable-devtools
114k
1// Copyright 2010 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5//go:build !goexperiment.jsonv26 7// Package json implements encoding and decoding of JSON as defined in RFC 7159.8// The mapping between JSON and Go values is described in the documentation for9// the Marshal and Unmarshal functions.10//11// See "JSON and Go" for an introduction to this package:12// https://golang.org/doc/articles/json_and_go.html13//14// # Security Considerations15//16// The JSON standard (RFC 7159) is lax in its definition of a number of parser17// behaviors. As such, many JSON parsers behave differently in various18// scenarios. These differences in parsers mean that systems that use multiple19// independent JSON parser implementations may parse the same JSON object in20// differing ways.21//22// Systems that rely on a JSON object being parsed consistently for security23// purposes should be careful to understand the behaviors of this parser, as24// well as how these behaviors may cause interoperability issues with other25// parser implementations.26//27// Due to the Go Backwards Compatibility promise (https://go.dev/doc/go1compat)28// there are a number of behaviors this package exhibits that may cause29// interopability issues, but cannot be changed. In particular the following30// parsing behaviors may cause issues:31//32// - If a JSON object contains duplicate keys, keys are processed in the order33// they are observed, meaning later values will replace or be merged into34// prior values, depending on the field type (in particular maps and structs35// will have values merged, while other types have values replaced).36// - When parsing a JSON object into a Go struct, keys are considered in a37// case-insensitive fashion.38// - When parsing a JSON object into a Go struct, unknown keys in the JSON39// object are ignored (unless a [Decoder] is used and40// [Decoder.DisallowUnknownFields] has been called).41// - Invalid UTF-8 bytes in JSON strings are replaced by the Unicode42// replacement character.43// - Large JSON number integers will lose precision when unmarshaled into44// floating-point types.45package json46 47import (48 "bytes"49 "cmp"50 "encoding"51 "encoding/base64"52 "fmt"53 "math"54 "reflect"55 "slices"56 "strconv"57 "strings"58 "sync"59 "unicode"60 "unicode/utf8"61 _ "unsafe" // for linkname62)63 64// Marshal returns the JSON encoding of v.65//66// Marshal traverses the value v recursively.67// If an encountered value implements [Marshaler]68// and is not a nil pointer, Marshal calls [Marshaler.MarshalJSON]69// to produce JSON. If no [Marshaler.MarshalJSON] method is present but the70// value implements [encoding.TextMarshaler] instead, Marshal calls71// [encoding.TextMarshaler.MarshalText] and encodes the result as a JSON string.72// The nil pointer exception is not strictly necessary73// but mimics a similar, necessary exception in the behavior of74// [Unmarshaler.UnmarshalJSON].75//76// Otherwise, Marshal uses the following type-dependent default encodings:77//78// Boolean values encode as JSON booleans.79//80// Floating point, integer, and [Number] values encode as JSON numbers.81// NaN and +/-Inf values will return an [UnsupportedValueError].82//83// String values encode as JSON strings coerced to valid UTF-8,84// replacing invalid bytes with the Unicode replacement rune.85// So that the JSON will be safe to embed inside HTML <script> tags,86// the string is encoded using [HTMLEscape],87// which replaces "<", ">", "&", U+2028, and U+2029 are escaped88// to "\u003c","\u003e", "\u0026", "\u2028", and "\u2029".89// This replacement can be disabled when using an [Encoder],90// by calling [Encoder.SetEscapeHTML](false).91//92// Array and slice values encode as JSON arrays, except that93// []byte encodes as a base64-encoded string, and a nil slice94// encodes as the null JSON value.95//96// Struct values encode as JSON objects.97// Each exported struct field becomes a member of the object, using the98// field name as the object key, unless the field is omitted for one of the99// reasons given below.100//101// The encoding of each struct field can be customized by the format string102// stored under the "json" key in the struct field's tag.103// The format string gives the name of the field, possibly followed by a104// comma-separated list of options. The name may be empty in order to105// specify options without overriding the default field name.106//107// The "omitempty" option specifies that the field should be omitted108// from the encoding if the field has an empty value, defined as109// false, 0, a nil pointer, a nil interface value, and any array,110// slice, map, or string of length zero.111//112// As a special case, if the field tag is "-", the field is always omitted.113// Note that a field with name "-" can still be generated using the tag "-,".114//115// Examples of struct field tags and their meanings:116//117// // Field appears in JSON as key "myName".118// Field int `json:"myName"`119//120// // Field appears in JSON as key "myName" and121// // the field is omitted from the object if its value is empty,122// // as defined above.123// Field int `json:"myName,omitempty"`124//125// // Field appears in JSON as key "Field" (the default), but126// // the field is skipped if empty.127// // Note the leading comma.128// Field int `json:",omitempty"`129//130// // Field is ignored by this package.131// Field int `json:"-"`132//133// // Field appears in JSON as key "-".134// Field int `json:"-,"`135//136// The "omitzero" option specifies that the field should be omitted137// from the encoding if the field has a zero value, according to rules:138//139// 1) If the field type has an "IsZero() bool" method, that will be used to140// determine whether the value is zero.141//142// 2) Otherwise, the value is zero if it is the zero value for its type.143//144// If both "omitempty" and "omitzero" are specified, the field will be omitted145// if the value is either empty or zero (or both).146//147// The "string" option signals that a field is stored as JSON inside a148// JSON-encoded string. It applies only to fields of string, floating point,149// integer, or boolean types. This extra level of encoding is sometimes used150// when communicating with JavaScript programs:151//152// Int64String int64 `json:",string"`153//154// The key name will be used if it's a non-empty string consisting of155// only Unicode letters, digits, and ASCII punctuation except quotation156// marks, backslash, and comma.157//158// Embedded struct fields are usually marshaled as if their inner exported fields159// were fields in the outer struct, subject to the usual Go visibility rules amended160// as described in the next paragraph.161// An anonymous struct field with a name given in its JSON tag is treated as162// having that name, rather than being anonymous.163// An anonymous struct field of interface type is treated the same as having164// that type as its name, rather than being anonymous.165//166// The Go visibility rules for struct fields are amended for JSON when167// deciding which field to marshal or unmarshal. If there are168// multiple fields at the same level, and that level is the least169// nested (and would therefore be the nesting level selected by the170// usual Go rules), the following extra rules apply:171//172// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered,173// even if there are multiple untagged fields that would otherwise conflict.174//175// 2) If there is exactly one field (tagged or not according to the first rule), that is selected.176//177// 3) Otherwise there are multiple fields, and all are ignored; no error occurs.178//179// Handling of anonymous struct fields is new in Go 1.1.180// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of181// an anonymous struct field in both current and earlier versions, give the field182// a JSON tag of "-".183//184// Map values encode as JSON objects. The map's key type must either be a185// string, an integer type, or implement [encoding.TextMarshaler]. The map keys186// are sorted and used as JSON object keys by applying the following rules,187// subject to the UTF-8 coercion described for string values above:188// - keys of any string type are used directly189// - keys that implement [encoding.TextMarshaler] are marshaled190// - integer keys are converted to strings191//192// Pointer values encode as the value pointed to.193// A nil pointer encodes as the null JSON value.194//195// Interface values encode as the value contained in the interface.196// A nil interface value encodes as the null JSON value.197//198// Channel, complex, and function values cannot be encoded in JSON.199// Attempting to encode such a value causes Marshal to return200// an [UnsupportedTypeError].201//202// JSON cannot represent cyclic data structures and Marshal does not203// handle them. Passing cyclic structures to Marshal will result in204// an error.205func Marshal(v any) ([]byte, error) {206 e := newEncodeState()207 defer encodeStatePool.Put(e)208 209 err := e.marshal(v, encOpts{escapeHTML: true})210 if err != nil {211 return nil, err212 }213 buf := append([]byte(nil), e.Bytes()...)214 215 return buf, nil216}217 218// MarshalIndent is like [Marshal] but applies [Indent] to format the output.219// Each JSON element in the output will begin on a new line beginning with prefix220// followed by one or more copies of indent according to the indentation nesting.221func MarshalIndent(v any, prefix, indent string) ([]byte, error) {222 b, err := Marshal(v)223 if err != nil {224 return nil, err225 }226 b2 := make([]byte, 0, indentGrowthFactor*len(b))227 b2, err = appendIndent(b2, b, prefix, indent)228 if err != nil {229 return nil, err230 }231 return b2, nil232}233 234// Marshaler is the interface implemented by types that235// can marshal themselves into valid JSON.236type Marshaler interface {237 MarshalJSON() ([]byte, error)238}239 240// An UnsupportedTypeError is returned by [Marshal] when attempting241// to encode an unsupported value type.242type UnsupportedTypeError struct {243 Type reflect.Type244}245 246func (e *UnsupportedTypeError) Error() string {247 return "json: unsupported type: " + e.Type.String()248}249 250// An UnsupportedValueError is returned by [Marshal] when attempting251// to encode an unsupported value.252type UnsupportedValueError struct {253 Value reflect.Value254 Str string255}256 257func (e *UnsupportedValueError) Error() string {258 return "json: unsupported value: " + e.Str259}260 261// Before Go 1.2, an InvalidUTF8Error was returned by [Marshal] when262// attempting to encode a string value with invalid UTF-8 sequences.263// As of Go 1.2, [Marshal] instead coerces the string to valid UTF-8 by264// replacing invalid bytes with the Unicode replacement rune U+FFFD.265//266// Deprecated: No longer used; kept for compatibility.267type InvalidUTF8Error struct {268 S string // the whole string value that caused the error269}270 271func (e *InvalidUTF8Error) Error() string {272 return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)273}274 275// A MarshalerError represents an error from calling a276// [Marshaler.MarshalJSON] or [encoding.TextMarshaler.MarshalText] method.277type MarshalerError struct {278 Type reflect.Type279 Err error280 sourceFunc string281}282 283func (e *MarshalerError) Error() string {284 srcFunc := e.sourceFunc285 if srcFunc == "" {286 srcFunc = "MarshalJSON"287 }288 return "json: error calling " + srcFunc +289 " for type " + e.Type.String() +290 ": " + e.Err.Error()291}292 293// Unwrap returns the underlying error.294func (e *MarshalerError) Unwrap() error { return e.Err }295 296const hex = "0123456789abcdef"297 298// An encodeState encodes JSON into a bytes.Buffer.299type encodeState struct {300 bytes.Buffer // accumulated output301 302 // Keep track of what pointers we've seen in the current recursive call303 // path, to avoid cycles that could lead to a stack overflow. Only do304 // the relatively expensive map operations if ptrLevel is larger than305 // startDetectingCyclesAfter, so that we skip the work if we're within a306 // reasonable amount of nested pointers deep.307 ptrLevel uint308 ptrSeen map[any]struct{}309}310 311const startDetectingCyclesAfter = 1000312 313var encodeStatePool sync.Pool314 315func newEncodeState() *encodeState {316 if v := encodeStatePool.Get(); v != nil {317 e := v.(*encodeState)318 e.Reset()319 if len(e.ptrSeen) > 0 {320 panic("ptrEncoder.encode should have emptied ptrSeen via defers")321 }322 e.ptrLevel = 0323 return e324 }325 return &encodeState{ptrSeen: make(map[any]struct{})}326}327 328// jsonError is an error wrapper type for internal use only.329// Panics with errors are wrapped in jsonError so that the top-level recover330// can distinguish intentional panics from this package.331type jsonError struct{ error }332 333func (e *encodeState) marshal(v any, opts encOpts) (err error) {334 defer func() {335 if r := recover(); r != nil {336 if je, ok := r.(jsonError); ok {337 err = je.error338 } else {339 panic(r)340 }341 }342 }()343 e.reflectValue(reflect.ValueOf(v), opts)344 return nil345}346 347// error aborts the encoding by panicking with err wrapped in jsonError.348func (e *encodeState) error(err error) {349 panic(jsonError{err})350}351 352func isEmptyValue(v reflect.Value) bool {353 switch v.Kind() {354 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:355 return v.Len() == 0356 case reflect.Bool,357 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,358 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,359 reflect.Float32, reflect.Float64,360 reflect.Interface, reflect.Pointer:361 return v.IsZero()362 }363 return false364}365 366func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) {367 valueEncoder(v)(e, v, opts)368}369 370type encOpts struct {371 // quoted causes primitive fields to be encoded inside JSON strings.372 quoted bool373 // escapeHTML causes '<', '>', and '&' to be escaped in JSON strings.374 escapeHTML bool375}376 377type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts)378 379var encoderCache sync.Map // map[reflect.Type]encoderFunc380 381func valueEncoder(v reflect.Value) encoderFunc {382 if !v.IsValid() {383 return invalidValueEncoder384 }385 return typeEncoder(v.Type())386}387 388func typeEncoder(t reflect.Type) encoderFunc {389 if fi, ok := encoderCache.Load(t); ok {390 return fi.(encoderFunc)391 }392 393 // To deal with recursive types, populate the map with an394 // indirect func before we build it. If the type is recursive,395 // the second lookup for the type will return the indirect func.396 //397 // This indirect func is only used for recursive types,398 // and briefly during racing calls to typeEncoder.399 indirect := sync.OnceValue(func() encoderFunc {400 return newTypeEncoder(t, true)401 })402 fi, loaded := encoderCache.LoadOrStore(t, encoderFunc(func(e *encodeState, v reflect.Value, opts encOpts) {403 indirect()(e, v, opts)404 }))405 if loaded {406 return fi.(encoderFunc)407 }408 409 f := indirect()410 encoderCache.Store(t, f)411 return f412}413 414var (415 marshalerType = reflect.TypeFor[Marshaler]()416 textMarshalerType = reflect.TypeFor[encoding.TextMarshaler]()417)418 419// newTypeEncoder constructs an encoderFunc for a type.420// The returned encoder only checks CanAddr when allowAddr is true.421func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {422 // If we have a non-pointer value whose type implements423 // Marshaler with a value receiver, then we're better off taking424 // the address of the value - otherwise we end up with an425 // allocation as we cast the value to an interface.426 if t.Kind() != reflect.Pointer && allowAddr && reflect.PointerTo(t).Implements(marshalerType) {427 return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false))428 }429 if t.Implements(marshalerType) {430 return marshalerEncoder431 }432 if t.Kind() != reflect.Pointer && allowAddr && reflect.PointerTo(t).Implements(textMarshalerType) {433 return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false))434 }435 if t.Implements(textMarshalerType) {436 return textMarshalerEncoder437 }438 439 switch t.Kind() {440 case reflect.Bool:441 return boolEncoder442 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:443 return intEncoder444 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:445 return uintEncoder446 case reflect.Float32:447 return float32Encoder448 case reflect.Float64:449 return float64Encoder450 case reflect.String:451 return stringEncoder452 case reflect.Interface:453 return interfaceEncoder454 case reflect.Struct:455 return newStructEncoder(t)456 case reflect.Map:457 return newMapEncoder(t)458 case reflect.Slice:459 return newSliceEncoder(t)460 case reflect.Array:461 return newArrayEncoder(t)462 case reflect.Pointer:463 return newPtrEncoder(t)464 default:465 return unsupportedTypeEncoder466 }467}468 469func invalidValueEncoder(e *encodeState, v reflect.Value, _ encOpts) {470 e.WriteString("null")471}472 473func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {474 if v.Kind() == reflect.Pointer && v.IsNil() {475 e.WriteString("null")476 return477 }478 m, ok := reflect.TypeAssert[Marshaler](v)479 if !ok {480 e.WriteString("null")481 return482 }483 b, err := m.MarshalJSON()484 if err == nil {485 e.Grow(len(b))486 out := e.AvailableBuffer()487 out, err = appendCompact(out, b, opts.escapeHTML)488 e.Buffer.Write(out)489 }490 if err != nil {491 e.error(&MarshalerError{v.Type(), err, "MarshalJSON"})492 }493}494 495func addrMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {496 va := v.Addr()497 if va.IsNil() {498 e.WriteString("null")499 return500 }501 m, _ := reflect.TypeAssert[Marshaler](va)502 b, err := m.MarshalJSON()503 if err == nil {504 e.Grow(len(b))505 out := e.AvailableBuffer()506 out, err = appendCompact(out, b, opts.escapeHTML)507 e.Buffer.Write(out)508 }509 if err != nil {510 e.error(&MarshalerError{v.Type(), err, "MarshalJSON"})511 }512}513 514func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {515 if v.Kind() == reflect.Pointer && v.IsNil() {516 e.WriteString("null")517 return518 }519 m, ok := reflect.TypeAssert[encoding.TextMarshaler](v)520 if !ok {521 e.WriteString("null")522 return523 }524 b, err := m.MarshalText()525 if err != nil {526 e.error(&MarshalerError{v.Type(), err, "MarshalText"})527 }528 e.Write(appendString(e.AvailableBuffer(), b, opts.escapeHTML))529}530 531func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {532 va := v.Addr()533 if va.IsNil() {534 e.WriteString("null")535 return536 }537 m, _ := reflect.TypeAssert[encoding.TextMarshaler](va)538 b, err := m.MarshalText()539 if err != nil {540 e.error(&MarshalerError{v.Type(), err, "MarshalText"})541 }542 e.Write(appendString(e.AvailableBuffer(), b, opts.escapeHTML))543}544 545func boolEncoder(e *encodeState, v reflect.Value, opts encOpts) {546 b := e.AvailableBuffer()547 b = mayAppendQuote(b, opts.quoted)548 b = strconv.AppendBool(b, v.Bool())549 b = mayAppendQuote(b, opts.quoted)550 e.Write(b)551}552 553func intEncoder(e *encodeState, v reflect.Value, opts encOpts) {554 b := e.AvailableBuffer()555 b = mayAppendQuote(b, opts.quoted)556 b = strconv.AppendInt(b, v.Int(), 10)557 b = mayAppendQuote(b, opts.quoted)558 e.Write(b)559}560 561func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) {562 b := e.AvailableBuffer()563 b = mayAppendQuote(b, opts.quoted)564 b = strconv.AppendUint(b, v.Uint(), 10)565 b = mayAppendQuote(b, opts.quoted)566 e.Write(b)567}568 569type floatEncoder int // number of bits570 571func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {572 f := v.Float()573 if math.IsInf(f, 0) || math.IsNaN(f) {574 e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))})575 }576 577 // Convert as if by ES6 number to string conversion.578 // This matches most other JSON generators.579 // See golang.org/issue/6384 and golang.org/issue/14135.580 // Like fmt %g, but the exponent cutoffs are different581 // and exponents themselves are not padded to two digits.582 b := e.AvailableBuffer()583 b = mayAppendQuote(b, opts.quoted)584 abs := math.Abs(f)585 fmt := byte('f')586 // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.587 if abs != 0 {588 if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {589 fmt = 'e'590 }591 }592 b = strconv.AppendFloat(b, f, fmt, -1, int(bits))593 if fmt == 'e' {594 // clean up e-09 to e-9595 n := len(b)596 if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' {597 b[n-2] = b[n-1]598 b = b[:n-1]599 }600 }601 b = mayAppendQuote(b, opts.quoted)602 e.Write(b)603}604 605var (606 float32Encoder = (floatEncoder(32)).encode607 float64Encoder = (floatEncoder(64)).encode608)609 610func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) {611 if v.Type() == numberType {612 numStr := v.String()613 // In Go1.5 the empty string encodes to "0", while this is not a valid number literal614 // we keep compatibility so check validity after this.615 if numStr == "" {616 numStr = "0" // Number's zero-val617 }618 if !isValidNumber(numStr) {619 e.error(fmt.Errorf("json: invalid number literal %q", numStr))620 }621 b := e.AvailableBuffer()622 b = mayAppendQuote(b, opts.quoted)623 b = append(b, numStr...)624 b = mayAppendQuote(b, opts.quoted)625 e.Write(b)626 return627 }628 if opts.quoted {629 b := appendString(nil, v.String(), opts.escapeHTML)630 e.Write(appendString(e.AvailableBuffer(), b, false)) // no need to escape again since it is already escaped631 } else {632 e.Write(appendString(e.AvailableBuffer(), v.String(), opts.escapeHTML))633 }634}635 636func isValidNumber(s string) bool {637 // This function implements the JSON numbers grammar.638 // See https://tools.ietf.org/html/rfc7159#section-6639 // and https://www.json.org/img/number.png640 641 if s == "" {642 return false643 }644 645 // Optional -646 if s[0] == '-' {647 s = s[1:]648 if s == "" {649 return false650 }651 }652 653 // Digits654 switch {655 default:656 return false657 658 case s[0] == '0':659 s = s[1:]660 661 case '1' <= s[0] && s[0] <= '9':662 s = s[1:]663 for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {664 s = s[1:]665 }666 }667 668 // . followed by 1 or more digits.669 if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {670 s = s[2:]671 for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {672 s = s[1:]673 }674 }675 676 // e or E followed by an optional - or + and677 // 1 or more digits.678 if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {679 s = s[1:]680 if s[0] == '+' || s[0] == '-' {681 s = s[1:]682 if s == "" {683 return false684 }685 }686 for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {687 s = s[1:]688 }689 }690 691 // Make sure we are at the end.692 return s == ""693}694 695func interfaceEncoder(e *encodeState, v reflect.Value, opts encOpts) {696 if v.IsNil() {697 e.WriteString("null")698 return699 }700 e.reflectValue(v.Elem(), opts)701}702 703func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) {704 e.error(&UnsupportedTypeError{v.Type()})705}706 707type structEncoder struct {708 fields structFields709}710 711type structFields struct {712 list []field713 byExactName map[string]*field714 byFoldedName map[string]*field715}716 717func (se structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {718 next := byte('{')719FieldLoop:720 for i := range se.fields.list {721 f := &se.fields.list[i]722 723 // Find the nested struct field by following f.index.724 fv := v725 for _, i := range f.index {726 if fv.Kind() == reflect.Pointer {727 if fv.IsNil() {728 continue FieldLoop729 }730 fv = fv.Elem()731 }732 fv = fv.Field(i)733 }734 735 if (f.omitEmpty && isEmptyValue(fv)) ||736 (f.omitZero && (f.isZero == nil && fv.IsZero() || (f.isZero != nil && f.isZero(fv)))) {737 continue738 }739 e.WriteByte(next)740 next = ','741 if opts.escapeHTML {742 e.WriteString(f.nameEscHTML)743 } else {744 e.WriteString(f.nameNonEsc)745 }746 opts.quoted = f.quoted747 f.encoder(e, fv, opts)748 }749 if next == '{' {750 e.WriteString("{}")751 } else {752 e.WriteByte('}')753 }754}755 756func newStructEncoder(t reflect.Type) encoderFunc {757 se := structEncoder{fields: cachedTypeFields(t)}758 return se.encode759}760 761type mapEncoder struct {762 elemEnc encoderFunc763}764 765func (me mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {766 if v.IsNil() {767 e.WriteString("null")768 return769 }770 if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter {771 // We're a large number of nested ptrEncoder.encode calls deep;772 // start checking if we've run into a pointer cycle.773 ptr := v.UnsafePointer()774 if _, ok := e.ptrSeen[ptr]; ok {775 e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())})776 }777 e.ptrSeen[ptr] = struct{}{}778 defer delete(e.ptrSeen, ptr)779 }780 e.WriteByte('{')781 782 // Extract and sort the keys.783 var (784 sv = make([]reflectWithString, v.Len())785 mi = v.MapRange()786 err error787 )788 for i := 0; mi.Next(); i++ {789 if sv[i].ks, err = resolveKeyName(mi.Key()); err != nil {790 e.error(fmt.Errorf("json: encoding error for type %q: %q", v.Type().String(), err.Error()))791 }792 sv[i].v = mi.Value()793 }794 slices.SortFunc(sv, func(i, j reflectWithString) int {795 return strings.Compare(i.ks, j.ks)796 })797 798 for i, kv := range sv {799 if i > 0 {800 e.WriteByte(',')801 }802 e.Write(appendString(e.AvailableBuffer(), kv.ks, opts.escapeHTML))803 e.WriteByte(':')804 me.elemEnc(e, kv.v, opts)805 }806 e.WriteByte('}')807 e.ptrLevel--808}809 810func newMapEncoder(t reflect.Type) encoderFunc {811 switch t.Key().Kind() {812 case reflect.String,813 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,814 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:815 default:816 if !t.Key().Implements(textMarshalerType) {817 return unsupportedTypeEncoder818 }819 }820 me := mapEncoder{typeEncoder(t.Elem())}821 return me.encode822}823 824func encodeByteSlice(e *encodeState, v reflect.Value, _ encOpts) {825 if v.IsNil() {826 e.WriteString("null")827 return828 }829 830 s := v.Bytes()831 b := e.AvailableBuffer()832 b = append(b, '"')833 b = base64.StdEncoding.AppendEncode(b, s)834 b = append(b, '"')835 e.Write(b)836}837 838// sliceEncoder just wraps an arrayEncoder, checking to make sure the value isn't nil.839type sliceEncoder struct {840 arrayEnc encoderFunc841}842 843func (se sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {844 if v.IsNil() {845 e.WriteString("null")846 return847 }848 if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter {849 // We're a large number of nested ptrEncoder.encode calls deep;850 // start checking if we've run into a pointer cycle.851 // Here we use a struct to memorize the pointer to the first element of the slice852 // and its length.853 ptr := struct {854 ptr any // always an unsafe.Pointer, but avoids a dependency on package unsafe855 len int856 }{v.UnsafePointer(), v.Len()}857 if _, ok := e.ptrSeen[ptr]; ok {858 e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())})859 }860 e.ptrSeen[ptr] = struct{}{}861 defer delete(e.ptrSeen, ptr)862 }863 se.arrayEnc(e, v, opts)864 e.ptrLevel--865}866 867func newSliceEncoder(t reflect.Type) encoderFunc {868 // Byte slices get special treatment; arrays don't.869 if t.Elem().Kind() == reflect.Uint8 {870 p := reflect.PointerTo(t.Elem())871 if !p.Implements(marshalerType) && !p.Implements(textMarshalerType) {872 return encodeByteSlice873 }874 }875 enc := sliceEncoder{newArrayEncoder(t)}876 return enc.encode877}878 879type arrayEncoder struct {880 elemEnc encoderFunc881}882 883func (ae arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {884 e.WriteByte('[')885 n := v.Len()886 for i := 0; i < n; i++ {887 if i > 0 {888 e.WriteByte(',')889 }890 ae.elemEnc(e, v.Index(i), opts)891 }892 e.WriteByte(']')893}894 895func newArrayEncoder(t reflect.Type) encoderFunc {896 enc := arrayEncoder{typeEncoder(t.Elem())}897 return enc.encode898}899 900type ptrEncoder struct {901 elemEnc encoderFunc902}903 904func (pe ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {905 if v.IsNil() {906 e.WriteString("null")907 return908 }909 if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter {910 // We're a large number of nested ptrEncoder.encode calls deep;911 // start checking if we've run into a pointer cycle.912 ptr := v.Interface()913 if _, ok := e.ptrSeen[ptr]; ok {914 e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())})915 }916 e.ptrSeen[ptr] = struct{}{}917 defer delete(e.ptrSeen, ptr)918 }919 pe.elemEnc(e, v.Elem(), opts)920 e.ptrLevel--921}922 923func newPtrEncoder(t reflect.Type) encoderFunc {924 enc := ptrEncoder{typeEncoder(t.Elem())}925 return enc.encode926}927 928type condAddrEncoder struct {929 canAddrEnc, elseEnc encoderFunc930}931 932func (ce condAddrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {933 if v.CanAddr() {934 ce.canAddrEnc(e, v, opts)935 } else {936 ce.elseEnc(e, v, opts)937 }938}939 940// newCondAddrEncoder returns an encoder that checks whether its value941// CanAddr and delegates to canAddrEnc if so, else to elseEnc.942func newCondAddrEncoder(canAddrEnc, elseEnc encoderFunc) encoderFunc {943 enc := condAddrEncoder{canAddrEnc: canAddrEnc, elseEnc: elseEnc}944 return enc.encode945}946 947func isValidTag(s string) bool {948 if s == "" {949 return false950 }951 for _, c := range s {952 switch {953 case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c):954 // Backslash and quote chars are reserved, but955 // otherwise any punctuation chars are allowed956 // in a tag name.957 case !unicode.IsLetter(c) && !unicode.IsDigit(c):958 return false959 }960 }961 return true962}963 964func typeByIndex(t reflect.Type, index []int) reflect.Type {965 for _, i := range index {966 if t.Kind() == reflect.Pointer {967 t = t.Elem()968 }969 t = t.Field(i).Type970 }971 return t972}973 974type reflectWithString struct {975 v reflect.Value976 ks string977}978 979func resolveKeyName(k reflect.Value) (string, error) {980 if k.Kind() == reflect.String {981 return k.String(), nil982 }983 if tm, ok := reflect.TypeAssert[encoding.TextMarshaler](k); ok {984 if k.Kind() == reflect.Pointer && k.IsNil() {985 return "", nil986 }987 buf, err := tm.MarshalText()988 return string(buf), err989 }990 switch k.Kind() {991 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:992 return strconv.FormatInt(k.Int(), 10), nil993 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:994 return strconv.FormatUint(k.Uint(), 10), nil995 }996 panic("unexpected map key type")997}998 999func appendString[Bytes []byte | string](dst []byte, src Bytes, escapeHTML bool) []byte {1000 dst = append(dst, '"')1001 start := 01002 for i := 0; i < len(src); {1003 if b := src[i]; b < utf8.RuneSelf {1004 if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {1005 i++1006 continue1007 }1008 dst = append(dst, src[start:i]...)1009 switch b {1010 case '\\', '"':1011 dst = append(dst, '\\', b)1012 case '\b':1013 dst = append(dst, '\\', 'b')1014 case '\f':1015 dst = append(dst, '\\', 'f')1016 case '\n':1017 dst = append(dst, '\\', 'n')1018 case '\r':1019 dst = append(dst, '\\', 'r')1020 case '\t':1021 dst = append(dst, '\\', 't')1022 default:1023 // This encodes bytes < 0x20 except for \b, \f, \n, \r and \t.1024 // If escapeHTML is set, it also escapes <, >, and &1025 // because they can lead to security holes when1026 // user-controlled strings are rendered into JSON1027 // and served to some browsers.1028 dst = append(dst, '\\', 'u', '0', '0', hex[b>>4], hex[b&0xF])1029 }1030 i++1031 start = i1032 continue1033 }1034 // TODO(https://go.dev/issue/56948): Use generic utf8 functionality.1035 // For now, cast only a small portion of byte slices to a string1036 // so that it can be stack allocated. This slows down []byte slightly1037 // due to the extra copy, but keeps string performance roughly the same.1038 n := min(len(src)-i, utf8.UTFMax)1039 c, size := utf8.DecodeRuneInString(string(src[i : i+n]))1040 if c == utf8.RuneError && size == 1 {1041 dst = append(dst, src[start:i]...)1042 dst = append(dst, `\ufffd`...)1043 i += size1044 start = i1045 continue1046 }1047 // U+2028 is LINE SEPARATOR.1048 // U+2029 is PARAGRAPH SEPARATOR.1049 // They are both technically valid characters in JSON strings,1050 // but don't work in JSONP, which has to be evaluated as JavaScript,1051 // and can lead to security holes there. It is valid JSON to1052 // escape them, so we do so unconditionally.1053 // See https://en.wikipedia.org/wiki/JSON#Safety.1054 if c == '\u2028' || c == '\u2029' {1055 dst = append(dst, src[start:i]...)1056 dst = append(dst, '\\', 'u', '2', '0', '2', hex[c&0xF])1057 i += size1058 start = i1059 continue1060 }1061 i += size1062 }1063 dst = append(dst, src[start:]...)1064 dst = append(dst, '"')1065 return dst1066}1067 1068// A field represents a single field found in a struct.1069type field struct {1070 name string1071 nameBytes []byte // []byte(name)1072 1073 nameNonEsc string // `"` + name + `":`1074 nameEscHTML string // `"` + HTMLEscape(name) + `":`1075 1076 tag bool1077 index []int1078 typ reflect.Type1079 omitEmpty bool1080 omitZero bool1081 isZero func(reflect.Value) bool1082 quoted bool1083 1084 encoder encoderFunc1085}1086 1087type isZeroer interface {1088 IsZero() bool1089}1090 1091var isZeroerType = reflect.TypeFor[isZeroer]()1092 1093func typeFields(t reflect.Type) structFields {1094 // Anonymous fields to explore at the current level and the next.1095 current := []field{}1096 next := []field{{typ: t}}1097 1098 // Count of queued names for current level and the next.1099 var count, nextCount map[reflect.Type]int1100 1101 // Types already visited at an earlier level.1102 visited := map[reflect.Type]bool{}1103 1104 // Fields found.1105 var fields []field1106 1107 // Buffer to run appendHTMLEscape on field names.1108 var nameEscBuf []byte1109 1110 for len(next) > 0 {1111 current, next = next, current[:0]1112 count, nextCount = nextCount, map[reflect.Type]int{}1113 1114 for _, f := range current {1115 if visited[f.typ] {1116 continue1117 }1118 visited[f.typ] = true1119 1120 // Scan f.typ for fields to include.1121 for i := 0; i < f.typ.NumField(); i++ {1122 sf := f.typ.Field(i)1123 if sf.Anonymous {1124 t := sf.Type1125 if t.Kind() == reflect.Pointer {1126 t = t.Elem()1127 }1128 if !sf.IsExported() && t.Kind() != reflect.Struct {1129 // Ignore embedded fields of unexported non-struct types.1130 continue1131 }1132 // Do not ignore embedded fields of unexported struct types1133 // since they may have exported fields.1134 } else if !sf.IsExported() {1135 // Ignore unexported non-embedded fields.1136 continue1137 }1138 tag := sf.Tag.Get("json")1139 if tag == "-" {1140 continue1141 }1142 name, opts := parseTag(tag)1143 if !isValidTag(name) {1144 name = ""1145 }1146 index := make([]int, len(f.index)+1)1147 copy(index, f.index)1148 index[len(f.index)] = i1149 1150 ft := sf.Type1151 if ft.Name() == "" && ft.Kind() == reflect.Pointer {1152 // Follow pointer.1153 ft = ft.Elem()1154 }1155 1156 // Only strings, floats, integers, and booleans can be quoted.1157 quoted := false1158 if opts.Contains("string") {1159 switch ft.Kind() {1160 case reflect.Bool,1161 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,1162 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,1163 reflect.Float32, reflect.Float64,1164 reflect.String:1165 quoted = true1166 }1167 }1168 1169 // Record found field and index sequence.1170 if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {1171 tagged := name != ""1172 if name == "" {1173 name = sf.Name1174 }1175 field := field{1176 name: name,1177 tag: tagged,1178 index: index,1179 typ: ft,1180 omitEmpty: opts.Contains("omitempty"),1181 omitZero: opts.Contains("omitzero"),1182 quoted: quoted,1183 }1184 field.nameBytes = []byte(field.name)1185 1186 // Build nameEscHTML and nameNonEsc ahead of time.1187 nameEscBuf = appendHTMLEscape(nameEscBuf[:0], field.nameBytes)1188 field.nameEscHTML = `"` + string(nameEscBuf) + `":`1189 field.nameNonEsc = `"` + field.name + `":`1190 1191 if field.omitZero {1192 t := sf.Type1193 // Provide a function that uses a type's IsZero method.1194 switch {1195 case t.Kind() == reflect.Interface && t.Implements(isZeroerType):1196 field.isZero = func(v reflect.Value) bool {1197 // Avoid panics calling IsZero on a nil interface or1198 // non-nil interface with nil pointer.1199 return v.IsNil() ||1200 (v.Elem().Kind() == reflect.Pointer && v.Elem().IsNil()) ||