This commit is contained in:
bluepython508 committed 2026-10-22 12:27:19 +01:00
1 parent 3530afb854
commit 6903fcff27
2146 files changed
+112256 -190703

No files matched your search

+258 -245
View File
@@ -11,6 +11,8 @@
// primitive data types such as booleans, strings, and numbers,
// in addition to structured data types such as objects and arrays.
//
// See the [Working with JSON] tutorial for an introduction to this package.
//
// [Marshal] and [Unmarshal] encode and decode Go values
// to/from JSON text contained within a []byte.
// [MarshalWrite] and [UnmarshalRead] operate on JSON text
@@ -55,7 +57,7 @@
// if [RejectUnknownMembers] is specified.
//
// The representation of each struct field can be customized in the
// "json" struct field tag, where the tag is a comma separated list of options.
// "json" struct field tag, where the tag is a comma-separated list of options.
// As a special case, if the entire tag is `json:"-"`,
// then the field is ignored with regard to its JSON representation.
// Some options also have equivalent behavior controlled by a caller-specified [Options].
@@ -63,11 +65,7 @@
//
// The first option is the JSON object name override for the Go struct field.
// If the name is not specified, then the Go struct field name
// is used as the JSON object name. JSON names containing commas or quotes,
// or names identical to "" or "-", can be specified using
// a single-quoted string literal, where the syntax is identical to
// the Go grammar for a double-quoted string literal,
// but instead uses single quotes as the delimiters.
// is used as the JSON object name.
// By default, unmarshaling uses case-sensitive matching to identify
// the Go struct field associated with a JSON object name.
//
@@ -84,60 +82,49 @@
// encoded as a JSON null, empty string, empty object, or empty array.
// This option has no effect when unmarshaling.
//
// - string: The "string" option specifies that [StringifyNumbers]
// be set when marshaling or unmarshaling a struct field value.
// This causes numeric types to be encoded as a JSON number
// within a JSON string, and to be decoded from a JSON string
// containing the JSON number without any surrounding whitespace.
// This extra level of encoding is often necessary since
// many JSON parsers cannot precisely represent 64-bit integers.
// - string: The "string" option specifies that [StringifyNumbers] be set
// when marshaling or unmarshaling a struct field value.
// This causes types that would normally be encoded as a JSON number
// to instead be encoded as a JSON number quoted within a JSON string,
// and to be decoded from a JSON string containing the JSON number
// without any surrounding whitespace.
// The "string" option only applies to the top-level of the Go struct field
// value. It is an error to apply this option to any type that does not
// encode as a JSON number.
// Note that composite types such as arrays, slices, structs, and maps do
// not encode as a JSON number, so applying this option will cause an error
// rather than affecting JSON numbers within such types.
// This extra level of encoding is often necessary since many JSON parsers
// cannot precisely represent 64-bit integers.
//
// - case: When unmarshaling, the "case" option specifies how
// JSON object names are matched with the JSON name for Go struct fields.
// The option is a key-value pair specified as "case:value" where
// the value must either be 'ignore' or 'strict'.
// The 'ignore' value specifies that matching is case-insensitive
// where dashes and underscores are also ignored. If multiple fields match,
// the first declared field in breadth-first order takes precedence.
// The 'ignore' value specifies that matching is case-insensitive,
// and also ignores dashes and underscores. If multiple fields match,
// then the field with an exact name match is selected, otherwise an error
// is reported because the choice of field to unmarshal into is ambiguous.
// The 'strict' value specifies that matching is case-sensitive.
// This takes precedence over the [MatchCaseInsensitiveNames] option.
//
// - inline: The "inline" option specifies that
// - embed: The "embed" option specifies that
// the JSON representable content of this field type is to be promoted
// as if they were specified in the parent struct.
// as if it were specified in the parent struct.
// It is the JSON equivalent of Go struct embedding.
// A Go embedded field is implicitly inlined unless an explicit JSON name
// is specified. The inlined field must be a Go struct
// A Go embedded field is implicitly JSON embedded unless
// an explicit JSON name is specified. The embedded field must be a Go struct
// (that does not implement any JSON methods), [jsontext.Value],
// map[~string]T, or an unnamed pointer to such types. When marshaling,
// inlined fields from a pointer type are omitted if it is nil.
// Inlined fields of type [jsontext.Value] and map[~string]T are called
// “inlined fallbacks” as they can represent all possible
// embedded fields from a pointer type are omitted if it is nil.
// Embedded fields of type [jsontext.Value] and map[~string]T are called
// “embedded fallbacks” as they can represent all possible
// JSON object members not directly handled by the parent struct.
// Only one inlined fallback field may be specified in a struct,
// Only one embedded fallback field may be specified in a struct,
// while many non-fallback fields may be specified. This option
// must not be specified with any other option (including the JSON name).
//
// - unknown: The "unknown" option is a specialized variant
// of the inlined fallback to indicate that this Go struct field
// contains any number of unknown JSON object members. The field type must
// be a [jsontext.Value], map[~string]T, or an unnamed pointer to such types.
// If [DiscardUnknownMembers] is specified when marshaling,
// the contents of this field are ignored.
// If [RejectUnknownMembers] is specified when unmarshaling,
// any unknown object members are rejected regardless of whether
// an inlined fallback with the "unknown" option exists. This option
// must not be specified with any other option (including the JSON name).
//
// - format: The "format" option specifies a format flag
// used to specialize the formatting of the field value.
// The option is a key-value pair specified as "format:value" where
// the value must be either a literal consisting of letters and numbers
// (e.g., "format:RFC3339") or a single-quoted string literal
// (e.g., "format:'2006-01-02'"). The interpretation of the format flag
// is determined by the struct field type.
//
// The "omitzero" and "omitempty" options are mostly semantically identical.
// The "omitzero" and "omitempty" options behave similarly.
// The former is defined in terms of the Go type system,
// while the latter in terms of the JSON type system.
// Consequently they behave differently in some circumstances.
@@ -146,14 +133,14 @@
// The "omitzero" option is useful for types with a well-defined zero value
// (e.g., [net/netip.Addr]) or have an IsZero method (e.g., [time.Time.IsZero]).
//
// Every Go struct corresponds to a list of JSON representable fields
// Every Go struct corresponds to a list of JSON-representable fields
// which is constructed by performing a breadth-first search over
// all struct fields (excluding unexported or ignored fields),
// where the search recursively descends into inlined structs.
// The set of non-inlined fields in a struct must have unique JSON names.
// where the search recursively descends into embedded structs.
// The set of non-embedded fields in a struct must have unique JSON names.
// If multiple fields all have the same JSON name, then the one
// at shallowest depth takes precedence and the other fields at deeper depths
// are excluded from the list of JSON representable fields.
// are excluded from the list of JSON-representable fields.
// If multiple fields at the shallowest depth have the same JSON name,
// but exactly one is explicitly tagged with a JSON name,
// then that field takes precedence and all others are excluded from the list.
@@ -161,7 +148,7 @@
// with embedded struct types.
//
// Marshaling or unmarshaling a non-empty struct
// without any JSON representable fields results in a [SemanticError].
// without any JSON-representable fields results in a [SemanticError].
// Unexported fields must not have any `json` tags except for `json:"-"`.
//
// # Security Considerations
@@ -173,8 +160,8 @@
//
// [For example, suppose we have two micro-services.]
// The first service is responsible for authenticating a JSON request,
// while the second service is responsible for executing the request
// (having assumed that the prior service authenticated the request).
// while the second service is responsible for executing the request,
// assuming that it was authenticated.
// If an attacker were able to maliciously craft a JSON request such that
// both services believe that the same request is from different users,
// it could bypass the authenticator with valid credentials for one user,
@@ -256,6 +243,7 @@
// The v2 API generally chooses more secure defaults than v1,
// but care should still be taken with large integers or unknown members.
//
// [Working with JSON]: https://go.dev/doc/tutorial/json
// [For example, suppose we have two micro-services.]: https://www.youtube.com/watch?v=avilmOcHKHE&t=1057s
package json
@@ -274,19 +262,21 @@ import (
// 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
// (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 the following rules:
// 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 [SkipFunc],
// 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.
@@ -302,51 +292,31 @@ import (
// - 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:
// Most Go types have a default JSON representation 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 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.
// 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].
// 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.
// 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.
// 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
@@ -354,53 +324,33 @@ import (
//
// - 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.
// 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.
// 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.
// 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.
// Passing cyclic structures will result in an error.
func Marshal(in any, opts ...Options) (out []byte, err error) {
opts = mayAppendSupportFormatTag(opts)
return json.Marshal(in, opts...)
}
@@ -409,18 +359,18 @@ func Marshal(in any, opts ...Options) (out []byte, err error) {
// 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) {
opts = mayAppendSupportFormatTag(opts)
return json.MarshalWrite(out, in, opts...)
}
// 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].
// 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 MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) {
opts = mayAppendSupportFormatTag(opts)
return json.MarshalEncode(out, in, opts...)
}
@@ -434,18 +384,24 @@ func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) {
// 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
// (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 the following rules:
// 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 [SkipFunc],
// 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.
@@ -459,10 +415,6 @@ func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) {
// 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,
@@ -472,20 +424,11 @@ func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) {
// 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.
// - 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,
@@ -497,15 +440,13 @@ func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) {
// 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].
// 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
@@ -513,7 +454,6 @@ func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) {
// 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
@@ -523,20 +463,17 @@ func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) {
// 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.
@@ -548,28 +485,15 @@ func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) {
// 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.
// 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.
// 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.
// 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].
@@ -580,6 +504,7 @@ func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) {
// 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) {
opts = mayAppendSupportFormatTag(opts)
return json.Unmarshal(in, out, opts...)
}
@@ -590,33 +515,25 @@ func Unmarshal(in []byte, out any, opts ...Options) (err error) {
// 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) {
opts = mayAppendSupportFormatTag(opts)
return json.UnmarshalRead(in, out, opts...)
}
// 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 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 one or more JSON values,
// where this only unmarshals the next JSON value in the stream.
// 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 UnmarshalDecode(in *jsontext.Decoder, out any, opts ...Options) (err error) {
opts = mayAppendSupportFormatTag(opts)
return json.UnmarshalDecode(in, out, opts...)
}
// SkipFunc may be returned by [MarshalToFunc] and [UnmarshalFromFunc] functions.
//
// Any function that returns SkipFunc must not cause observable side effects
// on the provided [jsontext.Encoder] or [jsontext.Decoder].
// For example, it is permissible to call [jsontext.Decoder.PeekKind],
// but not permissible to call [jsontext.Decoder.ReadToken] or
// [jsontext.Encoder.WriteToken] since such methods mutate the state.
var SkipFunc = json.SkipFunc
// Marshalers is a list of functions that may override the marshal behavior
// of specific types. Populate [WithMarshalers] to use it with
// [Marshal], [MarshalWrite], or [MarshalEncode].
@@ -627,7 +544,8 @@ type Marshalers = json.Marshalers
// JoinMarshalers constructs a flattened list of marshal functions.
// If multiple functions in the list are applicable for a value of a given type,
// then those earlier in the list take precedence over those that come later.
// If a function returns [SkipFunc], then the next applicable function is called,
// If a function returns [errors.ErrUnsupported],
// then the next applicable function is called,
// otherwise the default marshaling behavior is used.
//
// For example:
@@ -649,7 +567,8 @@ type Unmarshalers = json.Unmarshalers
// JoinUnmarshalers constructs a flattened list of unmarshal functions.
// If multiple functions in the list are applicable for a value of a given type,
// then those earlier in the list take precedence over those that come later.
// If a function returns [SkipFunc], then the next applicable function is called,
// If a function returns [errors.ErrUnsupported],
// then the next applicable function is called,
// otherwise the default unmarshaling behavior is used.
//
// For example:
@@ -667,9 +586,9 @@ func JoinUnmarshalers(us ...*Unmarshalers) *Unmarshalers {
// The function is always provided with a non-nil pointer value
// if T is an interface or pointer type.
//
// The function must marshal exactly one JSON value.
// The value of T must not be retained outside the function call.
// It may not return [SkipFunc].
// Implementations must follow the requirements of [Marshaler].
//
// Implementations must not retain the value of T.
func MarshalFunc[T any](fn func(T) ([]byte, error)) *Marshalers {
return json.MarshalFunc[T](fn)
}
@@ -680,12 +599,10 @@ func MarshalFunc[T any](fn func(T) ([]byte, error)) *Marshalers {
// The function is always provided with a non-nil pointer value
// if T is an interface or pointer type.
//
// The function must marshal exactly one JSON value by calling write methods
// on the provided encoder. It may return [SkipFunc] such that marshaling can
// move on to the next marshal function. However, no mutable method calls may
// be called on the encoder if [SkipFunc] is returned.
// The pointer to [jsontext.Encoder] and the value of T
// must not be retained outside the function call.
// Implementations must follow the requirements of [MarshalerTo].
//
// Implementations must not retain the pointer to [jsontext.Encoder] or the
// value of T.
func MarshalToFunc[T any](fn func(*jsontext.Encoder, T) error) *Marshalers {
return json.MarshalToFunc[T](fn)
}
@@ -695,10 +612,9 @@ func MarshalToFunc[T any](fn func(*jsontext.Encoder, T) error) *Marshalers {
// T must be an unnamed pointer or an interface type.
// The function is always provided with a non-nil pointer value.
//
// The function must unmarshal exactly one JSON value.
// The input []byte must not be mutated.
// The input []byte and value T must not be retained outside the function call.
// It may not return [SkipFunc].
// Implementations must follow the requirements of [Unmarshaler].
//
// Implementations must not retain the value of T.
func UnmarshalFunc[T any](fn func([]byte, T) error) *Unmarshalers {
return json.UnmarshalFunc[T](fn)
}
@@ -708,60 +624,133 @@ func UnmarshalFunc[T any](fn func([]byte, T) error) *Unmarshalers {
// T must be an unnamed pointer or an interface type.
// The function is always provided with a non-nil pointer value.
//
// The function must unmarshal exactly one JSON value by calling read methods
// on the provided decoder. It may return [SkipFunc] such that unmarshaling can
// move on to the next unmarshal function. However, no mutable method calls may
// be called on the decoder if [SkipFunc] is returned.
// The pointer to [jsontext.Decoder] and the value of T
// must not be retained outside the function call.
// Implementations must follow the requirements of [UnmarshalerFrom].
//
// Implementations must not retain the pointer to [jsontext.Decoder] or the
// value of T.
func UnmarshalFromFunc[T any](fn func(*jsontext.Decoder, T) error) *Unmarshalers {
return json.UnmarshalFromFunc[T](fn)
}
// Marshaler is implemented by types that can marshal themselves.
// It is recommended that types implement [MarshalerTo] unless the implementation
// is trying to avoid a hard dependency on the "jsontext" package.
// is trying to avoid directly depending on the "jsontext" package.
//
// It is recommended that implementations return a buffer that is safe
// Implementations should return a buffer that is safe
// for the caller to retain and potentially mutate.
//
// Implementations must not return [errors.ErrUnsupported].
//
// If the returned error is a [SemanticError], then unpopulated fields
// of the error may be populated by [json] with additional context.
// Errors of other types are wrapped within a [SemanticError].
//
// Implementations should assume [Deterministic] is true and return
// deterministic output.
type Marshaler = json.Marshaler
// MarshalerTo is implemented by types that can marshal themselves.
// It is recommended that types implement MarshalerTo instead of [Marshaler]
// since this is both more performant and flexible.
// since it is both more performant and more flexible.
// If a type implements both Marshaler and MarshalerTo,
// then MarshalerTo takes precedence. In such a case, both implementations
// should aim to have equivalent behavior for the default marshal options.
//
// The implementation must write only one JSON value to the Encoder and
// must not retain the pointer to [jsontext.Encoder].
// The implementation must write only one JSON value to the Encoder.
// Alternatively, it may return [errors.ErrUnsupported] without mutating
// the Encoder. The "json" package calling the method will
// use the next available JSON representation for the receiver type,
// as described in [Marshal].
// Implementations must not retain the pointer to [jsontext.Encoder].
//
// If the returned error is a [SemanticError], then unpopulated fields
// of the error may be populated by [json] with additional context.
// Errors of other types are wrapped within a [SemanticError],
// except for IO errors.
//
// The MarshalJSONTo method should not be called directly as it may
// return sentinel errors that need special handling.
// Users should instead call [MarshalEncode], which handles such cases.
//
// Implementations should inspect the marshal options from
// [jsontext.Encoder.Options] and adjust behavior to respect the options as
// necessary.
//
// The following options may be relevant to MarshalerTo implementations:
//
// - [Deterministic]: if the implementation may produce non-deterministic output
// - [StringifyNumbers]: if the type is represented as a JSON number
//
// Several options, such as [FormatNilSliceAsNull], apply only to native Go
// types. Thus, these options are typically not directly relevant to
// MarshalerTo implementations. However, types representing a composite type
// should marshal contained types using [MarshalEncode] to ensure these options
// apply to the contained types. Similarly, [WithMarshalers] may influence
// marshaling of any contained type within a composite type.
//
// All other options are automatically handled outside of the MarshalerTo
// implementation, and thus are not relevant to implementations.
type MarshalerTo = json.MarshalerTo
// Unmarshaler is implemented by types that can unmarshal themselves.
// It is recommended that types implement [UnmarshalerFrom] unless the implementation
// is trying to avoid a hard dependency on the "jsontext" package.
// is trying to avoid a direct dependency on the "jsontext" package.
//
// The input can be assumed to be a valid encoding of a JSON value
// if called from unmarshal functionality in this package.
// UnmarshalJSON must copy the JSON data if it is retained after returning.
// It is recommended that UnmarshalJSON implement merge semantics when
// unmarshaling into a pre-populated value.
// It is recommended that UnmarshalJSON implement merge semantics
// when unmarshaling into a pre-populated value, as described in [Unmarshal].
//
// Implementations must not retain or mutate the input []byte.
//
// Implementations must not return [errors.ErrUnsupported].
//
// If the returned error is a [SemanticError], then unpopulated fields
// of the error may be populated by [json] with additional context.
// Errors of other types are wrapped within a [SemanticError].
type Unmarshaler = json.Unmarshaler
// UnmarshalerFrom is implemented by types that can unmarshal themselves.
// It is recommended that types implement UnmarshalerFrom instead of [Unmarshaler]
// since this is both more performant and flexible.
// since this is both more performant and more flexible.
// If a type implements both Unmarshaler and UnmarshalerFrom,
// then UnmarshalerFrom takes precedence. In such a case, both implementations
// should aim to have equivalent behavior for the default unmarshal options.
//
// The implementation must read only one JSON value from the Decoder.
// It is recommended that UnmarshalJSONFrom implement merge semantics when
// unmarshaling into a pre-populated value.
//
// unmarshaling into a pre-populated value, as described in [Unmarshal].
// Alternatively, it may return [errors.ErrUnsupported] without mutating
// the Decoder. The "json" package calling the method will
// use the next available JSON representation for the receiver type.
// Implementations must not retain the pointer to [jsontext.Decoder].
//
// If the returned error is a [SemanticError], then unpopulated fields
// of the error may be populated by [json] with additional context.
// Errors of other types are wrapped within a [SemanticError],
// except for [jsontext.SyntacticError]s and IO errors.
//
// The UnmarshalJSONFrom method should not be called directly as it may
// return sentinel errors that need special handling.
// Users should instead call [UnmarshalDecode], which handles such cases.
//
// Implementations should inspect the unmarshal options from
// [jsontext.Decoder.Options] and adjust behavior to respect the options as
// necessary.
//
// The following options may be relevant to UnmarshalerFrom implementations:
//
// - [StringifyNumbers]: if the type is represented as a JSON number
//
// Several options, such as [FormatNilSliceAsNull], apply only to native Go
// types. Thus, these options are typically not directly relevant to
// UnmarshalerFrom implementations. However, types representing a composite
// type should unmarshal contained types using [UnmarshalDecode] to ensure
// these options apply to the contained types. Similarly, [WithUnmarshalers]
// may influence unmarshaling of any contained type within a composite type.
//
// All other options are automatically handled outside of the UnmarshalerFrom
// implementation, and thus are not relevant to implementations.
type UnmarshalerFrom = json.UnmarshalerFrom
// ErrUnknownName indicates that a JSON object member could not be
@@ -771,8 +760,8 @@ type UnmarshalerFrom = json.UnmarshalerFrom
// The name of an unknown JSON object member can be extracted as:
//
// err := ...
// var serr json.SemanticError
// if errors.As(err, &serr) && serr.Err == json.ErrUnknownName {
// serr, ok := errors.AsType[*json.SemanticError](err)
// if ok && serr.Err == json.ErrUnknownName {
// ptr := serr.JSONPointer // JSON pointer to unknown name
// name := ptr.LastToken() // unknown name itself
// ...
@@ -782,7 +771,12 @@ type UnmarshalerFrom = json.UnmarshalerFrom
var ErrUnknownName = json.ErrUnknownName
// SemanticError describes an error determining the meaning
// of JSON data as Go data or vice-versa.
// of JSON data as Go data, or vice versa.
//
// If a [Marshaler], [MarshalerTo], [Unmarshaler], or [UnmarshalerFrom] method
// returns a SemanticError when called by the [json] package,
// then the ByteOffset, JSONPointer, and GoType fields are automatically
// populated by the calling context if they are the zero value.
//
// The contents of this error as produced by this package may change over time.
type SemanticError = json.SemanticError
@@ -796,11 +790,11 @@ type SemanticError = json.SemanticError
// [encoding/json/jsontext.Options]. Options from the other packages can
// be used interchangeably with functionality in this package.
//
// Options represent either a singular option or a set of options.
// It can be functionally thought of as a Go map of option properties
// An Options value represents either a single option or a set of options.
// It can be thought of as a Go map of option properties
// (even though the underlying implementation avoids Go maps for performance).
//
// The constructors (e.g., [Deterministic]) return a singular option value:
// The constructors (e.g., [Deterministic]) return a value for a single option:
//
// opt := Deterministic(true)
//
@@ -808,7 +802,7 @@ type SemanticError = json.SemanticError
//
// opt := Options{"Deterministic": true}
//
// [JoinOptions] composes multiple options values to together:
// [JoinOptions] composes multiple options values together:
//
// out := JoinOptions(opts...)
//
@@ -821,7 +815,7 @@ type SemanticError = json.SemanticError
// }
// }
//
// [GetOption] looks up the value of options parameter:
// [GetOption] looks up the value of an options parameter:
//
// v, ok := GetOption(opts, Deterministic)
//
@@ -838,7 +832,6 @@ type SemanticError = json.SemanticError
// - [FormatNilMapAsNull] affects marshaling only
// - [OmitZeroStructFields] affects marshaling only
// - [MatchCaseInsensitiveNames] affects marshaling and unmarshaling
// - [DiscardUnknownMembers] affects marshaling only
// - [RejectUnknownMembers] affects unmarshaling only
// - [WithMarshalers] affects marshaling only
// - [WithUnmarshalers] affects unmarshaling only
@@ -854,6 +847,7 @@ func JoinOptions(srcs ...Options) Options {
// GetOption returns the value stored in opts with the provided setter,
// reporting whether the value is present.
// If not present, the returned value is the zero value for type T.
//
// Example usage:
//
@@ -868,18 +862,33 @@ func GetOption[T any](opts Options, setter func(T) Options) (T, bool) {
}
// DefaultOptionsV2 is the full set of all options that define v2 semantics.
// It is equivalent to all options under [Options], [encoding/json.Options],
// and [encoding/json/jsontext.Options] being set to false or the zero value,
// except for the options related to whitespace formatting.
// It is equivalent to the set of options in [encoding/json.DefaultOptionsV1]
// all being set to false. All other options are not present.
func DefaultOptionsV2() Options {
return json.DefaultOptionsV2()
}
// StringifyNumbers specifies that numeric Go types should be marshaled
// as a JSON string containing the equivalent JSON number value.
// When unmarshaling, numeric Go types are parsed from a JSON string
// StringifyNumbers specifies that types that would normally be
// encoded as a JSON number instead be encoded as a JSON string
// containing the equivalent JSON number value.
// When unmarshaling, the value is parsed from a JSON string
// containing the JSON number without any surrounding whitespace.
//
// Specifying the `string` tag option on a Go struct field applies this option
// to the top-level JSON value for that field. When applied via the `string`
// tag option, StringifyNumbers option does not recursively apply to nested
// JSON numbers within a JSON object or array.
//
// Like all options, explicitly specifying this option in a call to [Marshal],
// [Unmarshal], etc, will apply recursively.
//
// A Go type with custom marshal/unmarshal that represents a JSON number
// should respect the StringifyNumbers option and if specified
// serialize as a JSON number within a JSON string.
// Custom marshal/unmarshal should handle nested JSON objects using
// [MarshalEncode]/[UnmarshalDecode], which will automatically apply the
// non-recursive `string` tag option behavior.
//
// 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.
@@ -890,11 +899,18 @@ func StringifyNumbers(v bool) Options {
return json.StringifyNumbers(v)
}
// 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 specifies that marshaling the same input value will always
// serialize as the same output bytes.
//
// For example, Go maps are marshaled sorted by key.
//
// For native Go types, Determinism is guaranteed across different instances of
// identical binaries, but not across different builds of a program (such as
// different source or toolchain version, different GOOS/GOARCH, different
// build flags).
//
// A Go type with a custom marshaler should also respect the Deterministic
// option and serialize deterministically if it is true.
//
// This only affects marshaling and is ignored when unmarshaling.
func Deterministic(v bool) Options {
@@ -904,8 +920,6 @@ func Deterministic(v bool) Options {
// FormatNilSliceAsNull specifies that a nil Go slice should marshal as a
// JSON null instead of the default representation as an empty JSON array
// (or an empty JSON string in the case of ~[]byte).
// Slice fields explicitly marked with `format:emitempty` still marshal
// as an empty JSON array.
//
// This only affects marshaling and is ignored when unmarshaling.
func FormatNilSliceAsNull(v bool) Options {
@@ -914,19 +928,17 @@ func FormatNilSliceAsNull(v bool) Options {
// FormatNilMapAsNull specifies that a nil Go map should marshal as a
// JSON null instead of the default representation as an empty JSON object.
// Map fields explicitly marked with `format:emitempty` still marshal
// as an empty JSON object.
//
// This only affects marshaling and is ignored when unmarshaling.
func FormatNilMapAsNull(v bool) Options {
return json.FormatNilMapAsNull(v)
}
// OmitZeroStructFields specifies that a Go struct should marshal in such a way
// that all struct fields that are zero are omitted from the marshaled output
// if the value is zero as determined by the "IsZero() bool" method if present,
// otherwise based on whether the field is the zero Go value.
// This is semantically equivalent to specifying the `omitzero` tag option
// OmitZeroStructFields specifies that zero-valued fields of Go struct should be
// omitted from the marshaled output.
// A value is considered zero if its type has an "IsZero() bool" method that returns true,
// or if it lacks such a method and the value is a Go zero value.
// This option is equivalent to specifying the `omitzero` tag option
// on every field in a Go struct.
//
// This only affects marshaling and is ignored when unmarshaling.
@@ -936,30 +948,31 @@ func OmitZeroStructFields(v bool) Options {
// MatchCaseInsensitiveNames specifies that JSON object members are matched
// against Go struct fields using a case-insensitive match of the name.
// If a name matches multiple fields, the field whose name matches exactly is chosen.
// If there is none, an error is reported.
// Go struct fields explicitly marked with `case:strict` or `case:ignore`
// always use case-sensitive (or case-insensitive) name matching,
// regardless of the value of this option.
//
// This affects either marshaling or unmarshaling.
// For marshaling, this option may alter the detection of duplicate names
// (assuming [jsontext.AllowDuplicateNames] is false) from inlined fields
// if it matches one of the declared fields in the Go struct.
//
// Matching names case-insensitively also affects duplicate name detection
// (assuming [jsontext.AllowDuplicateNames] is false) since
// variations of the same name may match the same Go struct field.
// For example, when unmarshaling, the names "foo" and "Foo" may both
// match the same Go struct field and therefore be considered a duplicate name.
// When marshaling, normally it is impossible for any two Go struct fields to
// serialize in a way where they unmarshal into the same Go struct field
// since they all have unique exact names.
// However, it is possible for an
// embedded fallback to contain a name that also matches the name for
// a Go struct field, resulting in a duplicate name error.
func MatchCaseInsensitiveNames(v bool) Options {
return json.MatchCaseInsensitiveNames(v)
}
// DiscardUnknownMembers specifies that marshaling should ignore any
// JSON object members stored in Go struct fields dedicated to storing
// unknown JSON object members.
//
// This only affects marshaling and is ignored when unmarshaling.
func DiscardUnknownMembers(v bool) Options {
return json.DiscardUnknownMembers(v)
}
// RejectUnknownMembers specifies that unknown members should be rejected
// when unmarshaling a JSON object, regardless of whether there is a field
// to store unknown members.
// when unmarshaling a JSON object.
//
// This only affects unmarshaling and is ignored when marshaling.
func RejectUnknownMembers(v bool) Options {