github.com/vmware/govmomi@v0.43.0/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 if v.IsZero() { 358 newPtrEncoder(v.Type())(e, v, opts) 359 } else { 360 discriminatorInterfaceEncode(e, v, opts) 361 } 362 default: 363 discriminatorValue := opts.discriminatorValueFn(v.Type()) 364 if discriminatorValue == "" { 365 e.reflectValue(v, opts) 366 return 367 } 368 e.WriteString(`{"`) 369 e.WriteString(opts.discriminatorTypeFieldName) 370 e.WriteString(`":"`) 371 e.WriteString(discriminatorValue) 372 e.WriteString(`","`) 373 e.WriteString(opts.discriminatorValueFieldName) 374 e.WriteString(`":`) 375 e.reflectValue(v, opts) 376 e.WriteByte('}') 377 } 378 } 379 380 func discriminatorMapEncode(e *encodeState, v reflect.Value, opts encOpts) { 381 if !e.discriminatorEncodeTypeName && !opts.discriminatorEncodeMode.all() { 382 return 383 } 384 discriminatorValue := opts.discriminatorValueFn(v.Type()) 385 if discriminatorValue == "" { 386 return 387 } 388 e.WriteByte('"') 389 e.WriteString(opts.discriminatorTypeFieldName) 390 e.WriteString(`":"`) 391 e.WriteString(discriminatorValue) 392 e.WriteByte('"') 393 if v.Len() > 0 { 394 e.WriteByte(',') 395 } 396 e.discriminatorEncodeTypeName = false 397 } 398 399 func discriminatorStructEncode(e *encodeState, v reflect.Value, opts encOpts) byte { 400 if !e.discriminatorEncodeTypeName && !opts.discriminatorEncodeMode.all() { 401 return '{' 402 } 403 discriminatorValue := opts.discriminatorValueFn(v.Type()) 404 if discriminatorValue == "" { 405 return '{' 406 } 407 e.WriteString(`{"`) 408 e.WriteString(opts.discriminatorTypeFieldName) 409 e.WriteString(`":"`) 410 e.WriteString(discriminatorValue) 411 e.WriteByte('"') 412 e.discriminatorEncodeTypeName = false 413 return ',' 414 } 415 416 var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() 417 418 // Discriminator is nested in map and struct unless they implement Unmarshaler. 419 func useNestedDiscriminator(t reflect.Type) bool { 420 if t.Implements(unmarshalerType) || reflect.PtrTo(t).Implements(unmarshalerType) { 421 return false 422 } 423 kind := t.Kind() 424 if kind == reflect.Struct || kind == reflect.Map { 425 return true 426 } 427 return false 428 } 429 430 var discriminatorTypeRegistry = map[string]reflect.Type{ 431 "uint": reflect.TypeOf(uint(0)), 432 "uint8": reflect.TypeOf(uint8(0)), 433 "uint16": reflect.TypeOf(uint16(0)), 434 "uint32": reflect.TypeOf(uint32(0)), 435 "uint64": reflect.TypeOf(uint64(0)), 436 "uintptr": reflect.TypeOf(uintptr(0)), 437 "int": reflect.TypeOf(int(0)), 438 "int8": reflect.TypeOf(int8(0)), 439 "int16": reflect.TypeOf(int16(0)), 440 "int32": reflect.TypeOf(int32(0)), 441 "int64": reflect.TypeOf(int64(0)), 442 "float32": reflect.TypeOf(float32(0)), 443 "float64": reflect.TypeOf(float64(0)), 444 "bool": reflect.TypeOf(true), 445 "string": reflect.TypeOf(""), 446 "any": reflect.TypeOf((*interface{})(nil)).Elem(), 447 "interface{}": reflect.TypeOf((*interface{})(nil)).Elem(), 448 "interface {}": reflect.TypeOf((*interface{})(nil)).Elem(), 449 450 // Not supported, but here to prevent the decoder from panicing 451 // if encountered. 452 "complex64": reflect.TypeOf(complex64(0)), 453 "complex128": reflect.TypeOf(complex128(0)), 454 } 455 456 // discriminatorPointerTypeCache caches the pointer type for another type. 457 // For example, a key that was the int type would have a value that is the 458 // *int type. 459 var discriminatorPointerTypeCache sync.Map // map[reflect.Type]reflect.Type 460 461 // cachedPointerType returns the pointer type for another and avoids repeated 462 // work by using a cache. 463 func cachedPointerType(t reflect.Type) reflect.Type { 464 if value, ok := discriminatorPointerTypeCache.Load(t); ok { 465 return value.(reflect.Type) 466 } 467 pt := reflect.New(t).Type() 468 value, _ := discriminatorPointerTypeCache.LoadOrStore(t, pt) 469 return value.(reflect.Type) 470 } 471 472 var ( 473 mapPatt = regexp.MustCompile(`^\*?map\[([^\]]+)\](.+)$`) 474 arrayPatt = regexp.MustCompile(`^\*?\[(\d+)\](.+)$`) 475 slicePatt = regexp.MustCompile(`^\*?\[\](.+)$`) 476 ) 477 478 // discriminatorParseTypeName returns a reflect.Type for the given type name. 479 func discriminatorParseTypeName( 480 typeName string, 481 typeFn DiscriminatorToTypeFunc) (reflect.Type, error) { 482 483 // Check to see if the type is an array, map, or slice. 484 var ( 485 aln = -1 // array length 486 etn string // map or slice element type name 487 ktn string // map key type name 488 ) 489 if m := arrayPatt.FindStringSubmatch(typeName); len(m) > 0 { 490 i, err := strconv.Atoi(m[1]) 491 if err != nil { 492 return nil, err 493 } 494 aln = i 495 etn = m[2] 496 } else if m := slicePatt.FindStringSubmatch(typeName); len(m) > 0 { 497 etn = m[1] 498 } else if m := mapPatt.FindStringSubmatch(typeName); len(m) > 0 { 499 ktn = m[1] 500 etn = m[2] 501 } 502 503 // indirectTypeName checks to see if the type name begins with a 504 // "*" characters. If it does, then the type name sans the "*" 505 // character is returned along with a true value indicating the 506 // type is a pointer. Otherwise the original type name is returned 507 // along with a false value. 508 indirectTypeName := func(tn string) (string, bool) { 509 if len(tn) > 1 && tn[0] == '*' { 510 return tn[1:], true 511 } 512 return tn, false 513 } 514 515 lookupType := func(tn string) (reflect.Type, bool) { 516 // Get the actual type name and a flag indicating whether the 517 // type is a pointer. 518 n, p := indirectTypeName(tn) 519 520 var t reflect.Type 521 ok := false 522 // look up the type in the external registry to allow name override. 523 if typeFn != nil { 524 t, ok = typeFn(n) 525 } 526 if !ok { 527 // Use the built-in registry if the external registry fails 528 if t, ok = discriminatorTypeRegistry[n]; !ok { 529 return nil, false 530 } 531 } 532 // If the type was a pointer then get the type's pointer type. 533 if p { 534 t = cachedPointerType(t) 535 } 536 return t, true 537 } 538 539 var t reflect.Type 540 541 if ktn == "" && etn != "" { 542 et, ok := lookupType(etn) 543 if !ok { 544 return nil, fmt.Errorf("json: invalid array/slice element type: %s", etn) 545 } 546 if aln > -1 { 547 // Array 548 t = reflect.ArrayOf(aln, et) 549 } else { 550 // Slice 551 t = reflect.SliceOf(et) 552 } 553 } else if ktn != "" && etn != "" { 554 // Map 555 kt, ok := lookupType(ktn) 556 if !ok { 557 return nil, fmt.Errorf("json: invalid map key type: %s", ktn) 558 } 559 et, ok := lookupType(etn) 560 if !ok { 561 return nil, fmt.Errorf("json: invalid map element type: %s", etn) 562 } 563 t = reflect.MapOf(kt, et) 564 } else { 565 var ok bool 566 if t, ok = lookupType(typeName); !ok { 567 return nil, fmt.Errorf("json: invalid discriminator type: %s", typeName) 568 } 569 } 570 571 return t, nil 572 }