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

View as plain text