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

+338 -205
View File
@@ -35,7 +35,7 @@ import (
const optimizeCommon = true
var (
// Most natural Go type that correspond with each JSON type.
// Most natural Go types that correspond with each JSON type.
anyType = reflect.TypeFor[any]() // JSON value
boolType = reflect.TypeFor[bool]() // JSON bool
stringType = reflect.TypeFor[string]() // JSON string
@@ -127,12 +127,19 @@ func makeBoolArshaler(t reflect.Type) *arshaler {
var fncs arshaler
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
xe := export.Encoder(enc)
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
return newInvalidFormatError(enc, t, mo)
var stringify bool // always false except `string` tag with StringifyWithLegacySemantics
if mo.Flags.Has(jsonflags.TagFlags) {
stringify = mo.Flags.Get(jsonflags.StringTag) && mo.Flags.Get(jsonflags.StringifyWithLegacySemantics)
if mo.Flags.Get(jsonflags.StringTag) && !mo.Flags.Get(jsonflags.StringifyWithLegacySemantics|jsonflags.ReportErrorsWithLegacySemantics) {
return newMarshalErrorBefore(enc, t, errInvalidStringTag)
}
if mo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(enc, t)
}
}
// Optimize for marshaling without preceding whitespace.
if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyBoolsAndStrings) && !xe.Tokens.Last.NeedObjectName() {
if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace) && !stringify && !xe.Tokens.Last.NeedObjectName() {
xe.Buf = strconv.AppendBool(xe.Tokens.MayAppendDelim(xe.Buf, 't'), va.Bool())
xe.Tokens.Last.Increment()
if xe.NeedFlush() {
@@ -141,7 +148,7 @@ func makeBoolArshaler(t reflect.Type) *arshaler {
return nil
}
if mo.Flags.Get(jsonflags.StringifyBoolsAndStrings) {
if stringify {
if va.Bool() {
return enc.WriteToken(jsontext.String("true"))
} else {
@@ -151,9 +158,15 @@ func makeBoolArshaler(t reflect.Type) *arshaler {
return enc.WriteToken(jsontext.Bool(va.Bool()))
}
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
xd := export.Decoder(dec)
if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
return newInvalidFormatError(dec, t, uo)
var stringify bool // always false except `string` tag with StringifyWithLegacySemantics
if uo.Flags.Has(jsonflags.TagFlags) {
stringify = uo.Flags.Get(jsonflags.StringTag) && uo.Flags.Get(jsonflags.StringifyWithLegacySemantics)
if uo.Flags.Get(jsonflags.StringTag) && !uo.Flags.Get(jsonflags.StringifyWithLegacySemantics|jsonflags.ReportErrorsWithLegacySemantics) {
return newUnmarshalErrorBeforeWithSkipping(dec, t, errInvalidStringTag)
}
if uo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(dec, t)
}
}
tok, err := dec.ReadToken()
if err != nil {
@@ -167,12 +180,12 @@ func makeBoolArshaler(t reflect.Type) *arshaler {
}
return nil
case 't', 'f':
if !uo.Flags.Get(jsonflags.StringifyBoolsAndStrings) {
if !stringify {
va.SetBool(tok.Bool())
return nil
}
case '"':
if uo.Flags.Get(jsonflags.StringifyBoolsAndStrings) {
if stringify {
switch tok.String() {
case "true":
va.SetBool(true)
@@ -190,7 +203,7 @@ func makeBoolArshaler(t reflect.Type) *arshaler {
return nil
}
}
return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil)
return newUnmarshalErrorAfterWithSkipping(dec, t, nil)
}
return &fncs
}
@@ -199,16 +212,23 @@ func makeStringArshaler(t reflect.Type) *arshaler {
var fncs arshaler
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
xe := export.Encoder(enc)
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
return newInvalidFormatError(enc, t, mo)
var stringify bool // always false except `string` tag with StringifyWithLegacySemantics
if mo.Flags.Has(jsonflags.TagFlags) {
stringify = mo.Flags.Get(jsonflags.StringTag) && mo.Flags.Get(jsonflags.StringifyWithLegacySemantics)
if mo.Flags.Get(jsonflags.StringTag) && !mo.Flags.Get(jsonflags.StringifyWithLegacySemantics|jsonflags.ReportErrorsWithLegacySemantics) {
return newMarshalErrorBefore(enc, t, errInvalidStringTag)
}
if mo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(enc, t)
}
}
// Optimize for marshaling without preceding whitespace.
s := va.String()
if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyBoolsAndStrings) && !xe.Tokens.Last.NeedObjectName() {
if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace) && !stringify && !xe.Tokens.Last.NeedObjectName() {
b := xe.Buf
b = xe.Tokens.MayAppendDelim(b, '"')
b, err := jsonwire.AppendQuote(b, s, &mo.Flags)
b, err := jsonwire.AppendQuote(b, []byte(s), &mo.Flags)
if err == nil {
xe.Buf = b
xe.Tokens.Last.Increment()
@@ -221,8 +241,8 @@ func makeStringArshaler(t reflect.Type) *arshaler {
// so let the logic below construct the proper error.
}
if mo.Flags.Get(jsonflags.StringifyBoolsAndStrings) {
b, err := jsonwire.AppendQuote(nil, s, &mo.Flags)
if stringify {
b, err := jsonwire.AppendQuote(nil, []byte(s), &mo.Flags)
if err != nil {
return newMarshalErrorBefore(enc, t, &jsontext.SyntacticError{Err: err})
}
@@ -236,8 +256,15 @@ func makeStringArshaler(t reflect.Type) *arshaler {
}
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
xd := export.Decoder(dec)
if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
return newInvalidFormatError(dec, t, uo)
var stringify bool // always false except `string` tag with StringifyWithLegacySemantics
if uo.Flags.Has(jsonflags.TagFlags) {
stringify = uo.Flags.Get(jsonflags.StringTag) && uo.Flags.Get(jsonflags.StringifyWithLegacySemantics)
if uo.Flags.Get(jsonflags.StringTag) && !uo.Flags.Get(jsonflags.StringifyWithLegacySemantics|jsonflags.ReportErrorsWithLegacySemantics) {
return newUnmarshalErrorBeforeWithSkipping(dec, t, errInvalidStringTag)
}
if uo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(dec, t)
}
}
var flags jsonwire.ValueFlags
val, err := xd.ReadValue(&flags)
@@ -253,7 +280,7 @@ func makeStringArshaler(t reflect.Type) *arshaler {
return nil
case '"':
val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim())
if uo.Flags.Get(jsonflags.StringifyBoolsAndStrings) {
if stringify {
val, err = jsontext.AppendUnquote(nil, val)
if err != nil {
return newUnmarshalErrorAfter(dec, t, err)
@@ -311,32 +338,37 @@ func makeBytesArshaler(t reflect.Type, fncs *arshaler) *arshaler {
}
xe := export.Encoder(enc)
appendEncode := appendEncodeBase64
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
switch mo.Format {
case "base64":
appendEncode = appendEncodeBase64
case "base64url":
appendEncode = appendEncodeBase64URL
case "base32":
appendEncode = appendEncodeBase32
case "base32hex":
appendEncode = appendEncodeBase32Hex
case "base16", "hex":
appendEncode = appendEncodeBase16
case "array":
mo.Format = ""
if mo.Flags.Has(jsonflags.TagFlags | jsonflags.FormatByteArrayAsArray | jsonflags.FormatBytesWithLegacySemantics | jsonflags.FormatNilSliceAsNull) {
switch {
case mo.Flags.Get(jsonflags.StringTag) && !mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics):
return newMarshalErrorBefore(enc, t, errInvalidStringTag)
case mo.Flags.Has(jsonflags.FormatTag):
switch mo.Format {
case "base64":
appendEncode = appendEncodeBase64
case "base64url":
appendEncode = appendEncodeBase64URL
case "base32":
appendEncode = appendEncodeBase32
case "base32hex":
appendEncode = appendEncodeBase32Hex
case "base16", "hex":
appendEncode = appendEncodeBase16
case "array":
mo.Flags.Clear(jsonflags.FormatTag)
return marshalArray(enc, va, mo)
default:
return newInvalidFormatError(enc, t)
}
case mo.Flags.Get(jsonflags.FormatByteArrayAsArray) && va.Kind() == reflect.Array:
return marshalArray(enc, va, mo)
case mo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && hasMarshaler:
return marshalArray(enc, va, mo)
default:
return newInvalidFormatError(enc, t, mo)
}
} else if mo.Flags.Get(jsonflags.FormatByteArrayAsArray) && va.Kind() == reflect.Array {
return marshalArray(enc, va, mo)
} else if mo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && hasMarshaler {
return marshalArray(enc, va, mo)
}
if mo.Flags.Get(jsonflags.FormatNilSliceAsNull) && va.Kind() == reflect.Slice && va.IsNil() {
// TODO: Provide a "emitempty" format override?
return enc.WriteToken(jsontext.Null)
if mo.Flags.Get(jsonflags.FormatNilSliceAsNull) && va.Kind() == reflect.Slice && va.IsNil() {
// TODO: Provide an "emitempty" format override?
return enc.WriteToken(jsontext.Null)
}
}
return xe.AppendRaw('"', true, func(b []byte) ([]byte, error) {
return appendEncode(b, va.Bytes()), nil
@@ -349,28 +381,33 @@ func makeBytesArshaler(t reflect.Type, fncs *arshaler) *arshaler {
}
xd := export.Decoder(dec)
appendDecode, encodedLen := appendDecodeBase64, encodedLenBase64
if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
switch uo.Format {
case "base64":
appendDecode, encodedLen = appendDecodeBase64, encodedLenBase64
case "base64url":
appendDecode, encodedLen = appendDecodeBase64URL, encodedLenBase64URL
case "base32":
appendDecode, encodedLen = appendDecodeBase32, encodedLenBase32
case "base32hex":
appendDecode, encodedLen = appendDecodeBase32Hex, encodedLenBase32Hex
case "base16", "hex":
appendDecode, encodedLen = appendDecodeBase16, encodedLenBase16
case "array":
uo.Format = ""
if uo.Flags.Has(jsonflags.TagFlags | jsonflags.FormatByteArrayAsArray | jsonflags.FormatBytesWithLegacySemantics) {
switch {
case uo.Flags.Get(jsonflags.StringTag) && !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics):
return newUnmarshalErrorBeforeWithSkipping(dec, t, errInvalidStringTag)
case uo.Flags.Has(jsonflags.FormatTag):
switch uo.Format {
case "base64":
appendDecode, encodedLen = appendDecodeBase64, encodedLenBase64
case "base64url":
appendDecode, encodedLen = appendDecodeBase64URL, encodedLenBase64URL
case "base32":
appendDecode, encodedLen = appendDecodeBase32, encodedLenBase32
case "base32hex":
appendDecode, encodedLen = appendDecodeBase32Hex, encodedLenBase32Hex
case "base16", "hex":
appendDecode, encodedLen = appendDecodeBase16, encodedLenBase16
case "array":
uo.Flags.Clear(jsonflags.FormatTag)
return unmarshalArray(dec, va, uo)
default:
return newInvalidFormatError(dec, t)
}
case uo.Flags.Get(jsonflags.FormatByteArrayAsArray) && va.Kind() == reflect.Array:
return unmarshalArray(dec, va, uo)
case uo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && dec.PeekKind() == '[':
return unmarshalArray(dec, va, uo)
default:
return newInvalidFormatError(dec, t, uo)
}
} else if uo.Flags.Get(jsonflags.FormatByteArrayAsArray) && va.Kind() == reflect.Array {
return unmarshalArray(dec, va, uo)
} else if uo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && dec.PeekKind() == '[' {
return unmarshalArray(dec, va, uo)
}
var flags jsonwire.ValueFlags
val, err := xd.ReadValue(&flags)
@@ -409,7 +446,7 @@ func makeBytesArshaler(t reflect.Type, fncs *arshaler) *arshaler {
if va.Kind() == reflect.Array {
dst := va.Bytes()
clear(dst[copy(dst, b):]) // noop if len(b) <= len(dst)
clear(dst[copy(dst, b):]) // noop if len(b) >= len(dst)
if len(b) != len(dst) && !uo.Flags.Get(jsonflags.UnmarshalArrayFromAnyLength) {
err := fmt.Errorf("decoded length of %d mismatches array length of %d", len(b), len(dst))
return newUnmarshalErrorAfter(dec, t, err)
@@ -432,12 +469,13 @@ func makeIntArshaler(t reflect.Type) *arshaler {
bits := t.Bits()
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
xe := export.Encoder(enc)
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
return newInvalidFormatError(enc, t, mo)
stringify := xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.StringTag)
if mo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(enc, t)
}
// Optimize for marshaling without preceding whitespace or string escaping.
if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyNumbers) && !xe.Tokens.Last.NeedObjectName() {
if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace) && !stringify {
xe.Buf = strconv.AppendInt(xe.Tokens.MayAppendDelim(xe.Buf, '0'), va.Int(), 10)
xe.Tokens.Last.Increment()
if xe.NeedFlush() {
@@ -446,17 +484,17 @@ func makeIntArshaler(t reflect.Type) *arshaler {
return nil
}
k := stringOrNumberKind(xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers))
k := stringOrNumberKind(stringify)
return xe.AppendRaw(k, true, func(b []byte) ([]byte, error) {
return strconv.AppendInt(b, va.Int(), 10), nil
})
}
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
xd := export.Decoder(dec)
if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
return newInvalidFormatError(dec, t, uo)
stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.StringTag)
if uo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(dec, t)
}
stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers)
var flags jsonwire.ValueFlags
val, err := xd.ReadValue(&flags)
if err != nil {
@@ -474,10 +512,21 @@ func makeIntArshaler(t reflect.Type) *arshaler {
break
}
val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim())
if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && string(val) == "null" {
if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) {
va.SetInt(0)
if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) {
// For historical reasons, v1 parsed a quoted number
// according to the Go syntax and permitted a quoted null.
// See https://go.dev/issue/75619
n, err := strconv.ParseInt(string(val), 10, bits)
if err != nil {
if string(val) == "null" {
if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) {
va.SetInt(0)
}
return nil
}
return newUnmarshalErrorAfterWithValue(dec, t, errors.Unwrap(err))
}
va.SetInt(n)
return nil
}
fallthrough
@@ -519,12 +568,13 @@ func makeUintArshaler(t reflect.Type) *arshaler {
bits := t.Bits()
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
xe := export.Encoder(enc)
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
return newInvalidFormatError(enc, t, mo)
stringify := xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.StringTag)
if mo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(enc, t)
}
// Optimize for marshaling without preceding whitespace or string escaping.
if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyNumbers) && !xe.Tokens.Last.NeedObjectName() {
if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace) && !stringify {
xe.Buf = strconv.AppendUint(xe.Tokens.MayAppendDelim(xe.Buf, '0'), va.Uint(), 10)
xe.Tokens.Last.Increment()
if xe.NeedFlush() {
@@ -533,17 +583,17 @@ func makeUintArshaler(t reflect.Type) *arshaler {
return nil
}
k := stringOrNumberKind(xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers))
k := stringOrNumberKind(stringify)
return xe.AppendRaw(k, true, func(b []byte) ([]byte, error) {
return strconv.AppendUint(b, va.Uint(), 10), nil
})
}
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
xd := export.Decoder(dec)
if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
return newInvalidFormatError(dec, t, uo)
stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.StringTag)
if uo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(dec, t)
}
stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers)
var flags jsonwire.ValueFlags
val, err := xd.ReadValue(&flags)
if err != nil {
@@ -561,10 +611,21 @@ func makeUintArshaler(t reflect.Type) *arshaler {
break
}
val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim())
if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && string(val) == "null" {
if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) {
va.SetUint(0)
if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) {
// For historical reasons, v1 parsed a quoted number
// according to the Go syntax and permitted a quoted null.
// See https://go.dev/issue/75619
n, err := strconv.ParseUint(string(val), 10, bits)
if err != nil {
if string(val) == "null" {
if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) {
va.SetUint(0)
}
return nil
}
return newUnmarshalErrorAfterWithValue(dec, t, errors.Unwrap(err))
}
va.SetUint(n)
return nil
}
fallthrough
@@ -597,12 +658,13 @@ func makeFloatArshaler(t reflect.Type) *arshaler {
bits := t.Bits()
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
xe := export.Encoder(enc)
stringify := xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.StringTag)
var allowNonFinite bool
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
if mo.Flags.Has(jsonflags.FormatTag) {
if mo.Format == "nonfinite" {
allowNonFinite = true
} else {
return newInvalidFormatError(enc, t, mo)
return newInvalidFormatError(enc, t)
}
}
@@ -616,7 +678,7 @@ func makeFloatArshaler(t reflect.Type) *arshaler {
}
// Optimize for marshaling without preceding whitespace or string escaping.
if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyNumbers) && !xe.Tokens.Last.NeedObjectName() {
if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace) && !stringify {
xe.Buf = jsonwire.AppendFloat(xe.Tokens.MayAppendDelim(xe.Buf, '0'), fv, bits)
xe.Tokens.Last.Increment()
if xe.NeedFlush() {
@@ -625,22 +687,23 @@ func makeFloatArshaler(t reflect.Type) *arshaler {
return nil
}
k := stringOrNumberKind(xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers))
k := stringOrNumberKind(stringify)
return xe.AppendRaw(k, true, func(b []byte) ([]byte, error) {
return jsonwire.AppendFloat(b, va.Float(), bits), nil
})
}
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
xd := export.Decoder(dec)
stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.StringTag)
var allowNonFinite bool
if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
if uo.Flags.Has(jsonflags.FormatTag) {
if uo.Format == "nonfinite" {
allowNonFinite = true
} else {
return newInvalidFormatError(dec, t, uo)
return newInvalidFormatError(dec, t)
}
}
stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers)
var flags jsonwire.ValueFlags
val, err := xd.ReadValue(&flags)
if err != nil {
@@ -671,10 +734,21 @@ func makeFloatArshaler(t reflect.Type) *arshaler {
if !stringify {
break
}
if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && string(val) == "null" {
if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) {
va.SetFloat(0)
if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) {
// For historical reasons, v1 parsed a quoted number
// according to the Go syntax and permitted a quoted null.
// See https://go.dev/issue/75619
n, err := strconv.ParseFloat(string(val), bits)
if err != nil {
if string(val) == "null" {
if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) {
va.SetFloat(0)
}
return nil
}
return newUnmarshalErrorAfterWithValue(dec, t, errors.Unwrap(err))
}
va.SetFloat(n)
return nil
}
if n, err := jsonwire.ConsumeNumber(val); n != len(val) || err != nil {
@@ -685,10 +759,10 @@ func makeFloatArshaler(t reflect.Type) *arshaler {
if stringify && k == '0' {
break
}
fv, ok := jsonwire.ParseFloat(val, bits)
fv, err := strconv.ParseFloat(string(val), bits)
va.SetFloat(fv)
if !ok {
return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrRange)
if err != nil {
return newUnmarshalErrorAfterWithValue(dec, t, errors.Unwrap(err))
}
return nil
}
@@ -728,16 +802,19 @@ func makeMapArshaler(t reflect.Type) *arshaler {
}
emitNull := mo.Flags.Get(jsonflags.FormatNilMapAsNull)
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
switch mo.Format {
case "emitnull":
emitNull = true
mo.Format = ""
case "emitempty":
emitNull = false
mo.Format = ""
default:
return newInvalidFormatError(enc, t, mo)
if mo.Flags.Has(jsonflags.TagFlags) {
if mo.Flags.Get(jsonflags.StringTag) && !mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newMarshalErrorBefore(enc, t, errInvalidStringTag)
}
if mo.Flags.Has(jsonflags.FormatTag) {
switch mo.Format {
case "emitnull":
emitNull = true
case "emitempty":
emitNull = false
default:
return newInvalidFormatError(enc, t)
}
}
}
@@ -810,7 +887,7 @@ func makeMapArshaler(t reflect.Type) *arshaler {
k.SetIterKey(iter)
(*names)[i] = k.String()
}
names.Sort()
slices.Sort(*names)
for _, name := range *names {
if err := enc.WriteToken(jsontext.String(name)); err != nil {
return err
@@ -877,12 +954,16 @@ func makeMapArshaler(t reflect.Type) *arshaler {
}
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
xd := export.Decoder(dec)
if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
switch uo.Format {
case "emitnull", "emitempty":
uo.Format = "" // only relevant for marshaling
default:
return newInvalidFormatError(dec, t, uo)
if uo.Flags.Has(jsonflags.TagFlags) {
if uo.Flags.Get(jsonflags.StringTag) && !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newUnmarshalErrorBeforeWithSkipping(dec, t, errInvalidStringTag)
}
if uo.Flags.Has(jsonflags.FormatTag) {
switch uo.Format {
case "emitnull", "emitempty":
default:
return newInvalidFormatError(dec, t)
}
}
}
tok, err := dec.ReadToken()
@@ -992,7 +1073,7 @@ func makeMapArshaler(t reflect.Type) *arshaler {
}
return errUnmarshal
}
return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil)
return newUnmarshalErrorAfterWithSkipping(dec, t, nil)
}
return &fncs
}
@@ -1000,7 +1081,7 @@ func makeMapArshaler(t reflect.Type) *arshaler {
// mapKeyWithUniqueRepresentation reports whether all possible values of k
// marshal to a different JSON value, and whether all possible JSON values
// that can unmarshal into k unmarshal to different Go values.
// In other words, the representation must be a bijective.
// In other words, the representation must be a bijection.
func mapKeyWithUniqueRepresentation(k reflect.Kind, allowInvalidUTF8 bool) bool {
switch k {
case reflect.Bool,
@@ -1009,7 +1090,7 @@ func mapKeyWithUniqueRepresentation(k reflect.Kind, allowInvalidUTF8 bool) bool
return true
case reflect.String:
// For strings, we have to be careful since names with invalid UTF-8
// maybe unescape to the same Go string value.
// may unescape to the same Go string value.
return !allowInvalidUTF8
default:
// Floating-point kinds are not listed above since NaNs
@@ -1019,6 +1100,7 @@ func mapKeyWithUniqueRepresentation(k reflect.Kind, allowInvalidUTF8 bool) bool
}
var errNilField = errors.New("cannot set embedded pointer to unexported struct type")
var errInvalidStringTag = errors.New("invalid use of `string` tag option")
func makeStructArshaler(t reflect.Type) *arshaler {
// NOTE: The logic below disables namespaces for tracking duplicate names
@@ -1036,13 +1118,21 @@ func makeStructArshaler(t reflect.Type) *arshaler {
}
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
xe := export.Encoder(enc)
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
return newInvalidFormatError(enc, t, mo)
if mo.Flags.Has(jsonflags.TagFlags) {
if mo.Flags.Get(jsonflags.StringTag) && !mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newMarshalErrorBefore(enc, t, errInvalidStringTag)
}
if mo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(enc, t)
}
}
once.Do(init)
if errInit != nil && !mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newMarshalErrorBefore(enc, errInit.GoType, errInit.Err)
} else if fields.errUnsupportedFormat != nil && !mo.Flags.Get(jsonflags.FormatTagSupported) {
return newMarshalErrorBefore(enc, fields.errUnsupportedFormat.GoType, fields.errUnsupportedFormat.Err)
}
if err := enc.WriteToken(jsontext.BeginObject); err != nil {
return err
}
@@ -1055,7 +1145,7 @@ func makeStructArshaler(t reflect.Type) *arshaler {
if len(f.index) > 0 {
v = v.fieldByIndex(f.index, false)
if !v.IsValid() {
continue // implies a nil inlined field
continue // implies a nil embedded field
}
}
@@ -1115,7 +1205,7 @@ func makeStructArshaler(t reflect.Type) *arshaler {
if !f.nameNeedEscape {
b = append(b, f.quotedName...)
} else {
b, _ = jsonwire.AppendQuote(b, f.name, &mo.Flags)
b, _ = jsonwire.AppendQuote(b, []byte(f.name), &mo.Flags)
}
xe.Buf = b
xe.Names.ReplaceLastQuotedOffset(n0)
@@ -1129,14 +1219,10 @@ func makeStructArshaler(t reflect.Type) *arshaler {
// Write the object member value.
flagsOriginal := mo.Flags
if f.string {
if !mo.Flags.Get(jsonflags.StringifyWithLegacySemantics) {
mo.Flags.Set(jsonflags.StringifyNumbers | 1)
} else if canLegacyStringify(f.typ) {
mo.Flags.Set(jsonflags.StringifyNumbers | jsonflags.StringifyBoolsAndStrings | 1)
}
mo.Flags.Set(jsonflags.StringTag | 1)
}
if f.format != "" {
mo.FormatDepth = xe.Tokens.Depth()
mo.Flags.Set(jsonflags.FormatTag | 1)
mo.Format = f.format
}
err := marshal(enc, v, mo)
@@ -1159,17 +1245,17 @@ func makeStructArshaler(t reflect.Type) *arshaler {
// Remember the previous written object member.
// The set of seen fields only needs to be updated to detect
// duplicate names with those from the inlined fallback.
if !mo.Flags.Get(jsonflags.AllowDuplicateNames) && fields.inlinedFallback != nil {
// duplicate names with those from the embedded fallback.
if !mo.Flags.Get(jsonflags.AllowDuplicateNames) && fields.embeddedFallback != nil {
seenIdxs.insert(uint(f.id))
}
prevIdx = f.id
}
if fields.inlinedFallback != nil && !(mo.Flags.Get(jsonflags.DiscardUnknownMembers) && fields.inlinedFallback.unknown) {
if fields.embeddedFallback != nil {
var insertUnquotedName func([]byte) bool
if !mo.Flags.Get(jsonflags.AllowDuplicateNames) {
insertUnquotedName = func(name []byte) bool {
// Check that the name from inlined fallback does not match
// Check that the name from embedded fallback does not match
// one of the previously marshaled names from known fields.
if foldedFields := fields.lookupByFoldedName(name); len(foldedFields) > 0 {
if f := fields.byActualName[string(name)]; f != nil {
@@ -1183,11 +1269,11 @@ func makeStructArshaler(t reflect.Type) *arshaler {
}
// Check that the name does not match any other name
// previously marshaled from the inlined fallback.
// previously marshaled from the embedded fallback.
return xe.Namespaces.Last().InsertUnquoted(name)
}
}
if err := marshalInlinedFallbackAll(enc, va, mo, fields.inlinedFallback, insertUnquotedName); err != nil {
if err := marshalEmbeddedFallbackAll(enc, va, mo, fields.embeddedFallback, insertUnquotedName); err != nil {
return err
}
}
@@ -1198,8 +1284,13 @@ func makeStructArshaler(t reflect.Type) *arshaler {
}
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
xd := export.Decoder(dec)
if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
return newInvalidFormatError(dec, t, uo)
if uo.Flags.Has(jsonflags.TagFlags) {
if uo.Flags.Get(jsonflags.StringTag) && !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newUnmarshalErrorBeforeWithSkipping(dec, t, errInvalidStringTag)
}
if uo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(dec, t)
}
}
tok, err := dec.ReadToken()
if err != nil {
@@ -1216,7 +1307,10 @@ func makeStructArshaler(t reflect.Type) *arshaler {
once.Do(init)
if errInit != nil && !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newUnmarshalErrorAfter(dec, errInit.GoType, errInit.Err)
} else if fields.errUnsupportedFormat != nil && !uo.Flags.Get(jsonflags.FormatTagSupported) {
return newUnmarshalErrorAfter(dec, fields.errUnsupportedFormat.GoType, fields.errUnsupportedFormat.Err)
}
var seenIdxs uintSet
xd.Tokens.Last.DisableNamespace()
var errUnmarshal error
@@ -1230,14 +1324,20 @@ func makeStructArshaler(t reflect.Type) *arshaler {
name := jsonwire.UnquoteMayCopy(val, flags.IsVerbatim())
f := fields.byActualName[string(name)]
if f == nil {
var numMatch int
for _, f2 := range fields.lookupByFoldedName(name) {
if f2.matchFoldedName(name, &uo.Flags) {
f = f2
break
if f == nil {
f = f2 // use first seen name by breadth-first order
}
numMatch++
}
}
if numMatch > 1 && !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newUnmarshalErrorAfter(dec, t, errAmbiguousName)
}
if f == nil {
if uo.Flags.Get(jsonflags.RejectUnknownMembers) && (fields.inlinedFallback == nil || fields.inlinedFallback.unknown) {
if uo.Flags.Get(jsonflags.RejectUnknownMembers) && fields.embeddedFallback == nil {
err := newUnmarshalErrorAfter(dec, t, ErrUnknownName)
if !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return err
@@ -1249,14 +1349,14 @@ func makeStructArshaler(t reflect.Type) *arshaler {
return newDuplicateNameError(dec.StackPointer(), nil, dec.InputOffset()-len64(val))
}
if fields.inlinedFallback == nil {
if fields.embeddedFallback == nil {
// Skip unknown value since we have no place to store it.
if err := dec.SkipValue(); err != nil {
return err
}
} else {
// Marshal into value capable of storing arbitrary object members.
if err := unmarshalInlinedFallbackNext(dec, va, uo, fields.inlinedFallback, val, name); err != nil {
// Unmarshal into a value capable of storing arbitrary object members.
if err := unmarshalEmbeddedFallbackNext(dec, va, uo, fields.embeddedFallback, val, name); err != nil {
if isFatalError(err, uo.Flags) {
return err
}
@@ -1278,14 +1378,10 @@ func makeStructArshaler(t reflect.Type) *arshaler {
}
flagsOriginal := uo.Flags
if f.string {
if !uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) {
uo.Flags.Set(jsonflags.StringifyNumbers | 1)
} else if canLegacyStringify(f.typ) {
uo.Flags.Set(jsonflags.StringifyNumbers | jsonflags.StringifyBoolsAndStrings | 1)
}
uo.Flags.Set(jsonflags.StringTag | 1)
}
if f.format != "" {
uo.FormatDepth = xd.Tokens.Depth()
uo.Flags.Set(jsonflags.FormatTag | 1)
uo.Format = f.format
}
v := addressableValue{va.Field(f.index0), va.forcedAddr} // addressable if struct value is addressable
@@ -1317,7 +1413,7 @@ func makeStructArshaler(t reflect.Type) *arshaler {
}
return errUnmarshal
}
return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil)
return newUnmarshalErrorAfterWithSkipping(dec, t, nil)
}
return &fncs
}
@@ -1366,25 +1462,6 @@ func isLegacyEmpty(v addressableValue) bool {
return false
}
// canLegacyStringify reports whether t can be stringified according to v1,
// where t is a bool, string, or number (or unnamed pointer to such).
// In v1, the `string` option does not apply recursively to nested types within
// a composite Go type (e.g., an array, slice, struct, map, or interface).
func canLegacyStringify(t reflect.Type) bool {
// Based on encoding/json.typeFields#L1126-L1143@v1.23.0
if t.Name() == "" && t.Kind() == reflect.Ptr {
t = t.Elem()
}
switch t.Kind() {
case reflect.Bool, reflect.String,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
reflect.Float32, reflect.Float64:
return true
}
return false
}
func makeSliceArshaler(t reflect.Type) *arshaler {
var fncs arshaler
var (
@@ -1405,16 +1482,19 @@ func makeSliceArshaler(t reflect.Type) *arshaler {
}
emitNull := mo.Flags.Get(jsonflags.FormatNilSliceAsNull)
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
switch mo.Format {
case "emitnull":
emitNull = true
mo.Format = ""
case "emitempty":
emitNull = false
mo.Format = ""
default:
return newInvalidFormatError(enc, t, mo)
if mo.Flags.Has(jsonflags.TagFlags) {
if mo.Flags.Get(jsonflags.StringTag) && !mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newMarshalErrorBefore(enc, t, errInvalidStringTag)
}
if mo.Flags.Has(jsonflags.FormatTag) {
switch mo.Format {
case "emitnull":
emitNull = true
case "emitempty":
emitNull = false
default:
return newInvalidFormatError(enc, t)
}
}
}
@@ -1456,13 +1536,16 @@ func makeSliceArshaler(t reflect.Type) *arshaler {
}
emptySlice := reflect.MakeSlice(t, 0, 0)
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
xd := export.Decoder(dec)
if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
switch uo.Format {
case "emitnull", "emitempty":
uo.Format = "" // only relevant for marshaling
default:
return newInvalidFormatError(dec, t, uo)
if uo.Flags.Has(jsonflags.TagFlags) {
if uo.Flags.Get(jsonflags.StringTag) && !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newUnmarshalErrorBeforeWithSkipping(dec, t, errInvalidStringTag)
}
if uo.Flags.Has(jsonflags.FormatTag) {
switch uo.Format {
case "emitnull", "emitempty":
default:
return newInvalidFormatError(dec, t)
}
}
}
@@ -1518,7 +1601,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler {
}
return errUnmarshal
}
return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil)
return newUnmarshalErrorAfterWithSkipping(dec, t, nil)
}
return &fncs
}
@@ -1537,9 +1620,13 @@ func makeArrayArshaler(t reflect.Type) *arshaler {
}
n := t.Len()
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
xe := export.Encoder(enc)
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
return newInvalidFormatError(enc, t, mo)
if mo.Flags.Has(jsonflags.TagFlags) {
if mo.Flags.Get(jsonflags.StringTag) && !mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newMarshalErrorBefore(enc, t, errInvalidStringTag)
}
if mo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(enc, t)
}
}
once.Do(init)
if err := enc.WriteToken(jsontext.BeginArray); err != nil {
@@ -1561,9 +1648,13 @@ func makeArrayArshaler(t reflect.Type) *arshaler {
return nil
}
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
xd := export.Decoder(dec)
if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
return newInvalidFormatError(dec, t, uo)
if uo.Flags.Has(jsonflags.TagFlags) {
if uo.Flags.Get(jsonflags.StringTag) && !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newUnmarshalErrorBeforeWithSkipping(dec, t, errInvalidStringTag)
}
if uo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(dec, t)
}
}
tok, err := dec.ReadToken()
if err != nil {
@@ -1616,7 +1707,7 @@ func makeArrayArshaler(t reflect.Type) *arshaler {
}
return errUnmarshal
}
return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil)
return newUnmarshalErrorAfterWithSkipping(dec, t, nil)
}
return &fncs
}
@@ -1641,6 +1732,12 @@ func makePointerArshaler(t reflect.Type) *arshaler {
}
// NOTE: Struct.Format is forwarded to underlying marshal.
if mo.Flags.Get(jsonflags.StringTag) && mo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && t.Elem().Kind() == reflect.Pointer {
if !mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newMarshalErrorBefore(enc, t, errInvalidStringTag)
}
mo.Flags.Clear(jsonflags.StringTag) // the `string` tag option does not apply to nested pointers
}
if va.IsNil() {
return enc.WriteToken(jsontext.Null)
}
@@ -1661,6 +1758,12 @@ func makePointerArshaler(t reflect.Type) *arshaler {
va.SetZero()
return nil
}
if uo.Flags.Get(jsonflags.StringTag) && uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && t.Elem().Kind() == reflect.Pointer {
if !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newUnmarshalErrorBeforeWithSkipping(dec, t, errInvalidStringTag)
}
uo.Flags.Clear(jsonflags.StringTag) // the `string` tag option does not apply to nested pointers
}
once.Do(init)
unmarshal := valFncs.unmarshal
if uo.Unmarshalers != nil {
@@ -1673,8 +1776,7 @@ func makePointerArshaler(t reflect.Type) *arshaler {
if err := unmarshal(dec, v, uo); err != nil {
return err
}
if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) &&
uo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.StringifyBoolsAndStrings) {
if uo.Flags.Get(jsonflags.StringTag) && uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) {
// A JSON null quoted within a JSON string should take effect
// within the pointer value, rather than the indirect value.
//
@@ -1704,9 +1806,18 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler {
}
}
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
xe := export.Encoder(enc)
if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
return newInvalidFormatError(enc, t, mo)
if mo.Flags.Has(jsonflags.TagFlags) {
if mo.Flags.Get(jsonflags.StringTag) {
if !mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newMarshalErrorBefore(enc, t, errInvalidStringTag)
}
if mo.Flags.Get(jsonflags.StringifyWithLegacySemantics) {
mo.Flags.Clear(jsonflags.StringTag) // the `string` tag option does not apply to interface types
}
}
if mo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(enc, t)
}
}
if va.IsNil() {
return enc.WriteToken(jsontext.Null)
@@ -1737,16 +1848,25 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler {
}
// Optimize for the any type if there are no special options.
if optimizeCommon &&
t == anyType && !mo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.StringifyBoolsAndStrings) && mo.Format == "" &&
t == anyType && !mo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.TagFlags) &&
(mo.Marshalers == nil || !mo.Marshalers.(*Marshalers).fromAny) {
return marshalValueAny(enc, va.Elem().Interface(), mo)
}
return marshal(enc, v, mo)
}
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
xd := export.Decoder(dec)
if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
return newInvalidFormatError(dec, t, uo)
if uo.Flags.Has(jsonflags.TagFlags) {
if uo.Flags.Get(jsonflags.StringTag) {
if !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return newUnmarshalErrorBeforeWithSkipping(dec, t, errInvalidStringTag)
}
if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) {
uo.Flags.Clear(jsonflags.StringTag) // the `string` tag option does not apply to interface types
}
}
if uo.Flags.Has(jsonflags.FormatTag) {
return newInvalidFormatError(dec, t)
}
}
if uo.Flags.Get(jsonflags.MergeWithLegacySemantics) && !va.IsNil() {
// Legacy merge behavior is difficult to explain.
@@ -1782,7 +1902,7 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler {
// Duplicate name check must be enforced since unmarshalValueAny
// does not implement merge semantics.
if optimizeCommon &&
t == anyType && !uo.Flags.Get(jsonflags.AllowDuplicateNames) && uo.Format == "" &&
t == anyType && !uo.Flags.Get(jsonflags.AllowDuplicateNames|jsonflags.FormatTag) &&
(uo.Unmarshalers == nil || !uo.Unmarshalers.(*Unmarshalers).fromAny) {
v, err := unmarshalValueAny(dec, uo)
// We must check for nil interface values up front.
@@ -1795,7 +1915,7 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler {
k := dec.PeekKind()
if !isAnyType(t) {
return newUnmarshalErrorBeforeWithSkipping(dec, uo, t, internal.ErrNilInterface)
return newUnmarshalErrorBeforeWithSkipping(dec, t, internal.ErrNilInterface)
}
switch k {
case 'f', 't':
@@ -1838,7 +1958,7 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler {
return &fncs
}
// isAnyType reports wether t is equivalent to the any interface type.
// isAnyType reports whether t is equivalent to the any interface type.
func isAnyType(t reflect.Type) bool {
// This is forward compatible if the Go language permits type sets within
// ordinary interfaces where an interface with zero methods does not
@@ -1853,6 +1973,19 @@ func makeInvalidArshaler(t reflect.Type) *arshaler {
return newMarshalErrorBefore(enc, t, nil)
}
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
// Under legacy error semantics, unmarshal continues on even with errors.
// Thus, always consume the value first.
// As a special-case, null is permitted for unsupported types.
if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
switch val, err := dec.ReadValue(); {
case err != nil:
return err
case val.Kind() == 'n':
return nil
default:
return newUnmarshalErrorAfter(dec, t, nil)
}
}
return newUnmarshalErrorBefore(dec, t, nil)
}
return &fncs