Source file src/encoding/json/v2/arshal_inlined.go

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build goexperiment.jsonv2
     6  
     7  package json
     8  
     9  import (
    10  	"bytes"
    11  	"errors"
    12  	"io"
    13  	"reflect"
    14  
    15  	"encoding/json/internal/jsonflags"
    16  	"encoding/json/internal/jsonopts"
    17  	"encoding/json/internal/jsonwire"
    18  	"encoding/json/jsontext"
    19  )
    20  
    21  // This package supports "inlining" a Go struct field, where the contents
    22  // of the serialized field (which must be a JSON object) are treated as if
    23  // they are part of the parent Go struct (which represents a JSON object).
    24  //
    25  // Generally, inlined fields are of a Go struct type, where the fields of the
    26  // nested struct are virtually hoisted up to the parent struct using rules
    27  // similar to how Go embedding works (but operating within the JSON namespace).
    28  //
    29  // However, inlined fields may also be of a Go map type with a string key or
    30  // a jsontext.Value. Such inlined fields are called "fallback" fields since they
    31  // represent any arbitrary JSON object member. Explicitly named fields take
    32  // precedence over the inlined fallback. Only one inlined fallback is allowed.
    33  
    34  var errRawInlinedNotObject = errors.New("inlined raw value must be a JSON object")
    35  
    36  var jsontextValueType = reflect.TypeFor[jsontext.Value]()
    37  
    38  // marshalInlinedFallbackAll marshals all the members in an inlined fallback.
    39  func marshalInlinedFallbackAll(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct, f *structField, insertUnquotedName func([]byte) bool) error {
    40  	v := addressableValue{va.Field(f.index0), va.forcedAddr} // addressable if struct value is addressable
    41  	if len(f.index) > 0 {
    42  		v = v.fieldByIndex(f.index, false)
    43  		if !v.IsValid() {
    44  			return nil // implies a nil inlined field
    45  		}
    46  	}
    47  	v = v.indirect(false)
    48  	if !v.IsValid() {
    49  		return nil
    50  	}
    51  
    52  	if v.Type() == jsontextValueType {
    53  		// TODO(https://go.dev/issue/62121): Use reflect.Value.AssertTo.
    54  		b := *v.Addr().Interface().(*jsontext.Value)
    55  		if len(b) == 0 { // TODO: Should this be nil? What if it were all whitespace?
    56  			return nil
    57  		}
    58  
    59  		dec := export.GetBufferedDecoder(b)
    60  		defer export.PutBufferedDecoder(dec)
    61  		xd := export.Decoder(dec)
    62  		xd.Flags.Set(jsonflags.AllowDuplicateNames | jsonflags.AllowInvalidUTF8 | 1)
    63  
    64  		tok, err := dec.ReadToken()
    65  		if err != nil {
    66  			if err == io.EOF {
    67  				err = io.ErrUnexpectedEOF
    68  			}
    69  			return newMarshalErrorBefore(enc, v.Type(), err)
    70  		}
    71  		if tok.Kind() != '{' {
    72  			return newMarshalErrorBefore(enc, v.Type(), errRawInlinedNotObject)
    73  		}
    74  		for dec.PeekKind() != '}' {
    75  			// Parse the JSON object name.
    76  			var flags jsonwire.ValueFlags
    77  			val, err := xd.ReadValue(&flags)
    78  			if err != nil {
    79  				return newMarshalErrorBefore(enc, v.Type(), err)
    80  			}
    81  			if insertUnquotedName != nil {
    82  				name := jsonwire.UnquoteMayCopy(val, flags.IsVerbatim())
    83  				if !insertUnquotedName(name) {
    84  					return newDuplicateNameError(enc.StackPointer().Parent(), val, enc.OutputOffset())
    85  				}
    86  			}
    87  			if err := enc.WriteValue(val); err != nil {
    88  				return err
    89  			}
    90  
    91  			// Parse the JSON object value.
    92  			val, err = xd.ReadValue(&flags)
    93  			if err != nil {
    94  				return newMarshalErrorBefore(enc, v.Type(), err)
    95  			}
    96  			if err := enc.WriteValue(val); err != nil {
    97  				return err
    98  			}
    99  		}
   100  		if _, err := dec.ReadToken(); err != nil {
   101  			return newMarshalErrorBefore(enc, v.Type(), err)
   102  		}
   103  		if err := xd.CheckEOF(); err != nil {
   104  			return newMarshalErrorBefore(enc, v.Type(), err)
   105  		}
   106  		return nil
   107  	} else {
   108  		m := v // must be a map[~string]V
   109  		n := m.Len()
   110  		if n == 0 {
   111  			return nil
   112  		}
   113  		mk := newAddressableValue(m.Type().Key())
   114  		mv := newAddressableValue(m.Type().Elem())
   115  		marshalKey := func(mk addressableValue) error {
   116  			b, err := jsonwire.AppendQuote(enc.UnusedBuffer(), mk.String(), &mo.Flags)
   117  			if err != nil {
   118  				return newMarshalErrorBefore(enc, m.Type().Key(), err)
   119  			}
   120  			if insertUnquotedName != nil {
   121  				isVerbatim := bytes.IndexByte(b, '\\') < 0
   122  				name := jsonwire.UnquoteMayCopy(b, isVerbatim)
   123  				if !insertUnquotedName(name) {
   124  					return newDuplicateNameError(enc.StackPointer().Parent(), b, enc.OutputOffset())
   125  				}
   126  			}
   127  			return enc.WriteValue(b)
   128  		}
   129  		marshalVal := f.fncs.marshal
   130  		if mo.Marshalers != nil {
   131  			marshalVal, _ = mo.Marshalers.(*Marshalers).lookup(marshalVal, mv.Type())
   132  		}
   133  		if !mo.Flags.Get(jsonflags.Deterministic) || n <= 1 {
   134  			for iter := m.MapRange(); iter.Next(); {
   135  				mk.SetIterKey(iter)
   136  				if err := marshalKey(mk); err != nil {
   137  					return err
   138  				}
   139  				mv.Set(iter.Value())
   140  				if err := marshalVal(enc, mv, mo); err != nil {
   141  					return err
   142  				}
   143  			}
   144  		} else {
   145  			names := getStrings(n)
   146  			for i, iter := 0, m.Value.MapRange(); i < n && iter.Next(); i++ {
   147  				mk.SetIterKey(iter)
   148  				(*names)[i] = mk.String()
   149  			}
   150  			names.Sort()
   151  			for _, name := range *names {
   152  				mk.SetString(name)
   153  				if err := marshalKey(mk); err != nil {
   154  					return err
   155  				}
   156  				// TODO(https://go.dev/issue/57061): Use mv.SetMapIndexOf.
   157  				mv.Set(m.MapIndex(mk.Value))
   158  				if err := marshalVal(enc, mv, mo); err != nil {
   159  					return err
   160  				}
   161  			}
   162  			putStrings(names)
   163  		}
   164  		return nil
   165  	}
   166  }
   167  
   168  // unmarshalInlinedFallbackNext unmarshals only the next member in an inlined fallback.
   169  func unmarshalInlinedFallbackNext(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct, f *structField, quotedName, unquotedName []byte) error {
   170  	v := addressableValue{va.Field(f.index0), va.forcedAddr} // addressable if struct value is addressable
   171  	if len(f.index) > 0 {
   172  		v = v.fieldByIndex(f.index, true)
   173  	}
   174  	v = v.indirect(true)
   175  
   176  	if v.Type() == jsontextValueType {
   177  		b := v.Addr().Interface().(*jsontext.Value)
   178  		if len(*b) == 0 { // TODO: Should this be nil? What if it were all whitespace?
   179  			*b = append(*b, '{')
   180  		} else {
   181  			*b = jsonwire.TrimSuffixWhitespace(*b)
   182  			if jsonwire.HasSuffixByte(*b, '}') {
   183  				// TODO: When merging into an object for the first time,
   184  				// should we verify that it is valid?
   185  				*b = jsonwire.TrimSuffixByte(*b, '}')
   186  				*b = jsonwire.TrimSuffixWhitespace(*b)
   187  				if !jsonwire.HasSuffixByte(*b, ',') && !jsonwire.HasSuffixByte(*b, '{') {
   188  					*b = append(*b, ',')
   189  				}
   190  			} else {
   191  				return newUnmarshalErrorAfterWithSkipping(dec, uo, v.Type(), errRawInlinedNotObject)
   192  			}
   193  		}
   194  		*b = append(*b, quotedName...)
   195  		*b = append(*b, ':')
   196  		val, err := dec.ReadValue()
   197  		if err != nil {
   198  			return err
   199  		}
   200  		*b = append(*b, val...)
   201  		*b = append(*b, '}')
   202  		return nil
   203  	} else {
   204  		name := string(unquotedName) // TODO: Intern this?
   205  
   206  		m := v // must be a map[~string]V
   207  		if m.IsNil() {
   208  			m.Set(reflect.MakeMap(m.Type()))
   209  		}
   210  		mk := reflect.ValueOf(name)
   211  		if mkt := m.Type().Key(); mkt != stringType {
   212  			mk = mk.Convert(mkt)
   213  		}
   214  		mv := newAddressableValue(m.Type().Elem()) // TODO: Cache across calls?
   215  		if v2 := m.MapIndex(mk); v2.IsValid() {
   216  			mv.Set(v2)
   217  		}
   218  
   219  		unmarshal := f.fncs.unmarshal
   220  		if uo.Unmarshalers != nil {
   221  			unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, mv.Type())
   222  		}
   223  		err := unmarshal(dec, mv, uo)
   224  		m.SetMapIndex(mk, mv.Value)
   225  		if err != nil {
   226  			return err
   227  		}
   228  		return nil
   229  	}
   230  }
   231  

View as plain text