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

View as plain text