| // Copyright 2020 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| //go:build goexperiment.jsonv2 | |
| package json | |
| import ( | |
| "bytes" | |
| "encoding" | |
| "io" | |
| "reflect" | |
| "sync" | |
| "time" | |
| "encoding/json/internal" | |
| "encoding/json/internal/jsonflags" | |
| "encoding/json/internal/jsonopts" | |
| "encoding/json/jsontext" | |
| ) | |
| // Reference encoding and time packages to assist pkgsite | |
| // in being able to hotlink references to those packages. | |
| var ( | |
| _ encoding.TextMarshaler | |
| _ encoding.TextAppender | |
| _ encoding.TextUnmarshaler | |
| _ time.Time | |
| _ time.Duration | |
| ) | |
| // export exposes internal functionality of the "jsontext" package. | |
| var export = jsontext.Internal.Export(&internal.AllowInternalUse) | |
| // Marshal serializes a Go value as a []byte according to the provided | |
| // marshal and encode options (while ignoring unmarshal or decode options). | |
| // It does not terminate the output with a newline. | |
| // | |
| // Type-specific marshal functions and methods take precedence | |
| // over the default representation of a value. | |
| // Functions or methods that operate on *T are only called when encoding | |
| // a value of type T (by taking its address) or a non-nil value of *T. | |
| // Marshal ensures that a value is always addressable | |
| // (by boxing it on the heap if necessary) so that | |
| // these functions and methods can be consistently called. For performance, | |
| // it is recommended that Marshal be passed a non-nil pointer to the value. | |
| // | |
| // The input value is encoded as JSON according the following rules: | |
| // | |
| // - If any type-specific functions in a [WithMarshalers] option match | |
| // the value type, then those functions are called to encode the value. | |
| // If all applicable functions return [SkipFunc], | |
| // then the value is encoded according to subsequent rules. | |
| // | |
| // - If the value type implements [MarshalerTo], | |
| // then the MarshalJSONTo method is called to encode the value. | |
| // | |
| // - If the value type implements [Marshaler], | |
| // then the MarshalJSON method is called to encode the value. | |
| // | |
| // - If the value type implements [encoding.TextAppender], | |
| // then the AppendText method is called to encode the value and | |
| // subsequently encode its result as a JSON string. | |
| // | |
| // - If the value type implements [encoding.TextMarshaler], | |
| // then the MarshalText method is called to encode the value and | |
| // subsequently encode its result as a JSON string. | |
| // | |
| // - Otherwise, the value is encoded according to the value's type | |
| // as described in detail below. | |
| // | |
| // Most Go types have a default JSON representation. | |
| // Certain types support specialized formatting according to | |
| // a format flag optionally specified in the Go struct tag | |
| // for the struct field that contains the current value | |
| // (see the “JSON Representation of Go structs” section for more details). | |
| // | |
| // The representation of each type is as follows: | |
| // | |
| // - A Go boolean is encoded as a JSON boolean (e.g., true or false). | |
| // It does not support any custom format flags. | |
| // | |
| // - A Go string is encoded as a JSON string. | |
| // It does not support any custom format flags. | |
| // | |
| // - A Go []byte or [N]byte is encoded as a JSON string containing | |
| // the binary value encoded using RFC 4648. | |
| // If the format is "base64" or unspecified, then this uses RFC 4648, section 4. | |
| // If the format is "base64url", then this uses RFC 4648, section 5. | |
| // If the format is "base32", then this uses RFC 4648, section 6. | |
| // If the format is "base32hex", then this uses RFC 4648, section 7. | |
| // If the format is "base16" or "hex", then this uses RFC 4648, section 8. | |
| // If the format is "array", then the bytes value is encoded as a JSON array | |
| // where each byte is recursively JSON-encoded as each JSON array element. | |
| // | |
| // - A Go integer is encoded as a JSON number without fractions or exponents. | |
| // If [StringifyNumbers] is specified or encoding a JSON object name, | |
| // then the JSON number is encoded within a JSON string. | |
| // It does not support any custom format flags. | |
| // | |
| // - A Go float is encoded as a JSON number. | |
| // If [StringifyNumbers] is specified or encoding a JSON object name, | |
| // then the JSON number is encoded within a JSON string. | |
| // If the format is "nonfinite", then NaN, +Inf, and -Inf are encoded as | |
| // the JSON strings "NaN", "Infinity", and "-Infinity", respectively. | |
| // Otherwise, the presence of non-finite numbers results in a [SemanticError]. | |
| // | |
| // - A Go map is encoded as a JSON object, where each Go map key and value | |
| // is recursively encoded as a name and value pair in the JSON object. | |
| // The Go map key must encode as a JSON string, otherwise this results | |
| // in a [SemanticError]. The Go map is traversed in a non-deterministic order. | |
| // For deterministic encoding, consider using the [Deterministic] option. | |
| // If the format is "emitnull", then a nil map is encoded as a JSON null. | |
| // If the format is "emitempty", then a nil map is encoded as an empty JSON object, | |
| // regardless of whether [FormatNilMapAsNull] is specified. | |
| // Otherwise by default, a nil map is encoded as an empty JSON object. | |
| // | |
| // - A Go struct is encoded as a JSON object. | |
| // See the “JSON Representation of Go structs” section | |
| // in the package-level documentation for more details. | |
| // | |
| // - A Go slice is encoded as a JSON array, where each Go slice element | |
| // is recursively JSON-encoded as the elements of the JSON array. | |
| // If the format is "emitnull", then a nil slice is encoded as a JSON null. | |
| // If the format is "emitempty", then a nil slice is encoded as an empty JSON array, | |
| // regardless of whether [FormatNilSliceAsNull] is specified. | |
| // Otherwise by default, a nil slice is encoded as an empty JSON array. | |
| // | |
| // - A Go array is encoded as a JSON array, where each Go array element | |
| // is recursively JSON-encoded as the elements of the JSON array. | |
| // The JSON array length is always identical to the Go array length. | |
| // It does not support any custom format flags. | |
| // | |
| // - A Go pointer is encoded as a JSON null if nil, otherwise it is | |
| // the recursively JSON-encoded representation of the underlying value. | |
| // Format flags are forwarded to the encoding of the underlying value. | |
| // | |
| // - A Go interface is encoded as a JSON null if nil, otherwise it is | |
| // the recursively JSON-encoded representation of the underlying value. | |
| // It does not support any custom format flags. | |
| // | |
| // - A Go [time.Time] is encoded as a JSON string containing the timestamp | |
| // formatted in RFC 3339 with nanosecond precision. | |
| // If the format matches one of the format constants declared | |
| // in the time package (e.g., RFC1123), then that format is used. | |
| // If the format is "unix", "unixmilli", "unixmicro", or "unixnano", | |
| // then the timestamp is encoded as a possibly fractional JSON number | |
| // of the number of seconds (or milliseconds, microseconds, or nanoseconds) | |
| // since the Unix epoch, which is January 1st, 1970 at 00:00:00 UTC. | |
| // To avoid a fractional component, round the timestamp to the relevant unit. | |
| // Otherwise, the format is used as-is with [time.Time.Format] if non-empty. | |
| // | |
| // - A Go [time.Duration] currently has no default representation and | |
| // requires an explicit format to be specified. | |
| // If the format is "sec", "milli", "micro", or "nano", | |
| // then the duration is encoded as a possibly fractional JSON number | |
| // of the number of seconds (or milliseconds, microseconds, or nanoseconds). | |
| // To avoid a fractional component, round the duration to the relevant unit. | |
| // If the format is "units", it is encoded as a JSON string formatted using | |
| // [time.Duration.String] (e.g., "1h30m" for 1 hour 30 minutes). | |
| // If the format is "iso8601", it is encoded as a JSON string using the | |
| // ISO 8601 standard for durations (e.g., "PT1H30M" for 1 hour 30 minutes) | |
| // using only accurate units of hours, minutes, and seconds. | |
| // | |
| // - All other Go types (e.g., complex numbers, channels, and functions) | |
| // have no default representation and result in a [SemanticError]. | |
| // | |
| // JSON cannot represent cyclic data structures and Marshal does not handle them. | |
| // Passing cyclic structures will result in an error. | |
| func Marshal(in any, opts ...Options) (out []byte, err error) { | |
| enc := export.GetBufferedEncoder(opts...) | |
| defer export.PutBufferedEncoder(enc) | |
| xe := export.Encoder(enc) | |
| xe.Flags.Set(jsonflags.OmitTopLevelNewline | 1) | |
| err = marshalEncode(enc, in, &xe.Struct) | |
| if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return nil, internal.TransformMarshalError(in, err) | |
| } | |
| return bytes.Clone(xe.Buf), err | |
| } | |
| // MarshalWrite serializes a Go value into an [io.Writer] according to the provided | |
| // marshal and encode options (while ignoring unmarshal or decode options). | |
| // It does not terminate the output with a newline. | |
| // See [Marshal] for details about the conversion of a Go value into JSON. | |
| func MarshalWrite(out io.Writer, in any, opts ...Options) (err error) { | |
| enc := export.GetStreamingEncoder(out, opts...) | |
| defer export.PutStreamingEncoder(enc) | |
| xe := export.Encoder(enc) | |
| xe.Flags.Set(jsonflags.OmitTopLevelNewline | 1) | |
| err = marshalEncode(enc, in, &xe.Struct) | |
| if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return internal.TransformMarshalError(in, err) | |
| } | |
| return err | |
| } | |
| // MarshalEncode serializes a Go value into an [jsontext.Encoder] according to | |
| // the provided marshal options (while ignoring unmarshal, encode, or decode options). | |
| // Any marshal-relevant options already specified on the [jsontext.Encoder] | |
| // take lower precedence than the set of options provided by the caller. | |
| // Unlike [Marshal] and [MarshalWrite], encode options are ignored because | |
| // they must have already been specified on the provided [jsontext.Encoder]. | |
| // | |
| // See [Marshal] for details about the conversion of a Go value into JSON. | |
| func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) { | |
| xe := export.Encoder(out) | |
| if len(opts) > 0 { | |
| optsOriginal := xe.Struct | |
| defer func() { xe.Struct = optsOriginal }() | |
| xe.Struct.JoinWithoutCoderOptions(opts...) | |
| } | |
| err = marshalEncode(out, in, &xe.Struct) | |
| if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return internal.TransformMarshalError(in, err) | |
| } | |
| return err | |
| } | |
| func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err error) { | |
| v := reflect.ValueOf(in) | |
| if !v.IsValid() || (v.Kind() == reflect.Pointer && v.IsNil()) { | |
| return out.WriteToken(jsontext.Null) | |
| } | |
| // Shallow copy non-pointer values to obtain an addressable value. | |
| // It is beneficial to performance to always pass pointers to avoid this. | |
| forceAddr := v.Kind() != reflect.Pointer | |
| if forceAddr { | |
| v2 := reflect.New(v.Type()) | |
| v2.Elem().Set(v) | |
| v = v2 | |
| } | |
| va := addressableValue{v.Elem(), forceAddr} // dereferenced pointer is always addressable | |
| t := va.Type() | |
| // Lookup and call the marshal function for this type. | |
| marshal := lookupArshaler(t).marshal | |
| if mo.Marshalers != nil { | |
| marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, t) | |
| } | |
| if err := marshal(out, va, mo); err != nil { | |
| if !mo.Flags.Get(jsonflags.AllowDuplicateNames) { | |
| export.Encoder(out).Tokens.InvalidateDisabledNamespaces() | |
| } | |
| return err | |
| } | |
| return nil | |
| } | |
| // Unmarshal decodes a []byte input into a Go value according to the provided | |
| // unmarshal and decode options (while ignoring marshal or encode options). | |
| // The input must be a single JSON value with optional whitespace interspersed. | |
| // The output must be a non-nil pointer. | |
| // | |
| // Type-specific unmarshal functions and methods take precedence | |
| // over the default representation of a value. | |
| // Functions or methods that operate on *T are only called when decoding | |
| // a value of type T (by taking its address) or a non-nil value of *T. | |
| // Unmarshal ensures that a value is always addressable | |
| // (by boxing it on the heap if necessary) so that | |
| // these functions and methods can be consistently called. | |
| // | |
| // The input is decoded into the output according the following rules: | |
| // | |
| // - If any type-specific functions in a [WithUnmarshalers] option match | |
| // the value type, then those functions are called to decode the JSON | |
| // value. If all applicable functions return [SkipFunc], | |
| // then the input is decoded according to subsequent rules. | |
| // | |
| // - If the value type implements [UnmarshalerFrom], | |
| // then the UnmarshalJSONFrom method is called to decode the JSON value. | |
| // | |
| // - If the value type implements [Unmarshaler], | |
| // then the UnmarshalJSON method is called to decode the JSON value. | |
| // | |
| // - If the value type implements [encoding.TextUnmarshaler], | |
| // then the input is decoded as a JSON string and | |
| // the UnmarshalText method is called with the decoded string value. | |
| // This fails with a [SemanticError] if the input is not a JSON string. | |
| // | |
| // - Otherwise, the JSON value is decoded according to the value's type | |
| // as described in detail below. | |
| // | |
| // Most Go types have a default JSON representation. | |
| // Certain types support specialized formatting according to | |
| // a format flag optionally specified in the Go struct tag | |
| // for the struct field that contains the current value | |
| // (see the “JSON Representation of Go structs” section for more details). | |
| // A JSON null may be decoded into every supported Go value where | |
| // it is equivalent to storing the zero value of the Go value. | |
| // If the input JSON kind is not handled by the current Go value type, | |
| // then this fails with a [SemanticError]. Unless otherwise specified, | |
| // the decoded value replaces any pre-existing value. | |
| // | |
| // The representation of each type is as follows: | |
| // | |
| // - A Go boolean is decoded from a JSON boolean (e.g., true or false). | |
| // It does not support any custom format flags. | |
| // | |
| // - A Go string is decoded from a JSON string. | |
| // It does not support any custom format flags. | |
| // | |
| // - A Go []byte or [N]byte is decoded from a JSON string | |
| // containing the binary value encoded using RFC 4648. | |
| // If the format is "base64" or unspecified, then this uses RFC 4648, section 4. | |
| // If the format is "base64url", then this uses RFC 4648, section 5. | |
| // If the format is "base32", then this uses RFC 4648, section 6. | |
| // If the format is "base32hex", then this uses RFC 4648, section 7. | |
| // If the format is "base16" or "hex", then this uses RFC 4648, section 8. | |
| // If the format is "array", then the Go slice or array is decoded from a | |
| // JSON array where each JSON element is recursively decoded for each byte. | |
| // When decoding into a non-nil []byte, the slice length is reset to zero | |
| // and the decoded input is appended to it. | |
| // When decoding into a [N]byte, the input must decode to exactly N bytes, | |
| // otherwise it fails with a [SemanticError]. | |
| // | |
| // - A Go integer is decoded from a JSON number. | |
| // It must be decoded from a JSON string containing a JSON number | |
| // if [StringifyNumbers] is specified or decoding a JSON object name. | |
| // It fails with a [SemanticError] if the JSON number | |
| // has a fractional or exponent component. | |
| // It also fails if it overflows the representation of the Go integer type. | |
| // It does not support any custom format flags. | |
| // | |
| // - A Go float is decoded from a JSON number. | |
| // It must be decoded from a JSON string containing a JSON number | |
| // if [StringifyNumbers] is specified or decoding a JSON object name. | |
| // It fails if it overflows the representation of the Go float type. | |
| // If the format is "nonfinite", then the JSON strings | |
| // "NaN", "Infinity", and "-Infinity" are decoded as NaN, +Inf, and -Inf. | |
| // Otherwise, the presence of such strings results in a [SemanticError]. | |
| // | |
| // - A Go map is decoded from a JSON object, | |
| // where each JSON object name and value pair is recursively decoded | |
| // as the Go map key and value. Maps are not cleared. | |
| // If the Go map is nil, then a new map is allocated to decode into. | |
| // If the decoded key matches an existing Go map entry, the entry value | |
| // is reused by decoding the JSON object value into it. | |
| // The formats "emitnull" and "emitempty" have no effect when decoding. | |
| // | |
| // - A Go struct is decoded from a JSON object. | |
| // See the “JSON Representation of Go structs” section | |
| // in the package-level documentation for more details. | |
| // | |
| // - A Go slice is decoded from a JSON array, where each JSON element | |
| // is recursively decoded and appended to the Go slice. | |
| // Before appending into a Go slice, a new slice is allocated if it is nil, | |
| // otherwise the slice length is reset to zero. | |
| // The formats "emitnull" and "emitempty" have no effect when decoding. | |
| // | |
| // - A Go array is decoded from a JSON array, where each JSON array element | |
| // is recursively decoded as each corresponding Go array element. | |
| // Each Go array element is zeroed before decoding into it. | |
| // It fails with a [SemanticError] if the JSON array does not contain | |
| // the exact same number of elements as the Go array. | |
| // It does not support any custom format flags. | |
| // | |
| // - A Go pointer is decoded based on the JSON kind and underlying Go type. | |
| // If the input is a JSON null, then this stores a nil pointer. | |
| // Otherwise, it allocates a new underlying value if the pointer is nil, | |
| // and recursively JSON decodes into the underlying value. | |
| // Format flags are forwarded to the decoding of the underlying type. | |
| // | |
| // - A Go interface is decoded based on the JSON kind and underlying Go type. | |
| // If the input is a JSON null, then this stores a nil interface value. | |
| // Otherwise, a nil interface value of an empty interface type is initialized | |
| // with a zero Go bool, string, float64, map[string]any, or []any if the | |
| // input is a JSON boolean, string, number, object, or array, respectively. | |
| // If the interface value is still nil, then this fails with a [SemanticError] | |
| // since decoding could not determine an appropriate Go type to decode into. | |
| // For example, unmarshaling into a nil io.Reader fails since | |
| // there is no concrete type to populate the interface value with. | |
| // Otherwise an underlying value exists and it recursively decodes | |
| // the JSON input into it. It does not support any custom format flags. | |
| // | |
| // - A Go [time.Time] is decoded from a JSON string containing the time | |
| // formatted in RFC 3339 with nanosecond precision. | |
| // If the format matches one of the format constants declared in | |
| // the time package (e.g., RFC1123), then that format is used for parsing. | |
| // If the format is "unix", "unixmilli", "unixmicro", or "unixnano", | |
| // then the timestamp is decoded from an optionally fractional JSON number | |
| // of the number of seconds (or milliseconds, microseconds, or nanoseconds) | |
| // since the Unix epoch, which is January 1st, 1970 at 00:00:00 UTC. | |
| // Otherwise, the format is used as-is with [time.Time.Parse] if non-empty. | |
| // | |
| // - A Go [time.Duration] currently has no default representation and | |
| // requires an explicit format to be specified. | |
| // If the format is "sec", "milli", "micro", or "nano", | |
| // then the duration is decoded from an optionally fractional JSON number | |
| // of the number of seconds (or milliseconds, microseconds, or nanoseconds). | |
| // If the format is "units", it is decoded from a JSON string parsed using | |
| // [time.ParseDuration] (e.g., "1h30m" for 1 hour 30 minutes). | |
| // If the format is "iso8601", it is decoded from a JSON string using the | |
| // ISO 8601 standard for durations (e.g., "PT1H30M" for 1 hour 30 minutes) | |
| // accepting only accurate units of hours, minutes, or seconds. | |
| // | |
| // - All other Go types (e.g., complex numbers, channels, and functions) | |
| // have no default representation and result in a [SemanticError]. | |
| // | |
| // In general, unmarshaling follows merge semantics (similar to RFC 7396) | |
| // where the decoded Go value replaces the destination value | |
| // for any JSON kind other than an object. | |
| // For JSON objects, the input object is merged into the destination value | |
| // where matching object members recursively apply merge semantics. | |
| func Unmarshal(in []byte, out any, opts ...Options) (err error) { | |
| dec := export.GetBufferedDecoder(in, opts...) | |
| defer export.PutBufferedDecoder(dec) | |
| xd := export.Decoder(dec) | |
| err = unmarshalDecode(dec, out, &xd.Struct, true) | |
| if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return internal.TransformUnmarshalError(out, err) | |
| } | |
| return err | |
| } | |
| // UnmarshalRead deserializes a Go value from an [io.Reader] according to the | |
| // provided unmarshal and decode options (while ignoring marshal or encode options). | |
| // The input must be a single JSON value with optional whitespace interspersed. | |
| // It consumes the entirety of [io.Reader] until [io.EOF] is encountered, | |
| // without reporting an error for EOF. The output must be a non-nil pointer. | |
| // See [Unmarshal] for details about the conversion of JSON into a Go value. | |
| func UnmarshalRead(in io.Reader, out any, opts ...Options) (err error) { | |
| dec := export.GetStreamingDecoder(in, opts...) | |
| defer export.PutStreamingDecoder(dec) | |
| xd := export.Decoder(dec) | |
| err = unmarshalDecode(dec, out, &xd.Struct, true) | |
| if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return internal.TransformUnmarshalError(out, err) | |
| } | |
| return err | |
| } | |
| // UnmarshalDecode deserializes a Go value from a [jsontext.Decoder] according to | |
| // the provided unmarshal options (while ignoring marshal, encode, or decode options). | |
| // Any unmarshal options already specified on the [jsontext.Decoder] | |
| // take lower precedence than the set of options provided by the caller. | |
| // Unlike [Unmarshal] and [UnmarshalRead], decode options are ignored because | |
| // they must have already been specified on the provided [jsontext.Decoder]. | |
| // | |
| // The input may be a stream of zero or more JSON values, | |
| // where this only unmarshals the next JSON value in the stream. | |
| // If there are no more top-level JSON values, it reports [io.EOF]. | |
| // The output must be a non-nil pointer. | |
| // See [Unmarshal] for details about the conversion of JSON into a Go value. | |
| func UnmarshalDecode(in *jsontext.Decoder, out any, opts ...Options) (err error) { | |
| xd := export.Decoder(in) | |
| if len(opts) > 0 { | |
| optsOriginal := xd.Struct | |
| defer func() { xd.Struct = optsOriginal }() | |
| xd.Struct.JoinWithoutCoderOptions(opts...) | |
| } | |
| err = unmarshalDecode(in, out, &xd.Struct, false) | |
| if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return internal.TransformUnmarshalError(out, err) | |
| } | |
| return err | |
| } | |
| func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct, last bool) (err error) { | |
| v := reflect.ValueOf(out) | |
| if v.Kind() != reflect.Pointer || v.IsNil() { | |
| return &SemanticError{action: "unmarshal", GoType: reflect.TypeOf(out), Err: internal.ErrNonNilReference} | |
| } | |
| va := addressableValue{v.Elem(), false} // dereferenced pointer is always addressable | |
| t := va.Type() | |
| // In legacy semantics, the entirety of the next JSON value | |
| // was validated before attempting to unmarshal it. | |
| if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| if err := export.Decoder(in).CheckNextValue(last); err != nil { | |
| if err == io.EOF && last { | |
| offset := in.InputOffset() + int64(len(in.UnreadBuffer())) | |
| return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF} | |
| } | |
| return err | |
| } | |
| } | |
| // Lookup and call the unmarshal function for this type. | |
| unmarshal := lookupArshaler(t).unmarshal | |
| if uo.Unmarshalers != nil { | |
| unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, t) | |
| } | |
| if err := unmarshal(in, va, uo); err != nil { | |
| if !uo.Flags.Get(jsonflags.AllowDuplicateNames) { | |
| export.Decoder(in).Tokens.InvalidateDisabledNamespaces() | |
| } | |
| if err == io.EOF && last { | |
| offset := in.InputOffset() + int64(len(in.UnreadBuffer())) | |
| return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF} | |
| } | |
| return err | |
| } | |
| if last { | |
| return export.Decoder(in).CheckEOF() | |
| } | |
| return nil | |
| } | |
| // addressableValue is a reflect.Value that is guaranteed to be addressable | |
| // such that calling the Addr and Set methods do not panic. | |
| // | |
| // There is no compile magic that enforces this property, | |
| // but rather the need to construct this type makes it easier to examine each | |
| // construction site to ensure that this property is upheld. | |
| type addressableValue struct { | |
| reflect.Value | |
| // forcedAddr reports whether this value is addressable | |
| // only through the use of [newAddressableValue]. | |
| // This is only used for [jsonflags.CallMethodsWithLegacySemantics]. | |
| forcedAddr bool | |
| } | |
| // newAddressableValue constructs a new addressable value of type t. | |
| func newAddressableValue(t reflect.Type) addressableValue { | |
| return addressableValue{reflect.New(t).Elem(), true} | |
| } | |
| // TODO: Remove *jsonopts.Struct argument from [marshaler] and [unmarshaler]. | |
| // This can be directly accessed on the encoder or decoder. | |
| // All marshal and unmarshal behavior is implemented using these signatures. | |
| // The *jsonopts.Struct argument is guaranteed to identical to or at least | |
| // a strict super-set of the options in Encoder.Struct or Decoder.Struct. | |
| // It is identical for Marshal, Unmarshal, MarshalWrite, and UnmarshalRead. | |
| // It is a super-set for MarshalEncode and UnmarshalDecode. | |
| type ( | |
| marshaler = func(*jsontext.Encoder, addressableValue, *jsonopts.Struct) error | |
| unmarshaler = func(*jsontext.Decoder, addressableValue, *jsonopts.Struct) error | |
| ) | |
| type arshaler struct { | |
| marshal marshaler | |
| unmarshal unmarshaler | |
| nonDefault bool | |
| } | |
| var lookupArshalerCache sync.Map // map[reflect.Type]*arshaler | |
| func lookupArshaler(t reflect.Type) *arshaler { | |
| if v, ok := lookupArshalerCache.Load(t); ok { | |
| return v.(*arshaler) | |
| } | |
| fncs := makeDefaultArshaler(t) | |
| fncs = makeMethodArshaler(fncs, t) | |
| fncs = makeTimeArshaler(fncs, t) | |
| // Use the last stored so that duplicate arshalers can be garbage collected. | |
| v, _ := lookupArshalerCache.LoadOrStore(t, fncs) | |
| return v.(*arshaler) | |
| } | |
| var stringsPools = &sync.Pool{New: func() any { return new(stringSlice) }} | |
| type stringSlice []string | |
| // getStrings returns a non-nil pointer to a slice with length n. | |
| func getStrings(n int) *stringSlice { | |
| s := stringsPools.Get().(*stringSlice) | |
| if cap(*s) < n { | |
| *s = make([]string, n) | |
| } | |
| *s = (*s)[:n] | |
| return s | |
| } | |
| func putStrings(s *stringSlice) { | |
| if cap(*s) > 1<<10 { | |
| *s = nil // avoid pinning arbitrarily large amounts of memory | |
| } | |
| clear(*s) // avoid pinning a reference to each string | |
| stringsPools.Put(s) | |
| } | |