| | |
| | |
| | |
| |
|
| | |
| |
|
| | package json |
| |
|
| | import ( |
| | "bytes" |
| | "cmp" |
| | "encoding" |
| | "encoding/base32" |
| | "encoding/base64" |
| | "encoding/hex" |
| | "errors" |
| | "fmt" |
| | "math" |
| | "reflect" |
| | "slices" |
| | "strconv" |
| | "strings" |
| | "sync" |
| |
|
| | "encoding/json/internal" |
| | "encoding/json/internal/jsonflags" |
| | "encoding/json/internal/jsonopts" |
| | "encoding/json/internal/jsonwire" |
| | "encoding/json/jsontext" |
| | ) |
| |
|
| | |
| | |
| | |
| | const optimizeCommon = true |
| |
|
| | var ( |
| | |
| | anyType = reflect.TypeFor[any]() |
| | boolType = reflect.TypeFor[bool]() |
| | stringType = reflect.TypeFor[string]() |
| | float64Type = reflect.TypeFor[float64]() |
| | mapStringAnyType = reflect.TypeFor[map[string]any]() |
| | sliceAnyType = reflect.TypeFor[[]any]() |
| |
|
| | bytesType = reflect.TypeFor[[]byte]() |
| | emptyStructType = reflect.TypeFor[struct{}]() |
| | ) |
| |
|
| | const startDetectingCyclesAfter = 1000 |
| |
|
| | type seenPointers = map[any]struct{} |
| |
|
| | type typedPointer struct { |
| | typ reflect.Type |
| | ptr any |
| | len int |
| | } |
| |
|
| | |
| | |
| | func visitPointer(m *seenPointers, v reflect.Value) error { |
| | p := typedPointer{v.Type(), v.UnsafePointer(), sliceLen(v)} |
| | if _, ok := (*m)[p]; ok { |
| | return internal.ErrCycle |
| | } |
| | if *m == nil { |
| | *m = make(seenPointers) |
| | } |
| | (*m)[p] = struct{}{} |
| | return nil |
| | } |
| | func leavePointer(m *seenPointers, v reflect.Value) { |
| | p := typedPointer{v.Type(), v.UnsafePointer(), sliceLen(v)} |
| | delete(*m, p) |
| | } |
| |
|
| | func sliceLen(v reflect.Value) int { |
| | if v.Kind() == reflect.Slice { |
| | return v.Len() |
| | } |
| | return 0 |
| | } |
| |
|
| | func len64[Bytes ~[]byte | ~string](in Bytes) int64 { |
| | return int64(len(in)) |
| | } |
| |
|
| | func makeDefaultArshaler(t reflect.Type) *arshaler { |
| | switch t.Kind() { |
| | case reflect.Bool: |
| | return makeBoolArshaler(t) |
| | case reflect.String: |
| | return makeStringArshaler(t) |
| | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
| | return makeIntArshaler(t) |
| | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: |
| | return makeUintArshaler(t) |
| | case reflect.Float32, reflect.Float64: |
| | return makeFloatArshaler(t) |
| | case reflect.Map: |
| | return makeMapArshaler(t) |
| | case reflect.Struct: |
| | return makeStructArshaler(t) |
| | case reflect.Slice: |
| | fncs := makeSliceArshaler(t) |
| | if t.Elem().Kind() == reflect.Uint8 { |
| | return makeBytesArshaler(t, fncs) |
| | } |
| | return fncs |
| | case reflect.Array: |
| | fncs := makeArrayArshaler(t) |
| | if t.Elem().Kind() == reflect.Uint8 { |
| | return makeBytesArshaler(t, fncs) |
| | } |
| | return fncs |
| | case reflect.Pointer: |
| | return makePointerArshaler(t) |
| | case reflect.Interface: |
| | return makeInterfaceArshaler(t) |
| | default: |
| | return makeInvalidArshaler(t) |
| | } |
| | } |
| |
|
| | 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) |
| | } |
| |
|
| | |
| | if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyBoolsAndStrings) && !xe.Tokens.Last.NeedObjectName() { |
| | xe.Buf = strconv.AppendBool(xe.Tokens.MayAppendDelim(xe.Buf, 't'), va.Bool()) |
| | xe.Tokens.Last.Increment() |
| | if xe.NeedFlush() { |
| | return xe.Flush() |
| | } |
| | return nil |
| | } |
| |
|
| | if mo.Flags.Get(jsonflags.StringifyBoolsAndStrings) { |
| | if va.Bool() { |
| | return enc.WriteToken(jsontext.String("true")) |
| | } else { |
| | return enc.WriteToken(jsontext.String("false")) |
| | } |
| | } |
| | 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) |
| | } |
| | tok, err := dec.ReadToken() |
| | if err != nil { |
| | return err |
| | } |
| | k := tok.Kind() |
| | switch k { |
| | case 'n': |
| | if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { |
| | va.SetBool(false) |
| | } |
| | return nil |
| | case 't', 'f': |
| | if !uo.Flags.Get(jsonflags.StringifyBoolsAndStrings) { |
| | va.SetBool(tok.Bool()) |
| | return nil |
| | } |
| | case '"': |
| | if uo.Flags.Get(jsonflags.StringifyBoolsAndStrings) { |
| | switch tok.String() { |
| | case "true": |
| | va.SetBool(true) |
| | case "false": |
| | va.SetBool(false) |
| | default: |
| | if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && tok.String() == "null" { |
| | if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { |
| | va.SetBool(false) |
| | } |
| | return nil |
| | } |
| | return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrSyntax) |
| | } |
| | return nil |
| | } |
| | } |
| | return newUnmarshalErrorAfterWithSkipping(dec, t, nil) |
| | } |
| | return &fncs |
| | } |
| |
|
| | 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) |
| | } |
| |
|
| | |
| | s := va.String() |
| | if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyBoolsAndStrings) && !xe.Tokens.Last.NeedObjectName() { |
| | b := xe.Buf |
| | b = xe.Tokens.MayAppendDelim(b, '"') |
| | b, err := jsonwire.AppendQuote(b, s, &mo.Flags) |
| | if err == nil { |
| | xe.Buf = b |
| | xe.Tokens.Last.Increment() |
| | if xe.NeedFlush() { |
| | return xe.Flush() |
| | } |
| | return nil |
| | } |
| | |
| | |
| | } |
| |
|
| | if mo.Flags.Get(jsonflags.StringifyBoolsAndStrings) { |
| | b, err := jsonwire.AppendQuote(nil, s, &mo.Flags) |
| | if err != nil { |
| | return newMarshalErrorBefore(enc, t, &jsontext.SyntacticError{Err: err}) |
| | } |
| | q, err := jsontext.AppendQuote(nil, b) |
| | if err != nil { |
| | panic("BUG: second AppendQuote should never fail: " + err.Error()) |
| | } |
| | return enc.WriteValue(q) |
| | } |
| | return enc.WriteToken(jsontext.String(s)) |
| | } |
| | 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) |
| | } |
| | var flags jsonwire.ValueFlags |
| | val, err := xd.ReadValue(&flags) |
| | if err != nil { |
| | return err |
| | } |
| | k := val.Kind() |
| | switch k { |
| | case 'n': |
| | if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { |
| | va.SetString("") |
| | } |
| | return nil |
| | case '"': |
| | val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) |
| | if uo.Flags.Get(jsonflags.StringifyBoolsAndStrings) { |
| | val, err = jsontext.AppendUnquote(nil, val) |
| | if err != nil { |
| | return newUnmarshalErrorAfter(dec, t, err) |
| | } |
| | if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && string(val) == "null" { |
| | if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { |
| | va.SetString("") |
| | } |
| | return nil |
| | } |
| | } |
| | if xd.StringCache == nil { |
| | xd.StringCache = new(stringCache) |
| | } |
| | str := makeString(xd.StringCache, val) |
| | va.SetString(str) |
| | return nil |
| | } |
| | return newUnmarshalErrorAfter(dec, t, nil) |
| | } |
| | return &fncs |
| | } |
| |
|
| | var ( |
| | appendEncodeBase16 = hex.AppendEncode |
| | appendEncodeBase32 = base32.StdEncoding.AppendEncode |
| | appendEncodeBase32Hex = base32.HexEncoding.AppendEncode |
| | appendEncodeBase64 = base64.StdEncoding.AppendEncode |
| | appendEncodeBase64URL = base64.URLEncoding.AppendEncode |
| | encodedLenBase16 = hex.EncodedLen |
| | encodedLenBase32 = base32.StdEncoding.EncodedLen |
| | encodedLenBase32Hex = base32.HexEncoding.EncodedLen |
| | encodedLenBase64 = base64.StdEncoding.EncodedLen |
| | encodedLenBase64URL = base64.URLEncoding.EncodedLen |
| | appendDecodeBase16 = hex.AppendDecode |
| | appendDecodeBase32 = base32.StdEncoding.AppendDecode |
| | appendDecodeBase32Hex = base32.HexEncoding.AppendDecode |
| | appendDecodeBase64 = base64.StdEncoding.AppendDecode |
| | appendDecodeBase64URL = base64.URLEncoding.AppendDecode |
| | ) |
| |
|
| | func makeBytesArshaler(t reflect.Type, fncs *arshaler) *arshaler { |
| | |
| | |
| | |
| | |
| | |
| | |
| | marshalArray := fncs.marshal |
| | isNamedByte := t.Elem().PkgPath() != "" |
| | hasMarshaler := implementsAny(t.Elem(), allMarshalerTypes...) |
| | fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { |
| | if !mo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && isNamedByte { |
| | return marshalArray(enc, va, mo) |
| | } |
| | 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 = "" |
| | return marshalArray(enc, va, mo) |
| | default: |
| | return newInvalidFormatError(enc, t) |
| | } |
| | } 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() { |
| | |
| | return enc.WriteToken(jsontext.Null) |
| | } |
| | return xe.AppendRaw('"', true, func(b []byte) ([]byte, error) { |
| | return appendEncode(b, va.Bytes()), nil |
| | }) |
| | } |
| | unmarshalArray := fncs.unmarshal |
| | fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { |
| | if !uo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && isNamedByte { |
| | return unmarshalArray(dec, va, uo) |
| | } |
| | 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 = "" |
| | return unmarshalArray(dec, va, uo) |
| | default: |
| | return newInvalidFormatError(dec, t) |
| | } |
| | } 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) |
| | if err != nil { |
| | return err |
| | } |
| | k := val.Kind() |
| | switch k { |
| | case 'n': |
| | if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) || va.Kind() != reflect.Array { |
| | va.SetZero() |
| | } |
| | return nil |
| | case '"': |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) |
| | b, err := appendDecode(va.Bytes()[:0], val) |
| | if err != nil { |
| | return newUnmarshalErrorAfter(dec, t, err) |
| | } |
| | if len(val) != encodedLen(len(b)) && !uo.Flags.Get(jsonflags.ParseBytesWithLooseRFC4648) { |
| | |
| | |
| | |
| | |
| | i := bytes.IndexAny(val, "\r\n") |
| | err := fmt.Errorf("illegal character %s at offset %d", jsonwire.QuoteRune(val[i:]), i) |
| | return newUnmarshalErrorAfter(dec, t, err) |
| | } |
| |
|
| | if va.Kind() == reflect.Array { |
| | dst := va.Bytes() |
| | clear(dst[copy(dst, b):]) |
| | 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) |
| | } |
| | } else { |
| | if b == nil { |
| | b = []byte{} |
| | } |
| | va.SetBytes(b) |
| | } |
| | return nil |
| | } |
| | return newUnmarshalErrorAfter(dec, t, nil) |
| | } |
| | return fncs |
| | } |
| |
|
| | func makeIntArshaler(t reflect.Type) *arshaler { |
| | var fncs 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) |
| | } |
| |
|
| | |
| | if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyNumbers) && !xe.Tokens.Last.NeedObjectName() { |
| | xe.Buf = strconv.AppendInt(xe.Tokens.MayAppendDelim(xe.Buf, '0'), va.Int(), 10) |
| | xe.Tokens.Last.Increment() |
| | if xe.NeedFlush() { |
| | return xe.Flush() |
| | } |
| | return nil |
| | } |
| |
|
| | k := stringOrNumberKind(xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers)) |
| | 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) |
| | } |
| | stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) |
| | var flags jsonwire.ValueFlags |
| | val, err := xd.ReadValue(&flags) |
| | if err != nil { |
| | return err |
| | } |
| | k := val.Kind() |
| | switch k { |
| | case 'n': |
| | if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { |
| | va.SetInt(0) |
| | } |
| | return nil |
| | case '"': |
| | if !stringify { |
| | break |
| | } |
| | val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) |
| | if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) { |
| | |
| | |
| | |
| | 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 |
| | case '0': |
| | if stringify && k == '0' { |
| | break |
| | } |
| | var negOffset int |
| | neg := len(val) > 0 && val[0] == '-' |
| | if neg { |
| | negOffset = 1 |
| | } |
| | n, ok := jsonwire.ParseUint(val[negOffset:]) |
| | maxInt := uint64(1) << (bits - 1) |
| | overflow := (neg && n > maxInt) || (!neg && n > maxInt-1) |
| | if !ok { |
| | if n != math.MaxUint64 { |
| | return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrSyntax) |
| | } |
| | overflow = true |
| | } |
| | if overflow { |
| | return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrRange) |
| | } |
| | if neg { |
| | va.SetInt(int64(-n)) |
| | } else { |
| | va.SetInt(int64(+n)) |
| | } |
| | return nil |
| | } |
| | return newUnmarshalErrorAfter(dec, t, nil) |
| | } |
| | return &fncs |
| | } |
| |
|
| | func makeUintArshaler(t reflect.Type) *arshaler { |
| | var fncs 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) |
| | } |
| |
|
| | |
| | if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyNumbers) && !xe.Tokens.Last.NeedObjectName() { |
| | xe.Buf = strconv.AppendUint(xe.Tokens.MayAppendDelim(xe.Buf, '0'), va.Uint(), 10) |
| | xe.Tokens.Last.Increment() |
| | if xe.NeedFlush() { |
| | return xe.Flush() |
| | } |
| | return nil |
| | } |
| |
|
| | k := stringOrNumberKind(xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers)) |
| | 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) |
| | } |
| | stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) |
| | var flags jsonwire.ValueFlags |
| | val, err := xd.ReadValue(&flags) |
| | if err != nil { |
| | return err |
| | } |
| | k := val.Kind() |
| | switch k { |
| | case 'n': |
| | if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { |
| | va.SetUint(0) |
| | } |
| | return nil |
| | case '"': |
| | if !stringify { |
| | break |
| | } |
| | val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) |
| | if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) { |
| | |
| | |
| | |
| | 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 |
| | case '0': |
| | if stringify && k == '0' { |
| | break |
| | } |
| | n, ok := jsonwire.ParseUint(val) |
| | maxUint := uint64(1) << bits |
| | overflow := n > maxUint-1 |
| | if !ok { |
| | if n != math.MaxUint64 { |
| | return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrSyntax) |
| | } |
| | overflow = true |
| | } |
| | if overflow { |
| | return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrRange) |
| | } |
| | va.SetUint(n) |
| | return nil |
| | } |
| | return newUnmarshalErrorAfter(dec, t, nil) |
| | } |
| | return &fncs |
| | } |
| |
|
| | func makeFloatArshaler(t reflect.Type) *arshaler { |
| | var fncs arshaler |
| | bits := t.Bits() |
| | fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { |
| | xe := export.Encoder(enc) |
| | var allowNonFinite bool |
| | if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { |
| | if mo.Format == "nonfinite" { |
| | allowNonFinite = true |
| | } else { |
| | return newInvalidFormatError(enc, t) |
| | } |
| | } |
| |
|
| | fv := va.Float() |
| | if math.IsNaN(fv) || math.IsInf(fv, 0) { |
| | if !allowNonFinite { |
| | err := fmt.Errorf("unsupported value: %v", fv) |
| | return newMarshalErrorBefore(enc, t, err) |
| | } |
| | return enc.WriteToken(jsontext.Float(fv)) |
| | } |
| |
|
| | |
| | if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyNumbers) && !xe.Tokens.Last.NeedObjectName() { |
| | xe.Buf = jsonwire.AppendFloat(xe.Tokens.MayAppendDelim(xe.Buf, '0'), fv, bits) |
| | xe.Tokens.Last.Increment() |
| | if xe.NeedFlush() { |
| | return xe.Flush() |
| | } |
| | return nil |
| | } |
| |
|
| | k := stringOrNumberKind(xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers)) |
| | 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) |
| | var allowNonFinite bool |
| | if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { |
| | if uo.Format == "nonfinite" { |
| | allowNonFinite = true |
| | } else { |
| | 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 { |
| | return err |
| | } |
| | k := val.Kind() |
| | switch k { |
| | case 'n': |
| | if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { |
| | va.SetFloat(0) |
| | } |
| | return nil |
| | case '"': |
| | val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) |
| | if allowNonFinite { |
| | switch string(val) { |
| | case "NaN": |
| | va.SetFloat(math.NaN()) |
| | return nil |
| | case "Infinity": |
| | va.SetFloat(math.Inf(+1)) |
| | return nil |
| | case "-Infinity": |
| | va.SetFloat(math.Inf(-1)) |
| | return nil |
| | } |
| | } |
| | if !stringify { |
| | break |
| | } |
| | if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) { |
| | |
| | |
| | |
| | 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 { |
| | return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrSyntax) |
| | } |
| | fallthrough |
| | case '0': |
| | if stringify && k == '0' { |
| | break |
| | } |
| | fv, ok := jsonwire.ParseFloat(val, bits) |
| | va.SetFloat(fv) |
| | if !ok { |
| | return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrRange) |
| | } |
| | return nil |
| | } |
| | return newUnmarshalErrorAfter(dec, t, nil) |
| | } |
| | return &fncs |
| | } |
| |
|
| | func makeMapArshaler(t reflect.Type) *arshaler { |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | var fncs arshaler |
| | var ( |
| | once sync.Once |
| | keyFncs *arshaler |
| | valFncs *arshaler |
| | ) |
| | init := func() { |
| | keyFncs = lookupArshaler(t.Key()) |
| | valFncs = lookupArshaler(t.Elem()) |
| | } |
| | nillableLegacyKey := t.Key().Kind() == reflect.Pointer && |
| | implementsAny(t.Key(), textMarshalerType, textAppenderType) |
| | fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { |
| | |
| | xe := export.Encoder(enc) |
| | if xe.Tokens.Depth() > startDetectingCyclesAfter { |
| | if err := visitPointer(&xe.SeenPointers, va.Value); err != nil { |
| | return newMarshalErrorBefore(enc, t, err) |
| | } |
| | defer leavePointer(&xe.SeenPointers, va.Value) |
| | } |
| |
|
| | 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) |
| | } |
| | } |
| |
|
| | |
| | n := va.Len() |
| | if n == 0 { |
| | if emitNull && va.IsNil() { |
| | return enc.WriteToken(jsontext.Null) |
| | } |
| | |
| | if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() { |
| | xe.Buf = append(xe.Tokens.MayAppendDelim(xe.Buf, '{'), "{}"...) |
| | xe.Tokens.Last.Increment() |
| | if xe.NeedFlush() { |
| | return xe.Flush() |
| | } |
| | return nil |
| | } |
| | } |
| |
|
| | once.Do(init) |
| | if err := enc.WriteToken(jsontext.BeginObject); err != nil { |
| | return err |
| | } |
| | if n > 0 { |
| | nonDefaultKey := keyFncs.nonDefault |
| | marshalKey := keyFncs.marshal |
| | marshalVal := valFncs.marshal |
| | if mo.Marshalers != nil { |
| | var ok bool |
| | marshalKey, ok = mo.Marshalers.(*Marshalers).lookup(marshalKey, t.Key()) |
| | marshalVal, _ = mo.Marshalers.(*Marshalers).lookup(marshalVal, t.Elem()) |
| | nonDefaultKey = nonDefaultKey || ok |
| | } |
| | k := newAddressableValue(t.Key()) |
| | v := newAddressableValue(t.Elem()) |
| |
|
| | |
| | |
| | |
| | if !nonDefaultKey && mapKeyWithUniqueRepresentation(k.Kind(), mo.Flags.Get(jsonflags.AllowInvalidUTF8)) { |
| | xe.Tokens.Last.DisableNamespace() |
| | } |
| |
|
| | switch { |
| | case !mo.Flags.Get(jsonflags.Deterministic) || n <= 1: |
| | for iter := va.Value.MapRange(); iter.Next(); { |
| | k.SetIterKey(iter) |
| | err := marshalKey(enc, k, mo) |
| | if err != nil { |
| | if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && |
| | errors.Is(err, jsontext.ErrNonStringName) && nillableLegacyKey && k.IsNil() { |
| | err = enc.WriteToken(jsontext.String("")) |
| | } |
| | if err != nil { |
| | if serr, ok := err.(*jsontext.SyntacticError); ok && serr.Err == jsontext.ErrNonStringName { |
| | err = newMarshalErrorBefore(enc, k.Type(), err) |
| | } |
| | return err |
| | } |
| | } |
| | v.SetIterValue(iter) |
| | if err := marshalVal(enc, v, mo); err != nil { |
| | return err |
| | } |
| | } |
| | case !nonDefaultKey && t.Key().Kind() == reflect.String: |
| | names := getStrings(n) |
| | for i, iter := 0, va.Value.MapRange(); i < n && iter.Next(); i++ { |
| | k.SetIterKey(iter) |
| | (*names)[i] = k.String() |
| | } |
| | slices.Sort(*names) |
| | for _, name := range *names { |
| | if err := enc.WriteToken(jsontext.String(name)); err != nil { |
| | return err |
| | } |
| | |
| | k.SetString(name) |
| | v.Set(va.MapIndex(k.Value)) |
| | if err := marshalVal(enc, v, mo); err != nil { |
| | return err |
| | } |
| | } |
| | putStrings(names) |
| | default: |
| | type member struct { |
| | name string |
| | key addressableValue |
| | val addressableValue |
| | } |
| | members := make([]member, n) |
| | keys := reflect.MakeSlice(reflect.SliceOf(t.Key()), n, n) |
| | vals := reflect.MakeSlice(reflect.SliceOf(t.Elem()), n, n) |
| | for i, iter := 0, va.Value.MapRange(); i < n && iter.Next(); i++ { |
| | |
| | k := addressableValue{keys.Index(i), true} |
| | k.SetIterKey(iter) |
| | v := addressableValue{vals.Index(i), true} |
| | v.SetIterValue(iter) |
| | err := marshalKey(enc, k, mo) |
| | if err != nil { |
| | if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && |
| | errors.Is(err, jsontext.ErrNonStringName) && nillableLegacyKey && k.IsNil() { |
| | err = enc.WriteToken(jsontext.String("")) |
| | } |
| | if err != nil { |
| | if serr, ok := err.(*jsontext.SyntacticError); ok && serr.Err == jsontext.ErrNonStringName { |
| | err = newMarshalErrorBefore(enc, k.Type(), err) |
| | } |
| | return err |
| | } |
| | } |
| | name := xe.UnwriteOnlyObjectMemberName() |
| | members[i] = member{name, k, v} |
| | } |
| | |
| | |
| | |
| | slices.SortFunc(members, func(x, y member) int { |
| | return strings.Compare(x.name, y.name) |
| | }) |
| | for _, member := range members { |
| | if err := enc.WriteToken(jsontext.String(member.name)); err != nil { |
| | return err |
| | } |
| | if err := marshalVal(enc, member.val, mo); err != nil { |
| | return err |
| | } |
| | } |
| | } |
| | } |
| | if err := enc.WriteToken(jsontext.EndObject); err != nil { |
| | return err |
| | } |
| | 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() { |
| | switch uo.Format { |
| | case "emitnull", "emitempty": |
| | uo.Format = "" |
| | default: |
| | return newInvalidFormatError(dec, t) |
| | } |
| | } |
| | tok, err := dec.ReadToken() |
| | if err != nil { |
| | return err |
| | } |
| | k := tok.Kind() |
| | switch k { |
| | case 'n': |
| | va.SetZero() |
| | return nil |
| | case '{': |
| | once.Do(init) |
| | if va.IsNil() { |
| | va.Set(reflect.MakeMap(t)) |
| | } |
| |
|
| | nonDefaultKey := keyFncs.nonDefault |
| | unmarshalKey := keyFncs.unmarshal |
| | unmarshalVal := valFncs.unmarshal |
| | if uo.Unmarshalers != nil { |
| | var ok bool |
| | unmarshalKey, ok = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshalKey, t.Key()) |
| | unmarshalVal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshalVal, t.Elem()) |
| | nonDefaultKey = nonDefaultKey || ok |
| | } |
| | k := newAddressableValue(t.Key()) |
| | v := newAddressableValue(t.Elem()) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | if !nonDefaultKey && mapKeyWithUniqueRepresentation(k.Kind(), uo.Flags.Get(jsonflags.AllowInvalidUTF8)) { |
| | xd.Tokens.Last.DisableNamespace() |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | var seen reflect.Value |
| | if !uo.Flags.Get(jsonflags.AllowDuplicateNames) && va.Len() > 0 { |
| | seen = reflect.MakeMap(reflect.MapOf(k.Type(), emptyStructType)) |
| | } |
| |
|
| | var errUnmarshal error |
| | for dec.PeekKind() != '}' { |
| | |
| | k.SetZero() |
| | err := unmarshalKey(dec, k, uo) |
| | if err != nil { |
| | if isFatalError(err, uo.Flags) { |
| | return err |
| | } |
| | if err := dec.SkipValue(); err != nil { |
| | return err |
| | } |
| | errUnmarshal = cmp.Or(errUnmarshal, err) |
| | continue |
| | } |
| | if k.Kind() == reflect.Interface && !k.IsNil() && !k.Elem().Type().Comparable() { |
| | err := newUnmarshalErrorAfter(dec, t, fmt.Errorf("invalid incomparable key type %v", k.Elem().Type())) |
| | if !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { |
| | return err |
| | } |
| | if err2 := dec.SkipValue(); err2 != nil { |
| | return err2 |
| | } |
| | errUnmarshal = cmp.Or(errUnmarshal, err) |
| | continue |
| | } |
| |
|
| | |
| | if v2 := va.MapIndex(k.Value); v2.IsValid() { |
| | if !uo.Flags.Get(jsonflags.AllowDuplicateNames) && (!seen.IsValid() || seen.MapIndex(k.Value).IsValid()) { |
| | |
| | name := xd.PreviousTokenOrValue() |
| | return newDuplicateNameError(dec.StackPointer(), nil, dec.InputOffset()-len64(name)) |
| | } |
| | if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { |
| | v.Set(v2) |
| | } else { |
| | v.SetZero() |
| | } |
| | } else { |
| | v.SetZero() |
| | } |
| |
|
| | |
| | err = unmarshalVal(dec, v, uo) |
| | va.SetMapIndex(k.Value, v.Value) |
| | if seen.IsValid() { |
| | seen.SetMapIndex(k.Value, reflect.Zero(emptyStructType)) |
| | } |
| | if err != nil { |
| | if isFatalError(err, uo.Flags) { |
| | return err |
| | } |
| | errUnmarshal = cmp.Or(errUnmarshal, err) |
| | } |
| | } |
| | if _, err := dec.ReadToken(); err != nil { |
| | return err |
| | } |
| | return errUnmarshal |
| | } |
| | return newUnmarshalErrorAfterWithSkipping(dec, t, nil) |
| | } |
| | return &fncs |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func mapKeyWithUniqueRepresentation(k reflect.Kind, allowInvalidUTF8 bool) bool { |
| | switch k { |
| | case reflect.Bool, |
| | reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, |
| | reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: |
| | return true |
| | case reflect.String: |
| | |
| | |
| | return !allowInvalidUTF8 |
| | default: |
| | |
| | |
| | return false |
| | } |
| | } |
| |
|
| | var errNilField = errors.New("cannot set embedded pointer to unexported struct type") |
| |
|
| | func makeStructArshaler(t reflect.Type) *arshaler { |
| | |
| | |
| | |
| |
|
| | var fncs arshaler |
| | var ( |
| | once sync.Once |
| | fields structFields |
| | errInit *SemanticError |
| | ) |
| | init := func() { |
| | fields, errInit = makeStructFields(t) |
| | } |
| | 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) |
| | } |
| | once.Do(init) |
| | if errInit != nil && !mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { |
| | return newMarshalErrorBefore(enc, errInit.GoType, errInit.Err) |
| | } |
| | if err := enc.WriteToken(jsontext.BeginObject); err != nil { |
| | return err |
| | } |
| | var seenIdxs uintSet |
| | prevIdx := -1 |
| | xe.Tokens.Last.DisableNamespace() |
| | for i := range fields.flattened { |
| | f := &fields.flattened[i] |
| | v := addressableValue{va.Field(f.index0), va.forcedAddr} |
| | if len(f.index) > 0 { |
| | v = v.fieldByIndex(f.index, false) |
| | if !v.IsValid() { |
| | continue |
| | } |
| | } |
| |
|
| | |
| | |
| | if (f.omitzero || mo.Flags.Get(jsonflags.OmitZeroStructFields)) && |
| | ((f.isZero == nil && v.IsZero()) || (f.isZero != nil && f.isZero(v))) { |
| | continue |
| | } |
| |
|
| | |
| | if f.omitempty && mo.Flags.Get(jsonflags.OmitEmptyWithLegacySemantics) && isLegacyEmpty(v) { |
| | continue |
| | } |
| |
|
| | marshal := f.fncs.marshal |
| | nonDefault := f.fncs.nonDefault |
| | if mo.Marshalers != nil { |
| | var ok bool |
| | marshal, ok = mo.Marshalers.(*Marshalers).lookup(marshal, f.typ) |
| | nonDefault = nonDefault || ok |
| | } |
| |
|
| | |
| | |
| | |
| | if f.omitempty && !mo.Flags.Get(jsonflags.OmitEmptyWithLegacySemantics) && |
| | !nonDefault && f.isEmpty != nil && f.isEmpty(v) { |
| | continue |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if optimizeCommon { |
| | |
| | b := xe.Buf |
| | if xe.Tokens.Last.Length() > 0 { |
| | b = append(b, ',') |
| | if mo.Flags.Get(jsonflags.SpaceAfterComma) { |
| | b = append(b, ' ') |
| | } |
| | } |
| | if mo.Flags.Get(jsonflags.Multiline) { |
| | b = xe.AppendIndent(b, xe.Tokens.NeedIndent('"')) |
| | } |
| |
|
| | |
| | n0 := len(b) |
| | if !f.nameNeedEscape { |
| | b = append(b, f.quotedName...) |
| | } else { |
| | b, _ = jsonwire.AppendQuote(b, f.name, &mo.Flags) |
| | } |
| | xe.Buf = b |
| | xe.Names.ReplaceLastQuotedOffset(n0) |
| | xe.Tokens.Last.Increment() |
| | } else { |
| | if err := enc.WriteToken(jsontext.String(f.name)); err != nil { |
| | return err |
| | } |
| | } |
| |
|
| | |
| | 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) |
| | } |
| | } |
| | if f.format != "" { |
| | mo.FormatDepth = xe.Tokens.Depth() |
| | mo.Format = f.format |
| | } |
| | err := marshal(enc, v, mo) |
| | mo.Flags = flagsOriginal |
| | mo.Format = "" |
| | if err != nil { |
| | return err |
| | } |
| |
|
| | |
| | if f.omitempty && !mo.Flags.Get(jsonflags.OmitEmptyWithLegacySemantics) { |
| | var prevName *string |
| | if prevIdx >= 0 { |
| | prevName = &fields.flattened[prevIdx].name |
| | } |
| | if xe.UnwriteEmptyObjectMember(prevName) { |
| | continue |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | if !mo.Flags.Get(jsonflags.AllowDuplicateNames) && fields.inlinedFallback != nil { |
| | seenIdxs.insert(uint(f.id)) |
| | } |
| | prevIdx = f.id |
| | } |
| | if fields.inlinedFallback != nil && !(mo.Flags.Get(jsonflags.DiscardUnknownMembers) && fields.inlinedFallback.unknown) { |
| | var insertUnquotedName func([]byte) bool |
| | if !mo.Flags.Get(jsonflags.AllowDuplicateNames) { |
| | insertUnquotedName = func(name []byte) bool { |
| | |
| | |
| | if foldedFields := fields.lookupByFoldedName(name); len(foldedFields) > 0 { |
| | if f := fields.byActualName[string(name)]; f != nil { |
| | return seenIdxs.insert(uint(f.id)) |
| | } |
| | for _, f := range foldedFields { |
| | if f.matchFoldedName(name, &mo.Flags) { |
| | return seenIdxs.insert(uint(f.id)) |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | return xe.Namespaces.Last().InsertUnquoted(name) |
| | } |
| | } |
| | if err := marshalInlinedFallbackAll(enc, va, mo, fields.inlinedFallback, insertUnquotedName); err != nil { |
| | return err |
| | } |
| | } |
| | if err := enc.WriteToken(jsontext.EndObject); err != nil { |
| | return err |
| | } |
| | 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) |
| | } |
| | tok, err := dec.ReadToken() |
| | if err != nil { |
| | return err |
| | } |
| | k := tok.Kind() |
| | switch k { |
| | case 'n': |
| | if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { |
| | va.SetZero() |
| | } |
| | return nil |
| | case '{': |
| | once.Do(init) |
| | if errInit != nil && !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { |
| | return newUnmarshalErrorAfter(dec, errInit.GoType, errInit.Err) |
| | } |
| | var seenIdxs uintSet |
| | xd.Tokens.Last.DisableNamespace() |
| | var errUnmarshal error |
| | for dec.PeekKind() != '}' { |
| | |
| | var flags jsonwire.ValueFlags |
| | val, err := xd.ReadValue(&flags) |
| | if err != nil { |
| | return err |
| | } |
| | name := jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) |
| | f := fields.byActualName[string(name)] |
| | if f == nil { |
| | for _, f2 := range fields.lookupByFoldedName(name) { |
| | if f2.matchFoldedName(name, &uo.Flags) { |
| | f = f2 |
| | break |
| | } |
| | } |
| | if f == nil { |
| | if uo.Flags.Get(jsonflags.RejectUnknownMembers) && (fields.inlinedFallback == nil || fields.inlinedFallback.unknown) { |
| | err := newUnmarshalErrorAfter(dec, t, ErrUnknownName) |
| | if !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { |
| | return err |
| | } |
| | errUnmarshal = cmp.Or(errUnmarshal, err) |
| | } |
| | if !uo.Flags.Get(jsonflags.AllowDuplicateNames) && !xd.Namespaces.Last().InsertUnquoted(name) { |
| | |
| | return newDuplicateNameError(dec.StackPointer(), nil, dec.InputOffset()-len64(val)) |
| | } |
| |
|
| | if fields.inlinedFallback == nil { |
| | |
| | if err := dec.SkipValue(); err != nil { |
| | return err |
| | } |
| | } else { |
| | |
| | if err := unmarshalInlinedFallbackNext(dec, va, uo, fields.inlinedFallback, val, name); err != nil { |
| | if isFatalError(err, uo.Flags) { |
| | return err |
| | } |
| | errUnmarshal = cmp.Or(errUnmarshal, err) |
| | } |
| | } |
| | continue |
| | } |
| | } |
| | if !uo.Flags.Get(jsonflags.AllowDuplicateNames) && !seenIdxs.insert(uint(f.id)) { |
| | |
| | return newDuplicateNameError(dec.StackPointer(), nil, dec.InputOffset()-len64(val)) |
| | } |
| |
|
| | |
| | unmarshal := f.fncs.unmarshal |
| | if uo.Unmarshalers != nil { |
| | unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, f.typ) |
| | } |
| | 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) |
| | } |
| | } |
| | if f.format != "" { |
| | uo.FormatDepth = xd.Tokens.Depth() |
| | uo.Format = f.format |
| | } |
| | v := addressableValue{va.Field(f.index0), va.forcedAddr} |
| | if len(f.index) > 0 { |
| | v = v.fieldByIndex(f.index, true) |
| | if !v.IsValid() { |
| | err := newUnmarshalErrorBefore(dec, t, errNilField) |
| | if !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { |
| | return err |
| | } |
| | errUnmarshal = cmp.Or(errUnmarshal, err) |
| | unmarshal = func(dec *jsontext.Decoder, _ addressableValue, _ *jsonopts.Struct) error { |
| | return dec.SkipValue() |
| | } |
| | } |
| | } |
| | err = unmarshal(dec, v, uo) |
| | uo.Flags = flagsOriginal |
| | uo.Format = "" |
| | if err != nil { |
| | if isFatalError(err, uo.Flags) { |
| | return err |
| | } |
| | errUnmarshal = cmp.Or(errUnmarshal, err) |
| | } |
| | } |
| | if _, err := dec.ReadToken(); err != nil { |
| | return err |
| | } |
| | return errUnmarshal |
| | } |
| | return newUnmarshalErrorAfterWithSkipping(dec, t, nil) |
| | } |
| | return &fncs |
| | } |
| |
|
| | func (va addressableValue) fieldByIndex(index []int, mayAlloc bool) addressableValue { |
| | for _, i := range index { |
| | va = va.indirect(mayAlloc) |
| | if !va.IsValid() { |
| | return va |
| | } |
| | va = addressableValue{va.Field(i), va.forcedAddr} |
| | } |
| | return va |
| | } |
| |
|
| | func (va addressableValue) indirect(mayAlloc bool) addressableValue { |
| | if va.Kind() == reflect.Pointer { |
| | if va.IsNil() { |
| | if !mayAlloc || !va.CanSet() { |
| | return addressableValue{} |
| | } |
| | va.Set(reflect.New(va.Type().Elem())) |
| | } |
| | va = addressableValue{va.Elem(), false} |
| | } |
| | return va |
| | } |
| |
|
| | |
| | func isLegacyEmpty(v addressableValue) bool { |
| | |
| | switch v.Kind() { |
| | case reflect.Bool: |
| | return v.Bool() == false |
| | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
| | return v.Int() == 0 |
| | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: |
| | return v.Uint() == 0 |
| | case reflect.Float32, reflect.Float64: |
| | return v.Float() == 0 |
| | case reflect.String, reflect.Map, reflect.Slice, reflect.Array: |
| | return v.Len() == 0 |
| | case reflect.Pointer, reflect.Interface: |
| | return v.IsNil() |
| | } |
| | return false |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func canLegacyStringify(t reflect.Type) bool { |
| | |
| | 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 ( |
| | once sync.Once |
| | valFncs *arshaler |
| | ) |
| | init := func() { |
| | valFncs = lookupArshaler(t.Elem()) |
| | } |
| | fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { |
| | |
| | xe := export.Encoder(enc) |
| | if xe.Tokens.Depth() > startDetectingCyclesAfter { |
| | if err := visitPointer(&xe.SeenPointers, va.Value); err != nil { |
| | return newMarshalErrorBefore(enc, t, err) |
| | } |
| | defer leavePointer(&xe.SeenPointers, va.Value) |
| | } |
| |
|
| | 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) |
| | } |
| | } |
| |
|
| | |
| | n := va.Len() |
| | if n == 0 { |
| | if emitNull && va.IsNil() { |
| | return enc.WriteToken(jsontext.Null) |
| | } |
| | |
| | if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() { |
| | xe.Buf = append(xe.Tokens.MayAppendDelim(xe.Buf, '['), "[]"...) |
| | xe.Tokens.Last.Increment() |
| | if xe.NeedFlush() { |
| | return xe.Flush() |
| | } |
| | return nil |
| | } |
| | } |
| |
|
| | once.Do(init) |
| | if err := enc.WriteToken(jsontext.BeginArray); err != nil { |
| | return err |
| | } |
| | marshal := valFncs.marshal |
| | if mo.Marshalers != nil { |
| | marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, t.Elem()) |
| | } |
| | for i := range n { |
| | v := addressableValue{va.Index(i), false} |
| | if err := marshal(enc, v, mo); err != nil { |
| | return err |
| | } |
| | } |
| | if err := enc.WriteToken(jsontext.EndArray); err != nil { |
| | return err |
| | } |
| | return nil |
| | } |
| | 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 = "" |
| | default: |
| | return newInvalidFormatError(dec, t) |
| | } |
| | } |
| |
|
| | tok, err := dec.ReadToken() |
| | if err != nil { |
| | return err |
| | } |
| | k := tok.Kind() |
| | switch k { |
| | case 'n': |
| | va.SetZero() |
| | return nil |
| | case '[': |
| | once.Do(init) |
| | unmarshal := valFncs.unmarshal |
| | if uo.Unmarshalers != nil { |
| | unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, t.Elem()) |
| | } |
| | mustZero := true |
| | cap := va.Cap() |
| | if cap > 0 { |
| | va.SetLen(cap) |
| | } |
| | var i int |
| | var errUnmarshal error |
| | for dec.PeekKind() != ']' { |
| | if i == cap { |
| | va.Value.Grow(1) |
| | cap = va.Cap() |
| | va.SetLen(cap) |
| | mustZero = false |
| | } |
| | v := addressableValue{va.Index(i), false} |
| | i++ |
| | if mustZero && !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { |
| | v.SetZero() |
| | } |
| | if err := unmarshal(dec, v, uo); err != nil { |
| | if isFatalError(err, uo.Flags) { |
| | va.SetLen(i) |
| | return err |
| | } |
| | errUnmarshal = cmp.Or(errUnmarshal, err) |
| | } |
| | } |
| | if i == 0 { |
| | va.Set(emptySlice) |
| | } else { |
| | va.SetLen(i) |
| | } |
| | if _, err := dec.ReadToken(); err != nil { |
| | return err |
| | } |
| | return errUnmarshal |
| | } |
| | return newUnmarshalErrorAfterWithSkipping(dec, t, nil) |
| | } |
| | return &fncs |
| | } |
| |
|
| | var errArrayUnderflow = errors.New("too few array elements") |
| | var errArrayOverflow = errors.New("too many array elements") |
| |
|
| | func makeArrayArshaler(t reflect.Type) *arshaler { |
| | var fncs arshaler |
| | var ( |
| | once sync.Once |
| | valFncs *arshaler |
| | ) |
| | init := func() { |
| | valFncs = lookupArshaler(t.Elem()) |
| | } |
| | 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) |
| | } |
| | once.Do(init) |
| | if err := enc.WriteToken(jsontext.BeginArray); err != nil { |
| | return err |
| | } |
| | marshal := valFncs.marshal |
| | if mo.Marshalers != nil { |
| | marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, t.Elem()) |
| | } |
| | for i := range n { |
| | v := addressableValue{va.Index(i), va.forcedAddr} |
| | if err := marshal(enc, v, mo); err != nil { |
| | return err |
| | } |
| | } |
| | if err := enc.WriteToken(jsontext.EndArray); err != nil { |
| | return err |
| | } |
| | 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) |
| | } |
| | tok, err := dec.ReadToken() |
| | if err != nil { |
| | return err |
| | } |
| | k := tok.Kind() |
| | switch k { |
| | case 'n': |
| | if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { |
| | va.SetZero() |
| | } |
| | return nil |
| | case '[': |
| | once.Do(init) |
| | unmarshal := valFncs.unmarshal |
| | if uo.Unmarshalers != nil { |
| | unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, t.Elem()) |
| | } |
| | var i int |
| | var errUnmarshal error |
| | for dec.PeekKind() != ']' { |
| | if i >= n { |
| | if err := dec.SkipValue(); err != nil { |
| | return err |
| | } |
| | err = errArrayOverflow |
| | continue |
| | } |
| | v := addressableValue{va.Index(i), va.forcedAddr} |
| | if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { |
| | v.SetZero() |
| | } |
| | if err := unmarshal(dec, v, uo); err != nil { |
| | if isFatalError(err, uo.Flags) { |
| | return err |
| | } |
| | errUnmarshal = cmp.Or(errUnmarshal, err) |
| | } |
| | i++ |
| | } |
| | for ; i < n; i++ { |
| | va.Index(i).SetZero() |
| | err = errArrayUnderflow |
| | } |
| | if _, err := dec.ReadToken(); err != nil { |
| | return err |
| | } |
| | if err != nil && !uo.Flags.Get(jsonflags.UnmarshalArrayFromAnyLength) { |
| | return newUnmarshalErrorAfter(dec, t, err) |
| | } |
| | return errUnmarshal |
| | } |
| | return newUnmarshalErrorAfterWithSkipping(dec, t, nil) |
| | } |
| | return &fncs |
| | } |
| |
|
| | func makePointerArshaler(t reflect.Type) *arshaler { |
| | var fncs arshaler |
| | var ( |
| | once sync.Once |
| | valFncs *arshaler |
| | ) |
| | init := func() { |
| | valFncs = lookupArshaler(t.Elem()) |
| | } |
| | fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { |
| | |
| | xe := export.Encoder(enc) |
| | if xe.Tokens.Depth() > startDetectingCyclesAfter { |
| | if err := visitPointer(&xe.SeenPointers, va.Value); err != nil { |
| | return newMarshalErrorBefore(enc, t, err) |
| | } |
| | defer leavePointer(&xe.SeenPointers, va.Value) |
| | } |
| |
|
| | |
| | if va.IsNil() { |
| | return enc.WriteToken(jsontext.Null) |
| | } |
| | once.Do(init) |
| | marshal := valFncs.marshal |
| | if mo.Marshalers != nil { |
| | marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, t.Elem()) |
| | } |
| | v := addressableValue{va.Elem(), false} |
| | return marshal(enc, v, mo) |
| | } |
| | fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { |
| | |
| | if dec.PeekKind() == 'n' { |
| | if _, err := dec.ReadToken(); err != nil { |
| | return err |
| | } |
| | va.SetZero() |
| | return nil |
| | } |
| | once.Do(init) |
| | unmarshal := valFncs.unmarshal |
| | if uo.Unmarshalers != nil { |
| | unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, t.Elem()) |
| | } |
| | if va.IsNil() { |
| | va.Set(reflect.New(t.Elem())) |
| | } |
| | v := addressableValue{va.Elem(), false} |
| | if err := unmarshal(dec, v, uo); err != nil { |
| | return err |
| | } |
| | if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && |
| | uo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.StringifyBoolsAndStrings) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | if string(export.Decoder(dec).PreviousTokenOrValue()) == `"null"` { |
| | va.SetZero() |
| | } |
| | } |
| | return nil |
| | } |
| | return &fncs |
| | } |
| |
|
| | func makeInterfaceArshaler(t reflect.Type) *arshaler { |
| | |
| | |
| | |
| |
|
| | var fncs arshaler |
| | var whichMarshaler reflect.Type |
| | for _, iface := range allMarshalerTypes { |
| | if t.Implements(iface) { |
| | whichMarshaler = t |
| | break |
| | } |
| | } |
| | 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) |
| | } |
| | if va.IsNil() { |
| | return enc.WriteToken(jsontext.Null) |
| | } else if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && whichMarshaler != nil { |
| | |
| | |
| | |
| | if va.Elem().Kind() == reflect.Pointer && va.Elem().IsNil() { |
| | v2 := newAddressableValue(whichMarshaler) |
| | switch whichMarshaler { |
| | case jsonMarshalerToType: |
| | v2.Set(reflect.ValueOf(struct{ MarshalerTo }{va.Elem().Interface().(MarshalerTo)})) |
| | case jsonMarshalerType: |
| | v2.Set(reflect.ValueOf(struct{ Marshaler }{va.Elem().Interface().(Marshaler)})) |
| | case textAppenderType: |
| | v2.Set(reflect.ValueOf(struct{ encoding.TextAppender }{va.Elem().Interface().(encoding.TextAppender)})) |
| | case textMarshalerType: |
| | v2.Set(reflect.ValueOf(struct{ encoding.TextMarshaler }{va.Elem().Interface().(encoding.TextMarshaler)})) |
| | } |
| | va = v2 |
| | } |
| | } |
| | v := newAddressableValue(va.Elem().Type()) |
| | v.Set(va.Elem()) |
| | marshal := lookupArshaler(v.Type()).marshal |
| | if mo.Marshalers != nil { |
| | marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, v.Type()) |
| | } |
| | |
| | if optimizeCommon && |
| | t == anyType && !mo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.StringifyBoolsAndStrings) && mo.Format == "" && |
| | (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) |
| | } |
| | if uo.Flags.Get(jsonflags.MergeWithLegacySemantics) && !va.IsNil() { |
| | |
| | |
| | |
| | |
| | |
| | e := va.Elem() |
| | if e.Kind() == reflect.Pointer && !e.IsNil() { |
| | if dec.PeekKind() == 'n' && e.Elem().Kind() == reflect.Pointer { |
| | if _, err := dec.ReadToken(); err != nil { |
| | return err |
| | } |
| | va.Elem().Elem().SetZero() |
| | return nil |
| | } |
| | } else { |
| | va.SetZero() |
| | } |
| | } |
| | if dec.PeekKind() == 'n' { |
| | if _, err := dec.ReadToken(); err != nil { |
| | return err |
| | } |
| | va.SetZero() |
| | return nil |
| | } |
| | var v addressableValue |
| | if va.IsNil() { |
| | |
| | |
| | |
| | |
| | |
| | if optimizeCommon && |
| | t == anyType && !uo.Flags.Get(jsonflags.AllowDuplicateNames) && uo.Format == "" && |
| | (uo.Unmarshalers == nil || !uo.Unmarshalers.(*Unmarshalers).fromAny) { |
| | v, err := unmarshalValueAny(dec, uo) |
| | |
| | |
| | if v != nil { |
| | va.Set(reflect.ValueOf(v)) |
| | } |
| | return err |
| | } |
| |
|
| | k := dec.PeekKind() |
| | if !isAnyType(t) { |
| | return newUnmarshalErrorBeforeWithSkipping(dec, t, internal.ErrNilInterface) |
| | } |
| | switch k { |
| | case 'f', 't': |
| | v = newAddressableValue(boolType) |
| | case '"': |
| | v = newAddressableValue(stringType) |
| | case '0': |
| | if uo.Flags.Get(jsonflags.UnmarshalAnyWithRawNumber) { |
| | v = addressableValue{reflect.ValueOf(internal.NewRawNumber()).Elem(), true} |
| | } else { |
| | v = newAddressableValue(float64Type) |
| | } |
| | case '{': |
| | v = newAddressableValue(mapStringAnyType) |
| | case '[': |
| | v = newAddressableValue(sliceAnyType) |
| | default: |
| | |
| | |
| | |
| | |
| | _, err := dec.ReadValue() |
| | return err |
| | } |
| | } else { |
| | |
| | |
| | |
| | v = newAddressableValue(va.Elem().Type()) |
| | v.Set(va.Elem()) |
| | } |
| | unmarshal := lookupArshaler(v.Type()).unmarshal |
| | if uo.Unmarshalers != nil { |
| | unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, v.Type()) |
| | } |
| | err := unmarshal(dec, v, uo) |
| | va.Set(v.Value) |
| | return err |
| | } |
| | return &fncs |
| | } |
| |
|
| | |
| | func isAnyType(t reflect.Type) bool { |
| | |
| | |
| | |
| | |
| | return t == anyType || anyType.Implements(t) |
| | } |
| |
|
| | func makeInvalidArshaler(t reflect.Type) *arshaler { |
| | var fncs arshaler |
| | fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { |
| | return newMarshalErrorBefore(enc, t, nil) |
| | } |
| | fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { |
| | return newUnmarshalErrorBefore(dec, t, nil) |
| | } |
| | return &fncs |
| | } |
| |
|
| | func stringOrNumberKind(isString bool) jsontext.Kind { |
| | if isString { |
| | return '"' |
| | } else { |
| | return '0' |
| | } |
| | } |
| |
|
| | type uintSet64 uint64 |
| |
|
| | func (s uintSet64) has(i uint) bool { return s&(1<<i) > 0 } |
| | func (s *uintSet64) set(i uint) { *s |= 1 << i } |
| |
|
| | |
| | |
| | type uintSet struct { |
| | lo uintSet64 |
| | hi []uintSet64 |
| | } |
| |
|
| | |
| | func (s *uintSet) has(i uint) bool { |
| | if i < 64 { |
| | return s.lo.has(i) |
| | } else { |
| | i -= 64 |
| | iHi, iLo := int(i/64), i%64 |
| | return iHi < len(s.hi) && s.hi[iHi].has(iLo) |
| | } |
| | } |
| |
|
| | |
| | func (s *uintSet) insert(i uint) bool { |
| | |
| | if i < 64 { |
| | has := s.lo.has(i) |
| | s.lo.set(i) |
| | return !has |
| | } else { |
| | i -= 64 |
| | iHi, iLo := int(i/64), i%64 |
| | if iHi >= len(s.hi) { |
| | s.hi = append(s.hi, make([]uintSet64, iHi+1-len(s.hi))...) |
| | s.hi = s.hi[:cap(s.hi)] |
| | } |
| | has := s.hi[iHi].has(iLo) |
| | s.hi[iHi].set(iLo) |
| | return !has |
| | } |
| | } |
| |
|