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

View as plain text