k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/internal/third_party/go-json-experiment/json/arshal_inlined.go (about)

     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  package json
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"reflect"
    11  )
    12  
    13  // This package supports "inlining" a Go struct field, where the contents
    14  // of the serialized field (which must be a JSON object) are treated as if
    15  // they are part of the parent Go struct (which represents a JSON object).
    16  //
    17  // Generally, inlined fields are of a Go struct type, where the fields of the
    18  // nested struct are virtually hoisted up to the parent struct using rules
    19  // similar to how Go embedding works (but operating within the JSON namespace).
    20  //
    21  // However, inlined fields may also be of a Go map type with a string key
    22  // or a RawValue. Such inlined fields are called "fallback" fields since they
    23  // represent any arbitrary JSON object member. Explicitly named fields take
    24  // precedence over the inlined fallback. Only one inlined fallback is allowed.
    25  
    26  var rawValueType = reflect.TypeOf((*RawValue)(nil)).Elem()
    27  
    28  // marshalInlinedFallbackAll marshals all the members in an inlined fallback.
    29  func marshalInlinedFallbackAll(mo MarshalOptions, enc *Encoder, va addressableValue, f *structField, insertUnquotedName func([]byte) bool) error {
    30  	v := addressableValue{va.Field(f.index[0])} // addressable if struct value is addressable
    31  	if len(f.index) > 1 {
    32  		v = v.fieldByIndex(f.index[1:], false)
    33  		if !v.IsValid() {
    34  			return nil // implies a nil inlined field
    35  		}
    36  	}
    37  	v = v.indirect(false)
    38  	if !v.IsValid() {
    39  		return nil
    40  	}
    41  
    42  	if v.Type() == rawValueType {
    43  		b := v.Interface().(RawValue)
    44  		if len(b) == 0 { // TODO: Should this be nil? What if it were all whitespace?
    45  			return nil
    46  		}
    47  
    48  		dec := getBufferedDecoder(b, DecodeOptions{AllowDuplicateNames: true, AllowInvalidUTF8: true})
    49  		defer putBufferedDecoder(dec)
    50  
    51  		tok, err := dec.ReadToken()
    52  		if err != nil {
    53  			return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
    54  		}
    55  		if tok.Kind() != '{' {
    56  			err := errors.New("inlined raw value must be a JSON object")
    57  			return &SemanticError{action: "marshal", JSONKind: tok.Kind(), GoType: rawValueType, Err: err}
    58  		}
    59  		for dec.PeekKind() != '}' {
    60  			// Parse the JSON object name.
    61  			var flags valueFlags
    62  			val, err := dec.readValue(&flags)
    63  			if err != nil {
    64  				return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
    65  			}
    66  			if insertUnquotedName != nil {
    67  				name := unescapeStringMayCopy(val, flags.isVerbatim())
    68  				if !insertUnquotedName(name) {
    69  					return &SyntacticError{str: "duplicate name " + string(val) + " in object"}
    70  				}
    71  			}
    72  			if err := enc.WriteValue(val); err != nil {
    73  				return err
    74  			}
    75  
    76  			// Parse the JSON object value.
    77  			val, err = dec.readValue(&flags)
    78  			if err != nil {
    79  				return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
    80  			}
    81  			if err := enc.WriteValue(val); err != nil {
    82  				return err
    83  			}
    84  		}
    85  		if _, err := dec.ReadToken(); err != nil {
    86  			return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
    87  		}
    88  		if err := dec.checkEOF(); err != nil {
    89  			return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
    90  		}
    91  		return nil
    92  	} else {
    93  		m := v // must be a map[string]V
    94  		n := m.Len()
    95  		if n == 0 {
    96  			return nil
    97  		}
    98  		mk := newAddressableValue(stringType)
    99  		mv := newAddressableValue(m.Type().Elem())
   100  		marshalKey := func(mk addressableValue) error {
   101  			b, err := appendString(enc.UnusedBuffer(), mk.String(), !enc.options.AllowInvalidUTF8, nil)
   102  			if err != nil {
   103  				return err
   104  			}
   105  			if insertUnquotedName != nil {
   106  				isVerbatim := bytes.IndexByte(b, '\\') < 0
   107  				name := unescapeStringMayCopy(b, isVerbatim)
   108  				if !insertUnquotedName(name) {
   109  					return &SyntacticError{str: "duplicate name " + string(b) + " in object"}
   110  				}
   111  			}
   112  			return enc.WriteValue(b)
   113  		}
   114  		marshalVal := f.fncs.marshal
   115  		if mo.Marshalers != nil {
   116  			marshalVal, _ = mo.Marshalers.lookup(marshalVal, mv.Type())
   117  		}
   118  		if !mo.Deterministic || n <= 1 {
   119  			for iter := m.MapRange(); iter.Next(); {
   120  				mk.SetIterKey(iter)
   121  				if err := marshalKey(mk); err != nil {
   122  					return err
   123  				}
   124  				mv.Set(iter.Value())
   125  				if err := marshalVal(mo, enc, mv); err != nil {
   126  					return err
   127  				}
   128  			}
   129  		} else {
   130  			names := getStrings(n)
   131  			for i, iter := 0, m.Value.MapRange(); i < n && iter.Next(); i++ {
   132  				mk.SetIterKey(iter)
   133  				(*names)[i] = mk.String()
   134  			}
   135  			names.Sort()
   136  			for _, name := range *names {
   137  				mk.SetString(name)
   138  				if err := marshalKey(mk); err != nil {
   139  					return err
   140  				}
   141  				// TODO(https://go.dev/issue/57061): Use mv.SetMapIndexOf.
   142  				mv.Set(m.MapIndex(mk.Value))
   143  				if err := marshalVal(mo, enc, mv); err != nil {
   144  					return err
   145  				}
   146  			}
   147  			putStrings(names)
   148  		}
   149  		return nil
   150  	}
   151  }
   152  
   153  // unmarshalInlinedFallbackNext unmarshals only the next member in an inlined fallback.
   154  func unmarshalInlinedFallbackNext(uo UnmarshalOptions, dec *Decoder, va addressableValue, f *structField, quotedName, unquotedName []byte) error {
   155  	v := addressableValue{va.Field(f.index[0])} // addressable if struct value is addressable
   156  	if len(f.index) > 1 {
   157  		v = v.fieldByIndex(f.index[1:], true)
   158  	}
   159  	v = v.indirect(true)
   160  
   161  	if v.Type() == rawValueType {
   162  		b := v.Addr().Interface().(*RawValue)
   163  		if len(*b) == 0 { // TODO: Should this be nil? What if it were all whitespace?
   164  			*b = append(*b, '{')
   165  		} else {
   166  			*b = trimSuffixWhitespace(*b)
   167  			if hasSuffixByte(*b, '}') {
   168  				// TODO: When merging into an object for the first time,
   169  				// should we verify that it is valid?
   170  				*b = trimSuffixByte(*b, '}')
   171  				*b = trimSuffixWhitespace(*b)
   172  				if !hasSuffixByte(*b, ',') && !hasSuffixByte(*b, '{') {
   173  					*b = append(*b, ',')
   174  				}
   175  			} else {
   176  				err := errors.New("inlined raw value must be a JSON object")
   177  				return &SemanticError{action: "unmarshal", GoType: rawValueType, Err: err}
   178  			}
   179  		}
   180  		*b = append(*b, quotedName...)
   181  		*b = append(*b, ':')
   182  		rawValue, err := dec.ReadValue()
   183  		if err != nil {
   184  			return err
   185  		}
   186  		*b = append(*b, rawValue...)
   187  		*b = append(*b, '}')
   188  		return nil
   189  	} else {
   190  		name := string(unquotedName) // TODO: Intern this?
   191  
   192  		m := v // must be a map[string]V
   193  		if m.IsNil() {
   194  			m.Set(reflect.MakeMap(m.Type()))
   195  		}
   196  		mk := reflect.ValueOf(name)
   197  		mv := newAddressableValue(v.Type().Elem()) // TODO: Cache across calls?
   198  		if v2 := m.MapIndex(mk); v2.IsValid() {
   199  			mv.Set(v2)
   200  		}
   201  
   202  		unmarshal := f.fncs.unmarshal
   203  		if uo.Unmarshalers != nil {
   204  			unmarshal, _ = uo.Unmarshalers.lookup(unmarshal, mv.Type())
   205  		}
   206  		err := unmarshal(uo, dec, mv)
   207  		m.SetMapIndex(mk, mv.Value)
   208  		if err != nil {
   209  			return err
   210  		}
   211  		return nil
   212  	}
   213  }