github.com/vmware/govmomi@v0.37.1/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 }