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

     1  // Copyright 2022 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  	"cmp"
    11  	"reflect"
    12  	"strconv"
    13  
    14  	"encoding/json/internal"
    15  	"encoding/json/internal/jsonflags"
    16  	"encoding/json/internal/jsonopts"
    17  	"encoding/json/internal/jsonwire"
    18  	"encoding/json/jsontext"
    19  )
    20  
    21  // This file contains an optimized marshal and unmarshal implementation
    22  // for the any type. This type is often used when the Go program has
    23  // no knowledge of the JSON schema. This is a common enough occurrence
    24  // to justify the complexity of adding logic for this.
    25  
    26  // marshalValueAny marshals a Go any as a JSON value.
    27  // This assumes that there are no special formatting directives
    28  // for any possible nested value.
    29  func marshalValueAny(enc *jsontext.Encoder, val any, mo *jsonopts.Struct) error {
    30  	switch val := val.(type) {
    31  	case nil:
    32  		return enc.WriteToken(jsontext.Null)
    33  	case bool:
    34  		return enc.WriteToken(jsontext.Bool(val))
    35  	case string:
    36  		return enc.WriteToken(jsontext.String(val))
    37  	case float64:
    38  		return enc.WriteToken(jsontext.Float(val))
    39  	case map[string]any:
    40  		return marshalObjectAny(enc, val, mo)
    41  	case []any:
    42  		return marshalArrayAny(enc, val, mo)
    43  	default:
    44  		v := newAddressableValue(reflect.TypeOf(val))
    45  		v.Set(reflect.ValueOf(val))
    46  		marshal := lookupArshaler(v.Type()).marshal
    47  		if mo.Marshalers != nil {
    48  			marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, v.Type())
    49  		}
    50  		return marshal(enc, v, mo)
    51  	}
    52  }
    53  
    54  // unmarshalValueAny unmarshals a JSON value as a Go any.
    55  // This assumes that there are no special formatting directives
    56  // for any possible nested value.
    57  // Duplicate names must be rejected since this does not implement merging.
    58  func unmarshalValueAny(dec *jsontext.Decoder, uo *jsonopts.Struct) (any, error) {
    59  	switch k := dec.PeekKind(); k {
    60  	case '{':
    61  		return unmarshalObjectAny(dec, uo)
    62  	case '[':
    63  		return unmarshalArrayAny(dec, uo)
    64  	default:
    65  		xd := export.Decoder(dec)
    66  		var flags jsonwire.ValueFlags
    67  		val, err := xd.ReadValue(&flags)
    68  		if err != nil {
    69  			return nil, err
    70  		}
    71  		switch val.Kind() {
    72  		case 'n':
    73  			return nil, nil
    74  		case 'f':
    75  			return false, nil
    76  		case 't':
    77  			return true, nil
    78  		case '"':
    79  			val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim())
    80  			if xd.StringCache == nil {
    81  				xd.StringCache = new(stringCache)
    82  			}
    83  			return makeString(xd.StringCache, val), nil
    84  		case '0':
    85  			if uo.Flags.Get(jsonflags.UnmarshalAnyWithRawNumber) {
    86  				return internal.RawNumberOf(val), nil
    87  			}
    88  			fv, ok := jsonwire.ParseFloat(val, 64)
    89  			if !ok {
    90  				return fv, newUnmarshalErrorAfterWithValue(dec, float64Type, strconv.ErrRange)
    91  			}
    92  			return fv, nil
    93  		default:
    94  			panic("BUG: invalid kind: " + k.String())
    95  		}
    96  	}
    97  }
    98  
    99  // marshalObjectAny marshals a Go map[string]any as a JSON object
   100  // (or as a JSON null if nil and [jsonflags.FormatNilMapAsNull]).
   101  func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.Struct) error {
   102  	// Check for cycles.
   103  	xe := export.Encoder(enc)
   104  	if xe.Tokens.Depth() > startDetectingCyclesAfter {
   105  		v := reflect.ValueOf(obj)
   106  		if err := visitPointer(&xe.SeenPointers, v); err != nil {
   107  			return newMarshalErrorBefore(enc, anyType, err)
   108  		}
   109  		defer leavePointer(&xe.SeenPointers, v)
   110  	}
   111  
   112  	// Handle empty maps.
   113  	if len(obj) == 0 {
   114  		if mo.Flags.Get(jsonflags.FormatNilMapAsNull) && obj == nil {
   115  			return enc.WriteToken(jsontext.Null)
   116  		}
   117  		// Optimize for marshaling an empty map without any preceding whitespace.
   118  		if !mo.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() {
   119  			xe.Buf = append(xe.Tokens.MayAppendDelim(xe.Buf, '{'), "{}"...)
   120  			xe.Tokens.Last.Increment()
   121  			if xe.NeedFlush() {
   122  				return xe.Flush()
   123  			}
   124  			return nil
   125  		}
   126  	}
   127  
   128  	if err := enc.WriteToken(jsontext.BeginObject); err != nil {
   129  		return err
   130  	}
   131  	// A Go map guarantees that each entry has a unique key
   132  	// The only possibility of duplicates is due to invalid UTF-8.
   133  	if !mo.Flags.Get(jsonflags.AllowInvalidUTF8) {
   134  		xe.Tokens.Last.DisableNamespace()
   135  	}
   136  	if !mo.Flags.Get(jsonflags.Deterministic) || len(obj) <= 1 {
   137  		for name, val := range obj {
   138  			if err := enc.WriteToken(jsontext.String(name)); err != nil {
   139  				return err
   140  			}
   141  			if err := marshalValueAny(enc, val, mo); err != nil {
   142  				return err
   143  			}
   144  		}
   145  	} else {
   146  		names := getStrings(len(obj))
   147  		var i int
   148  		for name := range obj {
   149  			(*names)[i] = name
   150  			i++
   151  		}
   152  		names.Sort()
   153  		for _, name := range *names {
   154  			if err := enc.WriteToken(jsontext.String(name)); err != nil {
   155  				return err
   156  			}
   157  			if err := marshalValueAny(enc, obj[name], mo); err != nil {
   158  				return err
   159  			}
   160  		}
   161  		putStrings(names)
   162  	}
   163  	if err := enc.WriteToken(jsontext.EndObject); err != nil {
   164  		return err
   165  	}
   166  	return nil
   167  }
   168  
   169  // unmarshalObjectAny unmarshals a JSON object as a Go map[string]any.
   170  // It panics if not decoding a JSON object.
   171  func unmarshalObjectAny(dec *jsontext.Decoder, uo *jsonopts.Struct) (map[string]any, error) {
   172  	switch tok, err := dec.ReadToken(); {
   173  	case err != nil:
   174  		return nil, err
   175  	case tok.Kind() != '{':
   176  		panic("BUG: invalid kind: " + tok.Kind().String())
   177  	}
   178  	obj := make(map[string]any)
   179  	// A Go map guarantees that each entry has a unique key
   180  	// The only possibility of duplicates is due to invalid UTF-8.
   181  	if !uo.Flags.Get(jsonflags.AllowInvalidUTF8) {
   182  		export.Decoder(dec).Tokens.Last.DisableNamespace()
   183  	}
   184  	var errUnmarshal error
   185  	for dec.PeekKind() != '}' {
   186  		tok, err := dec.ReadToken()
   187  		if err != nil {
   188  			return obj, err
   189  		}
   190  		name := tok.String()
   191  
   192  		// Manually check for duplicate names.
   193  		if _, ok := obj[name]; ok {
   194  			// TODO: Unread the object name.
   195  			name := export.Decoder(dec).PreviousTokenOrValue()
   196  			err := newDuplicateNameError(dec.StackPointer(), nil, dec.InputOffset()-len64(name))
   197  			return obj, err
   198  		}
   199  
   200  		val, err := unmarshalValueAny(dec, uo)
   201  		obj[name] = val
   202  		if err != nil {
   203  			if isFatalError(err, uo.Flags) {
   204  				return obj, err
   205  			}
   206  			errUnmarshal = cmp.Or(err, errUnmarshal)
   207  		}
   208  	}
   209  	if _, err := dec.ReadToken(); err != nil {
   210  		return obj, err
   211  	}
   212  	return obj, errUnmarshal
   213  }
   214  
   215  // marshalArrayAny marshals a Go []any as a JSON array
   216  // (or as a JSON null if nil and [jsonflags.FormatNilSliceAsNull]).
   217  func marshalArrayAny(enc *jsontext.Encoder, arr []any, mo *jsonopts.Struct) error {
   218  	// Check for cycles.
   219  	xe := export.Encoder(enc)
   220  	if xe.Tokens.Depth() > startDetectingCyclesAfter {
   221  		v := reflect.ValueOf(arr)
   222  		if err := visitPointer(&xe.SeenPointers, v); err != nil {
   223  			return newMarshalErrorBefore(enc, sliceAnyType, err)
   224  		}
   225  		defer leavePointer(&xe.SeenPointers, v)
   226  	}
   227  
   228  	// Handle empty slices.
   229  	if len(arr) == 0 {
   230  		if mo.Flags.Get(jsonflags.FormatNilSliceAsNull) && arr == nil {
   231  			return enc.WriteToken(jsontext.Null)
   232  		}
   233  		// Optimize for marshaling an empty slice without any preceding whitespace.
   234  		if !mo.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() {
   235  			xe.Buf = append(xe.Tokens.MayAppendDelim(xe.Buf, '['), "[]"...)
   236  			xe.Tokens.Last.Increment()
   237  			if xe.NeedFlush() {
   238  				return xe.Flush()
   239  			}
   240  			return nil
   241  		}
   242  	}
   243  
   244  	if err := enc.WriteToken(jsontext.BeginArray); err != nil {
   245  		return err
   246  	}
   247  	for _, val := range arr {
   248  		if err := marshalValueAny(enc, val, mo); err != nil {
   249  			return err
   250  		}
   251  	}
   252  	if err := enc.WriteToken(jsontext.EndArray); err != nil {
   253  		return err
   254  	}
   255  	return nil
   256  }
   257  
   258  // unmarshalArrayAny unmarshals a JSON array as a Go []any.
   259  // It panics if not decoding a JSON array.
   260  func unmarshalArrayAny(dec *jsontext.Decoder, uo *jsonopts.Struct) ([]any, error) {
   261  	switch tok, err := dec.ReadToken(); {
   262  	case err != nil:
   263  		return nil, err
   264  	case tok.Kind() != '[':
   265  		panic("BUG: invalid kind: " + tok.Kind().String())
   266  	}
   267  	arr := []any{}
   268  	var errUnmarshal error
   269  	for dec.PeekKind() != ']' {
   270  		val, err := unmarshalValueAny(dec, uo)
   271  		arr = append(arr, val)
   272  		if err != nil {
   273  			if isFatalError(err, uo.Flags) {
   274  				return arr, err
   275  			}
   276  			errUnmarshal = cmp.Or(errUnmarshal, err)
   277  		}
   278  	}
   279  	if _, err := dec.ReadToken(); err != nil {
   280  		return arr, err
   281  	}
   282  	return arr, errUnmarshal
   283  }
   284  

View as plain text