github.com/vmware/govmomi@v0.37.2/vim25/json/discriminator.go (about)

     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  package json
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"regexp"
    11  	"strconv"
    12  	"sync"
    13  )
    14  
    15  // DiscriminatorToTypeFunc is used to get a reflect.Type from its
    16  // discriminator.
    17  type DiscriminatorToTypeFunc func(discriminator string) (reflect.Type, bool)
    18  
    19  // TypeToDiscriminatorFunc is used to get a discriminator string from a
    20  // reflect.Type. Empty return value suppresses discriminator rendering.
    21  type TypeToDiscriminatorFunc func(reflect.Type) (discriminator string)
    22  
    23  // DefaultDiscriminatorFunc is shorthand for the ShortName func and is used when
    24  // no other discriminator func is set explicitly
    25  var DefaultDiscriminatorFunc = ShortName
    26  
    27  // ShortName returns the type name in golang without the package name
    28  func ShortName(t reflect.Type) (discriminator string) {
    29  	tn := t.Name()
    30  	if tn == "" {
    31  		return t.String()
    32  	}
    33  	return tn
    34  }
    35  
    36  // FullName return the name of the type prefixed with the package name as
    37  // appropriate
    38  func FullName(t reflect.Type) (discriminator string) {
    39  	tn := t.Name()
    40  	if tn == "" {
    41  		return t.String()
    42  	}
    43  	if pp := t.PkgPath(); pp != "" {
    44  		return fmt.Sprintf("%s.%s", pp, tn)
    45  	}
    46  	return tn
    47  }
    48  
    49  // DiscriminatorEncodeMode is a mask that describes the different encode
    50  // options.
    51  type DiscriminatorEncodeMode uint8
    52  
    53  const (
    54  	// DiscriminatorEncodeTypeNameRootValue causes the type name to be encoded
    55  	// for the root value.
    56  	DiscriminatorEncodeTypeNameRootValue DiscriminatorEncodeMode = 1 << iota
    57  
    58  	// DiscriminatorEncodeTypeNameAllObjects causes the type name to be encoded
    59  	// for all struct and map values. Please note this specifically does not
    60  	// apply to the root value.
    61  	DiscriminatorEncodeTypeNameAllObjects
    62  
    63  	// DiscriminatorEncodeTypeNameIfRequired is the default behavior when
    64  	// the discriminator is set, and the type name is only encoded if required.
    65  	DiscriminatorEncodeTypeNameIfRequired DiscriminatorEncodeMode = 0
    66  )
    67  
    68  func (m DiscriminatorEncodeMode) root() bool {
    69  	return m&DiscriminatorEncodeTypeNameRootValue > 0
    70  }
    71  
    72  func (m DiscriminatorEncodeMode) all() bool {
    73  	return m&DiscriminatorEncodeTypeNameAllObjects > 0
    74  }
    75  
    76  func (d *decodeState) isDiscriminatorSet() bool {
    77  	return d.discriminatorTypeFieldName != "" &&
    78  		d.discriminatorValueFieldName != ""
    79  }
    80  
    81  // discriminatorOpType describes the current operation related to
    82  // discriminators when reading a JSON object's fields.
    83  type discriminatorOpType uint8
    84  
    85  const (
    86  	// discriminatorOpTypeNameField indicates the discriminator type name
    87  	// field was discovered.
    88  	discriminatorOpTypeNameField = iota + 1
    89  
    90  	// discriminatorOpValueField indicates the discriminator value field
    91  	// was discovered.
    92  	discriminatorOpValueField
    93  )
    94  
    95  func (d *decodeState) discriminatorGetValue() (reflect.Value, error) {
    96  	// Record the current offset so we know where the data starts.
    97  	offset := d.readIndex()
    98  
    99  	// Create a temporary decodeState used to inspect the current object
   100  	// and determine its discriminator type and decode its value.
   101  	dd := &decodeState{
   102  		disallowUnknownFields:       d.disallowUnknownFields,
   103  		useNumber:                   d.useNumber,
   104  		discriminatorToTypeFn:       d.discriminatorToTypeFn,
   105  		discriminatorTypeFieldName:  d.discriminatorTypeFieldName,
   106  		discriminatorValueFieldName: d.discriminatorValueFieldName,
   107  	}
   108  	dd.init(append([]byte{}, d.data[offset:]...))
   109  	defer freeScanner(&dd.scan)
   110  	dd.scan.reset()
   111  
   112  	var (
   113  		t        reflect.Type // the instance of the type
   114  		valueOff = -1         // the offset of a possible discriminator value
   115  	)
   116  
   117  	dd.scanWhile(scanSkipSpace)
   118  	if dd.opcode != scanBeginObject {
   119  		panic(phasePanicMsg)
   120  	}
   121  
   122  	for {
   123  		dd.scanWhile(scanSkipSpace)
   124  		if dd.opcode == scanEndObject {
   125  			// closing } - can only happen on first iteration.
   126  			break
   127  		}
   128  		if dd.opcode != scanBeginLiteral {
   129  			panic(phasePanicMsg)
   130  		}
   131  
   132  		// Read key.
   133  		start := dd.readIndex()
   134  		dd.rescanLiteral()
   135  		item := dd.data[start:dd.readIndex()]
   136  		key, ok := unquote(item)
   137  		if !ok {
   138  			panic(phasePanicMsg)
   139  		}
   140  
   141  		// Check to see if the key is related to the discriminator.
   142  		var discriminatorOp discriminatorOpType
   143  		switch key {
   144  		case d.discriminatorTypeFieldName:
   145  			discriminatorOp = discriminatorOpTypeNameField
   146  		case d.discriminatorValueFieldName:
   147  			discriminatorOp = discriminatorOpValueField
   148  		}
   149  
   150  		// Read : before value.
   151  		if dd.opcode == scanSkipSpace {
   152  			dd.scanWhile(scanSkipSpace)
   153  		}
   154  
   155  		if dd.opcode != scanObjectKey {
   156  			panic(phasePanicMsg)
   157  		}
   158  		dd.scanWhile(scanSkipSpace)
   159  
   160  		// Read value.
   161  		valOff := dd.readIndex()
   162  		val := dd.valueInterface()
   163  
   164  		switch discriminatorOp {
   165  		case discriminatorOpTypeNameField:
   166  			tn, ok := val.(string)
   167  			if !ok {
   168  				return reflect.Value{}, fmt.Errorf(
   169  					"json: discriminator type at offset %d is not string",
   170  					offset+valOff)
   171  			}
   172  			if tn == "" {
   173  				return reflect.Value{}, fmt.Errorf(
   174  					"json: discriminator type at offset %d is empty",
   175  					offset+valOff)
   176  			}
   177  
   178  			// Parse the type name into a type instance.
   179  			ti, err := discriminatorParseTypeName(tn, d.discriminatorToTypeFn)
   180  			if err != nil {
   181  				return reflect.Value{}, err
   182  			}
   183  
   184  			// Assign the type instance to the outer variable, t.
   185  			t = ti
   186  
   187  			// Primitive types and types with Unmarshaler are wrapped in a
   188  			// structure with type and value fields. Structures and Maps not
   189  			// implementing Unmarshaler use discriminator embedded within their
   190  			// content.
   191  			if useNestedDiscriminator(t) {
   192  				// If the type is a map or a struct not implementing Unmarshaler
   193  				// then it is not necessary to continue walking over the current
   194  				// JSON object since it will be completely re-scanned to decode
   195  				// its value into the discovered type.
   196  				dd.opcode = scanEndObject
   197  			} else {
   198  				// Otherwise if the value offset has been discovered then it is
   199  				// safe to stop walking over the current JSON object as well.
   200  				if valueOff > -1 {
   201  					dd.opcode = scanEndObject
   202  				}
   203  			}
   204  		case discriminatorOpValueField:
   205  			valueOff = valOff
   206  
   207  			// If the type has been discovered then it is safe to stop walking
   208  			// over the current JSON object.
   209  			if t != nil {
   210  				dd.opcode = scanEndObject
   211  			}
   212  		}
   213  
   214  		// Next token must be , or }.
   215  		if dd.opcode == scanSkipSpace {
   216  			dd.scanWhile(scanSkipSpace)
   217  		}
   218  		if dd.opcode == scanEndObject {
   219  			break
   220  		}
   221  		if dd.opcode != scanObjectValue {
   222  			panic(phasePanicMsg)
   223  		}
   224  	}
   225  
   226  	// If there is not a type discriminator then return early.
   227  	if t == nil {
   228  		return reflect.Value{}, fmt.Errorf("json: missing discriminator")
   229  	}
   230  
   231  	// Instantiate a new instance of the discriminated type.
   232  	var v reflect.Value
   233  	switch t.Kind() {
   234  	case reflect.Slice:
   235  		// MakeSlice returns a value that is not addressable.
   236  		// Instead, use MakeSlice to get the type, then use
   237  		// reflect.New to create an addressable value.
   238  		v = reflect.New(reflect.MakeSlice(t, 0, 0).Type()).Elem()
   239  	case reflect.Map:
   240  		// MakeMap returns a value that is not addressable.
   241  		// Instead, use MakeMap to get the type, then use
   242  		// reflect.New to create an addressable value.
   243  		v = reflect.New(reflect.MakeMap(t).Type()).Elem()
   244  	case reflect.Complex64, reflect.Complex128:
   245  		return reflect.Value{}, fmt.Errorf("json: unsupported discriminator type: %s", t.Kind())
   246  	default:
   247  		v = reflect.New(t)
   248  	}
   249  
   250  	// Reset the decode state to prepare for decoding the data.
   251  	dd.scan.reset()
   252  
   253  	if useNestedDiscriminator(t) {
   254  		// Set the offset to zero since the entire object will be decoded
   255  		// into v.
   256  		dd.off = 0
   257  	} else {
   258  		// Set the offset to what it was before the discriminator value was
   259  		// read so only the value field is decoded into v.
   260  		dd.off = valueOff
   261  	}
   262  	// This will initialize the correct scan step and op code.
   263  	dd.scanWhile(scanSkipSpace)
   264  
   265  	// Decode the data into the value.
   266  	if err := dd.value(v); err != nil {
   267  		return reflect.Value{}, err
   268  	}
   269  
   270  	// Check the saved error as well since the decoder.value function does not
   271  	// always return an error. If the reflected value is still zero, then it is
   272  	// likely the decoder was unable to decode the value.
   273  	if err := dd.savedError; err != nil {
   274  		switch v.Kind() {
   275  		case reflect.Ptr, reflect.Interface:
   276  			v = v.Elem()
   277  		}
   278  		if v.IsZero() {
   279  			return reflect.Value{}, err
   280  		}
   281  	}
   282  
   283  	return v, nil
   284  }
   285  
   286  func (d *decodeState) discriminatorInterfaceDecode(t reflect.Type, v reflect.Value) error {
   287  
   288  	defer func() {
   289  		// Advance the decode state, throwing away the value.
   290  		_ = d.objectInterface()
   291  	}()
   292  
   293  	dv, err := d.discriminatorGetValue()
   294  	if err != nil {
   295  		return err
   296  	}
   297  
   298  	switch dv.Kind() {
   299  	case reflect.Map, reflect.Slice:
   300  		if dv.Type().AssignableTo(t) {
   301  			v.Set(dv)
   302  			return nil
   303  		}
   304  		if pdv := dv.Addr(); pdv.Type().AssignableTo(t) {
   305  			v.Set(pdv)
   306  			return nil
   307  		}
   308  	case reflect.Ptr:
   309  		if dve := dv.Elem(); dve.Type().AssignableTo(t) {
   310  			v.Set(dve)
   311  			return nil
   312  		}
   313  		if dv.Type().AssignableTo(t) {
   314  			v.Set(dv)
   315  			return nil
   316  		}
   317  	}
   318  
   319  	return fmt.Errorf("json: unsupported discriminator kind: %s", dv.Kind())
   320  }
   321  
   322  func (o encOpts) isDiscriminatorSet() bool {
   323  	return o.discriminatorTypeFieldName != "" &&
   324  		o.discriminatorValueFieldName != ""
   325  }
   326  
   327  func discriminatorInterfaceEncode(e *encodeState, v reflect.Value, opts encOpts) {
   328  	v = v.Elem()
   329  
   330  	if v.Type().Implements(marshalerType) {
   331  		discriminatorValue := opts.discriminatorValueFn(v.Type())
   332  		if discriminatorValue == "" {
   333  			marshalerEncoder(e, v, opts)
   334  		}
   335  		e.WriteString(`{"`)
   336  		e.WriteString(opts.discriminatorTypeFieldName)
   337  		e.WriteString(`":"`)
   338  		e.WriteString(discriminatorValue)
   339  		e.WriteString(`","`)
   340  		e.WriteString(opts.discriminatorValueFieldName)
   341  		e.WriteString(`":`)
   342  		marshalerEncoder(e, v, opts)
   343  		e.WriteByte('}')
   344  		return
   345  	}
   346  
   347  	switch v.Kind() {
   348  	case reflect.Chan, reflect.Func, reflect.Invalid:
   349  		e.error(&UnsupportedValueError{v, fmt.Sprintf("invalid kind: %s", v.Kind())})
   350  	case reflect.Map:
   351  		e.discriminatorEncodeTypeName = true
   352  		newMapEncoder(v.Type())(e, v, opts)
   353  	case reflect.Struct:
   354  		e.discriminatorEncodeTypeName = true
   355  		newStructEncoder(v.Type())(e, v, opts)
   356  	case reflect.Ptr:
   357  		discriminatorInterfaceEncode(e, v, opts)
   358  	default:
   359  		discriminatorValue := opts.discriminatorValueFn(v.Type())
   360  		if discriminatorValue == "" {
   361  			e.reflectValue(v, opts)
   362  			return
   363  		}
   364  		e.WriteString(`{"`)
   365  		e.WriteString(opts.discriminatorTypeFieldName)
   366  		e.WriteString(`":"`)
   367  		e.WriteString(discriminatorValue)
   368  		e.WriteString(`","`)
   369  		e.WriteString(opts.discriminatorValueFieldName)
   370  		e.WriteString(`":`)
   371  		e.reflectValue(v, opts)
   372  		e.WriteByte('}')
   373  	}
   374  }
   375  
   376  func discriminatorMapEncode(e *encodeState, v reflect.Value, opts encOpts) {
   377  	if !e.discriminatorEncodeTypeName && !opts.discriminatorEncodeMode.all() {
   378  		return
   379  	}
   380  	discriminatorValue := opts.discriminatorValueFn(v.Type())
   381  	if discriminatorValue == "" {
   382  		return
   383  	}
   384  	e.WriteByte('"')
   385  	e.WriteString(opts.discriminatorTypeFieldName)
   386  	e.WriteString(`":"`)
   387  	e.WriteString(discriminatorValue)
   388  	e.WriteByte('"')
   389  	if v.Len() > 0 {
   390  		e.WriteByte(',')
   391  	}
   392  	e.discriminatorEncodeTypeName = false
   393  }
   394  
   395  func discriminatorStructEncode(e *encodeState, v reflect.Value, opts encOpts) byte {
   396  	if !e.discriminatorEncodeTypeName && !opts.discriminatorEncodeMode.all() {
   397  		return '{'
   398  	}
   399  	discriminatorValue := opts.discriminatorValueFn(v.Type())
   400  	if discriminatorValue == "" {
   401  		return '{'
   402  	}
   403  	e.WriteString(`{"`)
   404  	e.WriteString(opts.discriminatorTypeFieldName)
   405  	e.WriteString(`":"`)
   406  	e.WriteString(discriminatorValue)
   407  	e.WriteByte('"')
   408  	e.discriminatorEncodeTypeName = false
   409  	return ','
   410  }
   411  
   412  var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
   413  
   414  // Discriminator is nested in map and struct unless they implement Unmarshaler.
   415  func useNestedDiscriminator(t reflect.Type) bool {
   416  	if t.Implements(unmarshalerType) || reflect.PtrTo(t).Implements(unmarshalerType) {
   417  		return false
   418  	}
   419  	kind := t.Kind()
   420  	if kind == reflect.Struct || kind == reflect.Map {
   421  		return true
   422  	}
   423  	return false
   424  }
   425  
   426  var discriminatorTypeRegistry = map[string]reflect.Type{
   427  	"uint":         reflect.TypeOf(uint(0)),
   428  	"uint8":        reflect.TypeOf(uint8(0)),
   429  	"uint16":       reflect.TypeOf(uint16(0)),
   430  	"uint32":       reflect.TypeOf(uint32(0)),
   431  	"uint64":       reflect.TypeOf(uint64(0)),
   432  	"uintptr":      reflect.TypeOf(uintptr(0)),
   433  	"int":          reflect.TypeOf(int(0)),
   434  	"int8":         reflect.TypeOf(int8(0)),
   435  	"int16":        reflect.TypeOf(int16(0)),
   436  	"int32":        reflect.TypeOf(int32(0)),
   437  	"int64":        reflect.TypeOf(int64(0)),
   438  	"float32":      reflect.TypeOf(float32(0)),
   439  	"float64":      reflect.TypeOf(float64(0)),
   440  	"bool":         reflect.TypeOf(true),
   441  	"string":       reflect.TypeOf(""),
   442  	"any":          reflect.TypeOf((*interface{})(nil)).Elem(),
   443  	"interface{}":  reflect.TypeOf((*interface{})(nil)).Elem(),
   444  	"interface {}": reflect.TypeOf((*interface{})(nil)).Elem(),
   445  
   446  	// Not supported, but here to prevent the decoder from panicing
   447  	// if encountered.
   448  	"complex64":  reflect.TypeOf(complex64(0)),
   449  	"complex128": reflect.TypeOf(complex128(0)),
   450  }
   451  
   452  // discriminatorPointerTypeCache caches the pointer type for another type.
   453  // For example, a key that was the int type would have a value that is the
   454  // *int type.
   455  var discriminatorPointerTypeCache sync.Map // map[reflect.Type]reflect.Type
   456  
   457  // cachedPointerType returns the pointer type for another and avoids repeated
   458  // work by using a cache.
   459  func cachedPointerType(t reflect.Type) reflect.Type {
   460  	if value, ok := discriminatorPointerTypeCache.Load(t); ok {
   461  		return value.(reflect.Type)
   462  	}
   463  	pt := reflect.New(t).Type()
   464  	value, _ := discriminatorPointerTypeCache.LoadOrStore(t, pt)
   465  	return value.(reflect.Type)
   466  }
   467  
   468  var (
   469  	mapPatt   = regexp.MustCompile(`^\*?map\[([^\]]+)\](.+)$`)
   470  	arrayPatt = regexp.MustCompile(`^\*?\[(\d+)\](.+)$`)
   471  	slicePatt = regexp.MustCompile(`^\*?\[\](.+)$`)
   472  )
   473  
   474  // discriminatorParseTypeName returns a reflect.Type for the given type name.
   475  func discriminatorParseTypeName(
   476  	typeName string,
   477  	typeFn DiscriminatorToTypeFunc) (reflect.Type, error) {
   478  
   479  	// Check to see if the type is an array, map, or slice.
   480  	var (
   481  		aln = -1   // array length
   482  		etn string // map or slice element type name
   483  		ktn string // map key type name
   484  	)
   485  	if m := arrayPatt.FindStringSubmatch(typeName); len(m) > 0 {
   486  		i, err := strconv.Atoi(m[1])
   487  		if err != nil {
   488  			return nil, err
   489  		}
   490  		aln = i
   491  		etn = m[2]
   492  	} else if m := slicePatt.FindStringSubmatch(typeName); len(m) > 0 {
   493  		etn = m[1]
   494  	} else if m := mapPatt.FindStringSubmatch(typeName); len(m) > 0 {
   495  		ktn = m[1]
   496  		etn = m[2]
   497  	}
   498  
   499  	// indirectTypeName checks to see if the type name begins with a
   500  	// "*" characters. If it does, then the type name sans the "*"
   501  	// character is returned along with a true value indicating the
   502  	// type is a pointer. Otherwise the original type name is returned
   503  	// along with a false value.
   504  	indirectTypeName := func(tn string) (string, bool) {
   505  		if len(tn) > 1 && tn[0] == '*' {
   506  			return tn[1:], true
   507  		}
   508  		return tn, false
   509  	}
   510  
   511  	lookupType := func(tn string) (reflect.Type, bool) {
   512  		// Get the actual type name and a flag indicating whether the
   513  		// type is a pointer.
   514  		n, p := indirectTypeName(tn)
   515  
   516  		var t reflect.Type
   517  		ok := false
   518  		// look up the type in the external registry to allow name override.
   519  		if typeFn != nil {
   520  			t, ok = typeFn(n)
   521  		}
   522  		if !ok {
   523  			// Use the built-in registry if the external registry fails
   524  			if t, ok = discriminatorTypeRegistry[n]; !ok {
   525  				return nil, false
   526  			}
   527  		}
   528  		// If the type was a pointer then get the type's pointer type.
   529  		if p {
   530  			t = cachedPointerType(t)
   531  		}
   532  		return t, true
   533  	}
   534  
   535  	var t reflect.Type
   536  
   537  	if ktn == "" && etn != "" {
   538  		et, ok := lookupType(etn)
   539  		if !ok {
   540  			return nil, fmt.Errorf("json: invalid array/slice element type: %s", etn)
   541  		}
   542  		if aln > -1 {
   543  			// Array
   544  			t = reflect.ArrayOf(aln, et)
   545  		} else {
   546  			// Slice
   547  			t = reflect.SliceOf(et)
   548  		}
   549  	} else if ktn != "" && etn != "" {
   550  		// Map
   551  		kt, ok := lookupType(ktn)
   552  		if !ok {
   553  			return nil, fmt.Errorf("json: invalid map key type: %s", ktn)
   554  		}
   555  		et, ok := lookupType(etn)
   556  		if !ok {
   557  			return nil, fmt.Errorf("json: invalid map element type: %s", etn)
   558  		}
   559  		t = reflect.MapOf(kt, et)
   560  	} else {
   561  		var ok bool
   562  		if t, ok = lookupType(typeName); !ok {
   563  			return nil, fmt.Errorf("json: invalid discriminator type: %s", typeName)
   564  		}
   565  	}
   566  
   567  	return t, nil
   568  }