Source File
arshal.go
Belonging Package
encoding/json/v2
// 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.jsonv2package jsonimport ()// 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)var (// Once a JSON object has begun processing without duplicate name verification,// it does not track the history of names that have been seen so far.// Reject changing the setting for the current JSON object namespace,// otherwise we would be operating with inconsistent state.// Note that you can change the setting before processing the start// of a different JSON object.//// TODO: We could loosen this restriction in certain conditions.// If we are already checking for duplicate names,// we can momentarily disable it for the next JSON object member name.// However, if we are already NOT checking for duplicate names,// we cannot momentarily enable it for the next JSON object member name// since we already lack prior history of JSON object names.errChangingDuplicateNames = errors.New("cannot change duplicate name checks after a JSON object has already begun processing")// The presence of invalid UTF-8 has an interesting intersection// with checking for duplicate names. Due to the semantic of mangling// invalid UTF-8 as the Unicode replacement character,// two string keys in a Go map (both with invalid UTF-8)// may encode as the same JSON string. Thus, we forbid changing of// invalid UTF-8 checks in the current JSON object namespace.errChangingInvalidUTF8 = errors.New("cannot change UTF-8 checks after a JSON object has already begun processing")// TODO(https://go.dev/issue/79559): Changing whitespace currently// leads to strange effects and will need more careful adjustment.// For now, we just report an error.errChangingWhitespace = errors.New("cannot change whitespace formatting within a MarshalEncode call"))// 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 copying the value 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 to 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 [errors.ErrUnsupported],// 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 method returns [errors.ErrUnsupported],// then the input is encoded according to subsequent rules.//// - 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 as follows://// - A Go boolean is encoded as a JSON boolean (e.g., true or false).//// - A Go string is encoded as a JSON string.//// - A Go []byte or [N]byte is encoded as a JSON string containing// a binary value using Base 64 Encoding per RFC 4648, section 4.//// - 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.//// - 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.// Encoding a NaN or ±Inf 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.// By default, a nil map is encoded as an empty JSON object,// unless the [FormatNilMapAsNull] option is specified.//// - 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.// By default, a nil slice is encoded as an empty JSON array,// unless the [FormatNilSliceAsNull] option is specified.//// - 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.//// - A Go pointer is encoded as a JSON null if nil, otherwise it is// the recursively JSON-encoded representation 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.//// - A Go [time.Time] is encoded as a JSON string containing the timestamp// formatted in RFC 3339 with nanosecond precision.//// - A Go [time.Duration] currently has no default representation and// results in a [SemanticError], unless the [encoding/json.FormatDurationAsNano]// option is specified, in which case it is encoded as a JSON number// without fractions or exponents, representing the duration in nanoseconds.//// - 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.func ( any, ...Options) ( []byte, error) {:= export.GetBufferedEncoder(...)defer export.PutBufferedEncoder():= export.Encoder().Flags.Set(jsonflags.OmitTopLevelNewline | 1)= marshalEncode(, , &.Struct)if != nil && .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {return nil, internal.TransformMarshalError(, )}return bytes.Clone(.Buf),}// 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 ( io.Writer, any, ...Options) ( error) {:= export.GetStreamingEncoder(, ...)defer export.PutStreamingEncoder():= export.Encoder().Flags.Set(jsonflags.OmitTopLevelNewline | 1)= marshalEncode(, , &.Struct)if != nil && .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {return internal.TransformMarshalError(, )}return}// MarshalEncode serializes a Go value into an [jsontext.Encoder] according to// the provided marshal or encode options (while ignoring unmarshal or decode options).// The options provided take precedence over options already applied on// the [jsontext.Encoder] and only apply for the duration of the marshal call.//// See [Marshal] for details about the conversion of a Go value into JSON.func ( *jsontext.Encoder, any, ...Options) ( error) {:= export.Encoder()if len() > 0 {:= .Structdefer func() { .Struct = }().Struct.Join(...)if .Tokens.Last.NeedObjectName() {if .Flags.Get(jsonflags.AllowDuplicateNames) != .Struct.Flags.Get(jsonflags.AllowDuplicateNames) {return newMarshalErrorBefore(, reflect.TypeOf(), errChangingDuplicateNames)}if .Flags.Get(jsonflags.AllowInvalidUTF8) != .Struct.Flags.Get(jsonflags.AllowInvalidUTF8) {return newMarshalErrorBefore(, reflect.TypeOf(), errChangingInvalidUTF8)}}if .Struct.Flags.Has(jsonflags.AnyWhitespace) {if .Struct.Flags.Get(jsonflags.Multiline) {.Struct.InitializeMultiline()}if jsonopts.ChangedWhitespace(, .Struct) {return newMarshalErrorBefore(, reflect.TypeOf(), errChangingWhitespace)}}}= marshalEncode(, , &.Struct)if != nil && .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {return internal.TransformMarshalError(, )}return}func ( *jsontext.Encoder, any, *jsonopts.Struct) ( error) {:= reflect.ValueOf()if !.IsValid() || (.Kind() == reflect.Pointer && .IsNil()) {return .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.:= .Kind() != reflect.Pointerif {:= reflect.New(.Type()).Elem().Set()=}:= addressableValue{.Elem(), } // dereferenced pointer is always addressable:= .Type()// Lookup and call the marshal function for this type.:= lookupArshaler().marshalif .Marshalers != nil {, _ = .Marshalers.(*Marshalers).lookup(, )}if := (, , ); != nil {if !.Flags.Get(jsonflags.AllowDuplicateNames) {export.Encoder().Tokens.InvalidateDisabledNamespaces()}return}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 copying the value if necessary) so that// these functions and methods can be consistently called.// If a value must be shallow copied to call a pointer-receiver// [Unmarshaler], [UnmarshalerFrom], or [encoding.TextUnmarshaler] method,// then any mutations performed by the method are shallow copied back// into the destination value.//// The input is decoded into the output according to 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 [errors.ErrUnsupported],// 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 method returns [errors.ErrUnsupported],// then the input is decoded according to subsequent rules.//// - 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.// 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).//// - A Go string is decoded from a JSON string.//// - A Go []byte or [N]byte is decoded from a JSON string containing// a binary value using Base 64 Encoding per RFC 4648, section 4.// 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.//// - 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.// Since JSON lacks a native representation for a NaN or ±Inf,// such values cannot be the result of decoding.//// - 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.//// - 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.//// - 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.//// - 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.//// - 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.//// - A Go [time.Time] is decoded from a JSON string containing the time// formatted in RFC 3339 with nanosecond precision.//// - A Go [time.Duration] currently has no default representation and// results in a [SemanticError], unless the [encoding/json.FormatDurationAsNano]// option is specified, in which case it is decoded as a JSON number// without fractions or exponents, representing the duration in nanoseconds.//// - 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 ( []byte, any, ...Options) ( error) {:= export.GetBufferedDecoder(, ...)defer export.PutBufferedDecoder():= export.Decoder()= unmarshalDecode(, , &.Struct, true)if != nil && .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {return internal.TransformUnmarshalError(, )}return}// 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 ( io.Reader, any, ...Options) ( error) {:= export.GetStreamingDecoder(, ...)defer export.PutStreamingDecoder():= export.Decoder()= unmarshalDecode(, , &.Struct, true)if != nil && .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {return internal.TransformUnmarshalError(, )}return}// UnmarshalDecode deserializes a Go value from a [jsontext.Decoder] according to// the provided unmarshal or decode options (while ignoring marshal or encode options).// The options provided take precedence over options already applied on// the [jsontext.Decoder] and only apply for the duration of the unmarshal call.//// The input may be a stream of zero or more JSON values.// UnmarshalDecode unmarshals only 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 ( *jsontext.Decoder, any, ...Options) ( error) {:= export.Decoder()if len() > 0 {:= .Structdefer func() { .Struct = }().Struct.Join(...)if .Tokens.Last.NeedObjectName() {if .Flags.Get(jsonflags.AllowDuplicateNames) != .Struct.Flags.Get(jsonflags.AllowDuplicateNames) {return newUnmarshalErrorBefore(, reflect.TypeOf(), errChangingDuplicateNames)}if .Flags.Get(jsonflags.AllowInvalidUTF8) != .Struct.Flags.Get(jsonflags.AllowInvalidUTF8) {return newUnmarshalErrorBefore(, reflect.TypeOf(), errChangingInvalidUTF8)}}}= unmarshalDecode(, , &.Struct, false)if != nil && .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {return internal.TransformUnmarshalError(, )}return}func ( *jsontext.Decoder, any, *jsonopts.Struct, bool) ( error) {:= reflect.ValueOf()if .Kind() != reflect.Pointer || .IsNil() {return &SemanticError{action: "unmarshal", GoType: reflect.TypeOf(), Err: internal.ErrNonNilReference}}:= addressableValue{.Elem(), false} // dereferenced pointer is always addressable:= .Type()// In legacy semantics, the entirety of the next JSON value// was validated before attempting to unmarshal it.if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {if := export.Decoder().CheckNextValue(); != nil {if == io.EOF && {:= .InputOffset() + int64(len(.UnreadBuffer()))return &jsontext.SyntacticError{ByteOffset: , Err: io.ErrUnexpectedEOF}}return}}// Lookup and call the unmarshal function for this type.:= lookupArshaler().unmarshalif .Unmarshalers != nil {, _ = .Unmarshalers.(*Unmarshalers).lookup(, )}if := (, , ); != nil {if !.Flags.Get(jsonflags.AllowDuplicateNames) {export.Decoder().Tokens.InvalidateDisabledNamespaces()}if == io.EOF && {:= .InputOffset() + int64(len(.UnreadBuffer()))return &jsontext.SyntacticError{ByteOffset: , Err: io.ErrUnexpectedEOF}}return}if {return export.Decoder().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 ( reflect.Type) addressableValue {return addressableValue{reflect.New().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 be 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) errorunmarshaler = func(*jsontext.Decoder, addressableValue, *jsonopts.Struct) error)type arshaler struct {marshal marshalerunmarshal unmarshalernonDefault bool}var lookupArshalerCache sync.Map // map[reflect.Type]*arshalerfunc ( reflect.Type) *arshaler {if , := lookupArshalerCache.Load(); {return .(*arshaler)}:= makeDefaultArshaler()= makeMethodArshaler(, )= makeTimeArshaler(, )// Use the last stored so that duplicate arshalers can be garbage collected., := lookupArshalerCache.LoadOrStore(, )return .(*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 ( int) *stringSlice {:= stringsPools.Get().(*stringSlice)if cap(*) < {* = make([]string, )}* = (*)[:]return}func ( *stringSlice) {if cap(*) > 1<<10 {* = nil // avoid pinning arbitrarily large amounts of memory}clear(*) // avoid pinning a reference to each stringstringsPools.Put()}
The pages are generated with Golds v0.8.4. (GOOS=linux GOARCH=amd64)