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 , mo )
}
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 , uo )
}
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 , uo , 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 , mo )
}
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 , 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 .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 , mo )
}
} else if mo .Flags .Get (jsonflags .FormatBytesWithLegacySemantics ) &&
(va .Kind () == reflect .Array || 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 , uo )
}
} else if uo .Flags .Get (jsonflags .FormatBytesWithLegacySemantics ) &&
(va .Kind () == reflect .Array || 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 .FormatBytesWithLegacySemantics ) {
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 , mo )
}
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 , uo )
}
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 ) && string (val ) == "null" {
if !uo .Flags .Get (jsonflags .MergeWithLegacySemantics ) {
va .SetInt (0 )
}
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 , mo )
}
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 , uo )
}
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 ) && string (val ) == "null" {
if !uo .Flags .Get (jsonflags .MergeWithLegacySemantics ) {
va .SetUint (0 )
}
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 , mo )
}
}
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 , uo )
}
}
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 ) && string (val ) == "null" {
if !uo .Flags .Get (jsonflags .MergeWithLegacySemantics ) {
va .SetFloat (0 )
}
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 , mo )
}
}
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 ()
}
names .Sort ()
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 , uo )
}
}
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 , uo , 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 , mo )
}
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 .OmitEmptyWithLegacyDefinition ) && 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 .OmitEmptyWithLegacyDefinition ) &&
!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 .OmitEmptyWithLegacyDefinition ) {
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 , uo )
}
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 , uo , 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 , mo )
}
}
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 , uo )
}
}
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 , uo , 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 , mo )
}
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 , uo )
}
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 , uo , 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
}
var errNilInterface = errors .New ("cannot derive concrete type for nil interface with finite type set" )
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 , mo )
}
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 , uo )
}
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 , uo , t , 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
}
}
The pages are generated with Golds v0.7.7-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .