package json
import (
"bytes"
"errors"
"io"
"reflect"
"encoding/json/internal/jsonflags"
"encoding/json/internal/jsonopts"
"encoding/json/internal/jsonwire"
"encoding/json/jsontext"
)
var errRawInlinedNotObject = errors .New ("inlined raw value must be a JSON object" )
var jsontextValueType = reflect .TypeFor [jsontext .Value ]()
func marshalInlinedFallbackAll(enc *jsontext .Encoder , va addressableValue , mo *jsonopts .Struct , f *structField , insertUnquotedName func ([]byte ) bool ) error {
v := addressableValue {va .Field (f .index0 ), va .forcedAddr }
if len (f .index ) > 0 {
v = v .fieldByIndex (f .index , false )
if !v .IsValid () {
return nil
}
}
v = v .indirect (false )
if !v .IsValid () {
return nil
}
if v .Type () == jsontextValueType {
b := *v .Addr ().Interface ().(*jsontext .Value )
if len (b ) == 0 {
return nil
}
dec := export .GetBufferedDecoder (b )
defer export .PutBufferedDecoder (dec )
xd := export .Decoder (dec )
xd .Flags .Set (jsonflags .AllowDuplicateNames | jsonflags .AllowInvalidUTF8 | 1 )
tok , err := dec .ReadToken ()
if err != nil {
if err == io .EOF {
err = io .ErrUnexpectedEOF
}
return newMarshalErrorBefore (enc , v .Type (), err )
}
if tok .Kind () != '{' {
return newMarshalErrorBefore (enc , v .Type (), errRawInlinedNotObject )
}
for dec .PeekKind () != '}' {
var flags jsonwire .ValueFlags
val , err := xd .ReadValue (&flags )
if err != nil {
return newMarshalErrorBefore (enc , v .Type (), err )
}
if insertUnquotedName != nil {
name := jsonwire .UnquoteMayCopy (val , flags .IsVerbatim ())
if !insertUnquotedName (name ) {
return newDuplicateNameError (enc .StackPointer ().Parent (), val , enc .OutputOffset ())
}
}
if err := enc .WriteValue (val ); err != nil {
return err
}
val , err = xd .ReadValue (&flags )
if err != nil {
return newMarshalErrorBefore (enc , v .Type (), err )
}
if err := enc .WriteValue (val ); err != nil {
return err
}
}
if _ , err := dec .ReadToken (); err != nil {
return newMarshalErrorBefore (enc , v .Type (), err )
}
if err := xd .CheckEOF (); err != nil {
return newMarshalErrorBefore (enc , v .Type (), err )
}
return nil
} else {
m := v
n := m .Len ()
if n == 0 {
return nil
}
mk := newAddressableValue (m .Type ().Key ())
mv := newAddressableValue (m .Type ().Elem ())
marshalKey := func (mk addressableValue ) error {
b , err := jsonwire .AppendQuote (enc .UnusedBuffer (), mk .String (), &mo .Flags )
if err != nil {
return newMarshalErrorBefore (enc , m .Type ().Key (), err )
}
if insertUnquotedName != nil {
isVerbatim := bytes .IndexByte (b , '\\' ) < 0
name := jsonwire .UnquoteMayCopy (b , isVerbatim )
if !insertUnquotedName (name ) {
return newDuplicateNameError (enc .StackPointer ().Parent (), b , enc .OutputOffset ())
}
}
return enc .WriteValue (b )
}
marshalVal := f .fncs .marshal
if mo .Marshalers != nil {
marshalVal , _ = mo .Marshalers .(*Marshalers ).lookup (marshalVal , mv .Type ())
}
if !mo .Flags .Get (jsonflags .Deterministic ) || n <= 1 {
for iter := m .MapRange (); iter .Next (); {
mk .SetIterKey (iter )
if err := marshalKey (mk ); err != nil {
return err
}
mv .Set (iter .Value ())
if err := marshalVal (enc , mv , mo ); err != nil {
return err
}
}
} else {
names := getStrings (n )
for i , iter := 0 , m .Value .MapRange (); i < n && iter .Next (); i ++ {
mk .SetIterKey (iter )
(*names )[i ] = mk .String ()
}
names .Sort ()
for _ , name := range *names {
mk .SetString (name )
if err := marshalKey (mk ); err != nil {
return err
}
mv .Set (m .MapIndex (mk .Value ))
if err := marshalVal (enc , mv , mo ); err != nil {
return err
}
}
putStrings (names )
}
return nil
}
}
func unmarshalInlinedFallbackNext(dec *jsontext .Decoder , va addressableValue , uo *jsonopts .Struct , f *structField , quotedName , unquotedName []byte ) error {
v := addressableValue {va .Field (f .index0 ), va .forcedAddr }
if len (f .index ) > 0 {
v = v .fieldByIndex (f .index , true )
}
v = v .indirect (true )
if v .Type () == jsontextValueType {
b := v .Addr ().Interface ().(*jsontext .Value )
if len (*b ) == 0 {
*b = append (*b , '{' )
} else {
*b = jsonwire .TrimSuffixWhitespace (*b )
if jsonwire .HasSuffixByte (*b , '}' ) {
*b = jsonwire .TrimSuffixByte (*b , '}' )
*b = jsonwire .TrimSuffixWhitespace (*b )
if !jsonwire .HasSuffixByte (*b , ',' ) && !jsonwire .HasSuffixByte (*b , '{' ) {
*b = append (*b , ',' )
}
} else {
return newUnmarshalErrorAfterWithSkipping (dec , uo , v .Type (), errRawInlinedNotObject )
}
}
*b = append (*b , quotedName ...)
*b = append (*b , ':' )
val , err := dec .ReadValue ()
if err != nil {
return err
}
*b = append (*b , val ...)
*b = append (*b , '}' )
return nil
} else {
name := string (unquotedName )
m := v
if m .IsNil () {
m .Set (reflect .MakeMap (m .Type ()))
}
mk := reflect .ValueOf (name )
if mkt := m .Type ().Key (); mkt != stringType {
mk = mk .Convert (mkt )
}
mv := newAddressableValue (m .Type ().Elem ())
if v2 := m .MapIndex (mk ); v2 .IsValid () {
mv .Set (v2 )
}
unmarshal := f .fncs .unmarshal
if uo .Unmarshalers != nil {
unmarshal , _ = uo .Unmarshalers .(*Unmarshalers ).lookup (unmarshal , mv .Type ())
}
err := unmarshal (dec , mv , uo )
m .SetMapIndex (mk , mv .Value )
if err != nil {
return err
}
return nil
}
}
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 .