mirror of
https://github.com/rocky-linux/peridot.git
synced 2024-10-19 07:55:07 +00:00
514 lines
23 KiB
Go
514 lines
23 KiB
Go
|
// 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.
|
||
|
|
||
|
package json
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"io"
|
||
|
"reflect"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
// MarshalOptions configures how Go data is serialized as JSON data.
|
||
|
// The zero value is equivalent to the default marshal settings.
|
||
|
type MarshalOptions struct {
|
||
|
requireKeyedLiterals
|
||
|
nonComparable
|
||
|
|
||
|
// Marshalers is a list of type-specific marshalers to use.
|
||
|
Marshalers *Marshalers
|
||
|
|
||
|
// StringifyNumbers specifies that numeric Go types should be serialized
|
||
|
// as a JSON string containing the equivalent JSON number value.
|
||
|
//
|
||
|
// According to RFC 8259, section 6, a JSON implementation may choose to
|
||
|
// limit the representation of a JSON number to an IEEE 754 binary64 value.
|
||
|
// This may cause decoders to lose precision for int64 and uint64 types.
|
||
|
// Escaping JSON numbers as a JSON string preserves the exact precision.
|
||
|
StringifyNumbers bool
|
||
|
|
||
|
// DiscardUnknownMembers specifies that marshaling should ignore any
|
||
|
// JSON object members stored in Go struct fields dedicated to storing
|
||
|
// unknown JSON object members.
|
||
|
DiscardUnknownMembers bool
|
||
|
|
||
|
// Deterministic specifies that the same input value will be serialized
|
||
|
// as the exact same output bytes. Different processes of
|
||
|
// the same program will serialize equal values to the same bytes,
|
||
|
// but different versions of the same program are not guaranteed
|
||
|
// to produce the exact same sequence of bytes.
|
||
|
Deterministic bool
|
||
|
|
||
|
// formatDepth is the depth at which we respect the format flag.
|
||
|
formatDepth int
|
||
|
// format is custom formatting for the value at the specified depth.
|
||
|
format string
|
||
|
}
|
||
|
|
||
|
// Marshal serializes a Go value as a []byte with default options.
|
||
|
// It is a thin wrapper over MarshalOptions.Marshal.
|
||
|
func Marshal(in any) (out []byte, err error) {
|
||
|
return MarshalOptions{}.Marshal(EncodeOptions{}, in)
|
||
|
}
|
||
|
|
||
|
// MarshalFull serializes a Go value into an io.Writer with default options.
|
||
|
// It is a thin wrapper over MarshalOptions.MarshalFull.
|
||
|
func MarshalFull(out io.Writer, in any) error {
|
||
|
return MarshalOptions{}.MarshalFull(EncodeOptions{}, out, in)
|
||
|
}
|
||
|
|
||
|
// Marshal serializes a Go value as a []byte according to the provided
|
||
|
// marshal and encode options. It does not terminate the output with a newline.
|
||
|
// See MarshalNext for details about the conversion of a Go value into JSON.
|
||
|
func (mo MarshalOptions) Marshal(eo EncodeOptions, in any) (out []byte, err error) {
|
||
|
enc := getBufferedEncoder(eo)
|
||
|
defer putBufferedEncoder(enc)
|
||
|
enc.options.omitTopLevelNewline = true
|
||
|
err = mo.MarshalNext(enc, in)
|
||
|
// TODO(https://go.dev/issue/45038): Use bytes.Clone.
|
||
|
return append([]byte(nil), enc.buf...), err
|
||
|
}
|
||
|
|
||
|
// MarshalFull serializes a Go value into an io.Writer according to the provided
|
||
|
// marshal and encode options. It does not terminate the output with a newline.
|
||
|
// See MarshalNext for details about the conversion of a Go value into JSON.
|
||
|
func (mo MarshalOptions) MarshalFull(eo EncodeOptions, out io.Writer, in any) error {
|
||
|
enc := getStreamingEncoder(out, eo)
|
||
|
defer putStreamingEncoder(enc)
|
||
|
enc.options.omitTopLevelNewline = true
|
||
|
err := mo.MarshalNext(enc, in)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// MarshalNext encodes a Go value as the next JSON value according to
|
||
|
// the provided marshal options.
|
||
|
//
|
||
|
// 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.
|
||
|
// MarshalNext 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 MarshalNext 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 MarshalOptions.Marshalers 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 MarshalerV2,
|
||
|
// then the MarshalNextJSON method is called to encode the value.
|
||
|
//
|
||
|
// - If the value type implements MarshalerV1,
|
||
|
// then the MarshalJSON method is called to encode the value.
|
||
|
//
|
||
|
// - 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 MarshalOptions.StringifyNumbers is specified, 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 MarshalOptions.StringifyNumbers is specified,
|
||
|
// 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. When encoding keys, MarshalOptions.StringifyNumbers
|
||
|
// is automatically applied so that numeric keys encode as JSON strings.
|
||
|
// The Go map is traversed in a non-deterministic order.
|
||
|
// For deterministic encoding, consider using RawValue.Canonicalize.
|
||
|
// If the format is "emitnull", then a nil map is encoded as a JSON null.
|
||
|
// 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.
|
||
|
// 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 resolution.
|
||
|
// If the format matches one of the format constants declared
|
||
|
// in the time package (e.g., RFC1123), then that format is used.
|
||
|
// Otherwise, the format is used as-is with time.Time.Format if non-empty.
|
||
|
//
|
||
|
// - A Go time.Duration is encoded as a JSON string containing the duration
|
||
|
// formatted according to time.Duration.String.
|
||
|
// If the format is "nanos", it is encoded as a JSON number
|
||
|
// containing the number of nanoseconds in the duration.
|
||
|
//
|
||
|
// - 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
|
||
|
// MarshalNext does not handle them.
|
||
|
// Passing cyclic structures will result in an error.
|
||
|
func (mo MarshalOptions) MarshalNext(out *Encoder, in any) error {
|
||
|
v := reflect.ValueOf(in)
|
||
|
if !v.IsValid() || (v.Kind() == reflect.Pointer && v.IsNil()) {
|
||
|
return out.WriteToken(Null)
|
||
|
}
|
||
|
// Shallow copy non-pointer values to obtain an addressable value.
|
||
|
// It is beneficial to performance to always pass pointers to avoid this.
|
||
|
if v.Kind() != reflect.Pointer {
|
||
|
v2 := reflect.New(v.Type())
|
||
|
v2.Elem().Set(v)
|
||
|
v = v2
|
||
|
}
|
||
|
va := addressableValue{v.Elem()} // 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.lookup(marshal, t)
|
||
|
}
|
||
|
if err := marshal(mo, out, va); err != nil {
|
||
|
if !out.options.AllowDuplicateNames {
|
||
|
out.tokens.invalidateDisabledNamespaces()
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// UnmarshalOptions configures how JSON data is deserialized as Go data.
|
||
|
// The zero value is equivalent to the default unmarshal settings.
|
||
|
type UnmarshalOptions struct {
|
||
|
requireKeyedLiterals
|
||
|
nonComparable
|
||
|
|
||
|
// Unmarshalers is a list of type-specific unmarshalers to use.
|
||
|
Unmarshalers *Unmarshalers
|
||
|
|
||
|
// StringifyNumbers specifies that numeric Go types can be deserialized
|
||
|
// from either a JSON number or a JSON string containing a JSON number
|
||
|
// without any surrounding whitespace.
|
||
|
StringifyNumbers bool
|
||
|
|
||
|
// RejectUnknownMembers specifies that unknown members should be rejected
|
||
|
// when unmarshaling a JSON object, regardless of whether there is a field
|
||
|
// to store unknown members.
|
||
|
RejectUnknownMembers bool
|
||
|
|
||
|
// formatDepth is the depth at which we respect the format flag.
|
||
|
formatDepth int
|
||
|
// format is custom formatting for the value at the specified depth.
|
||
|
format string
|
||
|
}
|
||
|
|
||
|
// Unmarshal deserializes a Go value from a []byte with default options.
|
||
|
// It is a thin wrapper over UnmarshalOptions.Unmarshal.
|
||
|
func Unmarshal(in []byte, out any) error {
|
||
|
return UnmarshalOptions{}.Unmarshal(DecodeOptions{}, in, out)
|
||
|
}
|
||
|
|
||
|
// UnmarshalFull deserializes a Go value from an io.Reader with default options.
|
||
|
// It is a thin wrapper over UnmarshalOptions.UnmarshalFull.
|
||
|
func UnmarshalFull(in io.Reader, out any) error {
|
||
|
return UnmarshalOptions{}.UnmarshalFull(DecodeOptions{}, in, out)
|
||
|
}
|
||
|
|
||
|
// Unmarshal deserializes a Go value from a []byte according to the
|
||
|
// provided unmarshal and decode options. The output must be a non-nil pointer.
|
||
|
// The input must be a single JSON value with optional whitespace interspersed.
|
||
|
// See UnmarshalNext for details about the conversion of JSON into a Go value.
|
||
|
func (uo UnmarshalOptions) Unmarshal(do DecodeOptions, in []byte, out any) error {
|
||
|
dec := getBufferedDecoder(in, do)
|
||
|
defer putBufferedDecoder(dec)
|
||
|
return uo.unmarshalFull(dec, out)
|
||
|
}
|
||
|
|
||
|
// UnmarshalFull deserializes a Go value from an io.Reader according to the
|
||
|
// provided unmarshal and decode options. The output must be a non-nil pointer.
|
||
|
// The input must be a single JSON value with optional whitespace interspersed.
|
||
|
// It consumes the entirety of io.Reader until io.EOF is encountered.
|
||
|
// See UnmarshalNext for details about the conversion of JSON into a Go value.
|
||
|
func (uo UnmarshalOptions) UnmarshalFull(do DecodeOptions, in io.Reader, out any) error {
|
||
|
dec := getStreamingDecoder(in, do)
|
||
|
defer putStreamingDecoder(dec)
|
||
|
return uo.unmarshalFull(dec, out)
|
||
|
}
|
||
|
func (uo UnmarshalOptions) unmarshalFull(in *Decoder, out any) error {
|
||
|
switch err := uo.UnmarshalNext(in, out); err {
|
||
|
case nil:
|
||
|
return in.checkEOF()
|
||
|
case io.EOF:
|
||
|
return io.ErrUnexpectedEOF
|
||
|
default:
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// UnmarshalNext decodes the next JSON value into a Go value according to
|
||
|
// the provided unmarshal options. 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.
|
||
|
// UnmarshalNext 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 UnmarshalOptions.Unmarshalers 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 UnmarshalerV2,
|
||
|
// then the UnmarshalNextJSON method is called to decode the JSON value.
|
||
|
//
|
||
|
// - If the value type implements UnmarshalerV1,
|
||
|
// 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 may also be decoded from a JSON string containing a JSON number
|
||
|
// if UnmarshalOptions.StringifyNumbers is specified.
|
||
|
// 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 may also be decoded from a JSON string containing a JSON number
|
||
|
// if UnmarshalOptions.StringifyNumbers is specified.
|
||
|
// The JSON number is parsed as the closest representable Go float value.
|
||
|
// 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. When decoding keys,
|
||
|
// UnmarshalOptions.StringifyNumbers is automatically applied so that
|
||
|
// numeric keys can decode from JSON strings. 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 only supported format is "emitnull" and has 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 only supported format is "emitnull" and has 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 resolution.
|
||
|
// If the format matches one of the format constants declared in
|
||
|
// the time package (e.g., RFC1123), then that format is used for parsing.
|
||
|
// Otherwise, the format is used as-is with time.Time.Parse if non-empty.
|
||
|
//
|
||
|
// - A Go time.Duration is decoded from a JSON string by
|
||
|
// passing the decoded string to time.ParseDuration.
|
||
|
// If the format is "nanos", it is instead decoded from a JSON number
|
||
|
// containing the number of nanoseconds in the duration.
|
||
|
//
|
||
|
// - 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 (uo UnmarshalOptions) UnmarshalNext(in *Decoder, out any) error {
|
||
|
v := reflect.ValueOf(out)
|
||
|
if !v.IsValid() || v.Kind() != reflect.Pointer || v.IsNil() {
|
||
|
var t reflect.Type
|
||
|
if v.IsValid() {
|
||
|
t = v.Type()
|
||
|
if t.Kind() == reflect.Pointer {
|
||
|
t = t.Elem()
|
||
|
}
|
||
|
}
|
||
|
err := errors.New("value must be passed as a non-nil pointer reference")
|
||
|
return &SemanticError{action: "unmarshal", GoType: t, Err: err}
|
||
|
}
|
||
|
va := addressableValue{v.Elem()} // dereferenced pointer is always addressable
|
||
|
t := va.Type()
|
||
|
|
||
|
// Lookup and call the unmarshal function for this type.
|
||
|
unmarshal := lookupArshaler(t).unmarshal
|
||
|
if uo.Unmarshalers != nil {
|
||
|
unmarshal, _ = uo.Unmarshalers.lookup(unmarshal, t)
|
||
|
}
|
||
|
if err := unmarshal(uo, in, va); err != nil {
|
||
|
if !in.options.AllowDuplicateNames {
|
||
|
in.tokens.invalidateDisabledNamespaces()
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
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 }
|
||
|
|
||
|
// newAddressableValue constructs a new addressable value of type t.
|
||
|
func newAddressableValue(t reflect.Type) addressableValue {
|
||
|
return addressableValue{reflect.New(t).Elem()}
|
||
|
}
|
||
|
|
||
|
// All marshal and unmarshal behavior is implemented using these signatures.
|
||
|
type (
|
||
|
marshaler = func(MarshalOptions, *Encoder, addressableValue) error
|
||
|
unmarshaler = func(UnmarshalOptions, *Decoder, addressableValue) 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)
|
||
|
}
|