1/* 2Copyright 2017 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package runtime 18 19import ( 20 encodingjson "encoding/json" 21 "fmt" 22 "math" 23 "os" 24 "reflect" 25 "strconv" 26 "strings" 27 "sync" 28 "sync/atomic" 29 "time" 30 31 "k8s.io/apimachinery/pkg/conversion" 32 "k8s.io/apimachinery/pkg/util/json" 33 utilruntime "k8s.io/apimachinery/pkg/util/runtime" 34 "sigs.k8s.io/structured-merge-diff/v4/value" 35 36 "k8s.io/klog/v2" 37) 38 39// UnstructuredConverter is an interface for converting between interface{} 40// and map[string]interface representation. 41type UnstructuredConverter interface { 42 ToUnstructured(obj interface{}) (map[string]interface{}, error) 43 FromUnstructured(u map[string]interface{}, obj interface{}) error 44} 45 46type structField struct { 47 structType reflect.Type 48 field int 49} 50 51type fieldInfo struct { 52 name string 53 nameValue reflect.Value 54 omitempty bool 55} 56 57type fieldsCacheMap map[structField]*fieldInfo 58 59type fieldsCache struct { 60 sync.Mutex 61 value atomic.Value 62} 63 64func newFieldsCache() *fieldsCache { 65 cache := &fieldsCache{} 66 cache.value.Store(make(fieldsCacheMap)) 67 return cache 68} 69 70var ( 71 mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{}) 72 stringType = reflect.TypeOf(string("")) 73 fieldCache = newFieldsCache() 74 75 // DefaultUnstructuredConverter performs unstructured to Go typed object conversions. 76 DefaultUnstructuredConverter = &unstructuredConverter{ 77 mismatchDetection: parseBool(os.Getenv("KUBE_PATCH_CONVERSION_DETECTOR")), 78 comparison: conversion.EqualitiesOrDie( 79 func(a, b time.Time) bool { 80 return a.UTC() == b.UTC() 81 }, 82 ), 83 } 84) 85 86func parseBool(key string) bool { 87 if len(key) == 0 { 88 return false 89 } 90 value, err := strconv.ParseBool(key) 91 if err != nil { 92 utilruntime.HandleError(fmt.Errorf("couldn't parse '%s' as bool for unstructured mismatch detection", key)) 93 } 94 return value 95} 96 97// unstructuredConverter knows how to convert between interface{} and 98// Unstructured in both ways. 99type unstructuredConverter struct { 100 // If true, we will be additionally running conversion via json 101 // to ensure that the result is true. 102 // This is supposed to be set only in tests. 103 mismatchDetection bool 104 // comparison is the default test logic used to compare 105 comparison conversion.Equalities 106} 107 108// NewTestUnstructuredConverter creates an UnstructuredConverter that accepts JSON typed maps and translates them 109// to Go types via reflection. It performs mismatch detection automatically and is intended for use by external 110// test tools. Use DefaultUnstructuredConverter if you do not explicitly need mismatch detection. 111func NewTestUnstructuredConverter(comparison conversion.Equalities) UnstructuredConverter { 112 return &unstructuredConverter{ 113 mismatchDetection: true, 114 comparison: comparison, 115 } 116} 117 118// FromUnstructured converts an object from map[string]interface{} representation into a concrete type. 119// It uses encoding/json/Unmarshaler if object implements it or reflection if not. 120func (c *unstructuredConverter) FromUnstructured(u map[string]interface{}, obj interface{}) error { 121 t := reflect.TypeOf(obj) 122 value := reflect.ValueOf(obj) 123 if t.Kind() != reflect.Ptr || value.IsNil() { 124 return fmt.Errorf("FromUnstructured requires a non-nil pointer to an object, got %v", t) 125 } 126 err := fromUnstructured(reflect.ValueOf(u), value.Elem()) 127 if c.mismatchDetection { 128 newObj := reflect.New(t.Elem()).Interface() 129 newErr := fromUnstructuredViaJSON(u, newObj) 130 if (err != nil) != (newErr != nil) { 131 klog.Fatalf("FromUnstructured unexpected error for %v: error: %v", u, err) 132 } 133 if err == nil && !c.comparison.DeepEqual(obj, newObj) { 134 klog.Fatalf("FromUnstructured mismatch\nobj1: %#v\nobj2: %#v", obj, newObj) 135 } 136 } 137 return err 138} 139 140func fromUnstructuredViaJSON(u map[string]interface{}, obj interface{}) error { 141 data, err := json.Marshal(u) 142 if err != nil { 143 return err 144 } 145 return json.Unmarshal(data, obj) 146} 147 148func fromUnstructured(sv, dv reflect.Value) error { 149 sv = unwrapInterface(sv) 150 if !sv.IsValid() { 151 dv.Set(reflect.Zero(dv.Type())) 152 return nil 153 } 154 st, dt := sv.Type(), dv.Type() 155 156 switch dt.Kind() { 157 case reflect.Map, reflect.Slice, reflect.Ptr, reflect.Struct, reflect.Interface: 158 // Those require non-trivial conversion. 159 default: 160 // This should handle all simple types. 161 if st.AssignableTo(dt) { 162 dv.Set(sv) 163 return nil 164 } 165 // We cannot simply use "ConvertibleTo", as JSON doesn't support conversions 166 // between those four groups: bools, integers, floats and string. We need to 167 // do the same. 168 if st.ConvertibleTo(dt) { 169 switch st.Kind() { 170 case reflect.String: 171 switch dt.Kind() { 172 case reflect.String: 173 dv.Set(sv.Convert(dt)) 174 return nil 175 } 176 case reflect.Bool: 177 switch dt.Kind() { 178 case reflect.Bool: 179 dv.Set(sv.Convert(dt)) 180 return nil 181 } 182 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 183 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 184 switch dt.Kind() { 185 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 186 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 187 dv.Set(sv.Convert(dt)) 188 return nil 189 case reflect.Float32, reflect.Float64: 190 dv.Set(sv.Convert(dt)) 191 return nil 192 } 193 case reflect.Float32, reflect.Float64: 194 switch dt.Kind() { 195 case reflect.Float32, reflect.Float64: 196 dv.Set(sv.Convert(dt)) 197 return nil 198 } 199 if sv.Float() == math.Trunc(sv.Float()) { 200 dv.Set(sv.Convert(dt)) 201 return nil 202 } 203 } 204 return fmt.Errorf("cannot convert %s to %s", st.String(), dt.String()) 205 } 206 } 207 208 // Check if the object has a custom JSON marshaller/unmarshaller. 209 entry := value.TypeReflectEntryOf(dv.Type()) 210 if entry.CanConvertFromUnstructured() { 211 return entry.FromUnstructured(sv, dv) 212 } 213 214 switch dt.Kind() { 215 case reflect.Map: 216 return mapFromUnstructured(sv, dv) 217 case reflect.Slice: 218 return sliceFromUnstructured(sv, dv) 219 case reflect.Ptr: 220 return pointerFromUnstructured(sv, dv) 221 case reflect.Struct: 222 return structFromUnstructured(sv, dv) 223 case reflect.Interface: 224 return interfaceFromUnstructured(sv, dv) 225 default: 226 return fmt.Errorf("unrecognized type: %v", dt.Kind()) 227 } 228} 229 230func fieldInfoFromField(structType reflect.Type, field int) *fieldInfo { 231 fieldCacheMap := fieldCache.value.Load().(fieldsCacheMap) 232 if info, ok := fieldCacheMap[structField{structType, field}]; ok { 233 return info 234 } 235 236 // Cache miss - we need to compute the field name. 237 info := &fieldInfo{} 238 typeField := structType.Field(field) 239 jsonTag := typeField.Tag.Get("json") 240 if len(jsonTag) == 0 { 241 // Make the first character lowercase. 242 if typeField.Name == "" { 243 info.name = typeField.Name 244 } else { 245 info.name = strings.ToLower(typeField.Name[:1]) + typeField.Name[1:] 246 } 247 } else { 248 items := strings.Split(jsonTag, ",") 249 info.name = items[0] 250 for i := range items { 251 if items[i] == "omitempty" { 252 info.omitempty = true 253 break 254 } 255 } 256 } 257 info.nameValue = reflect.ValueOf(info.name) 258 259 fieldCache.Lock() 260 defer fieldCache.Unlock() 261 fieldCacheMap = fieldCache.value.Load().(fieldsCacheMap) 262 newFieldCacheMap := make(fieldsCacheMap) 263 for k, v := range fieldCacheMap { 264 newFieldCacheMap[k] = v 265 } 266 newFieldCacheMap[structField{structType, field}] = info 267 fieldCache.value.Store(newFieldCacheMap) 268 return info 269} 270 271func unwrapInterface(v reflect.Value) reflect.Value { 272 for v.Kind() == reflect.Interface { 273 v = v.Elem() 274 } 275 return v 276} 277 278func mapFromUnstructured(sv, dv reflect.Value) error { 279 st, dt := sv.Type(), dv.Type() 280 if st.Kind() != reflect.Map { 281 return fmt.Errorf("cannot restore map from %v", st.Kind()) 282 } 283 284 if !st.Key().AssignableTo(dt.Key()) && !st.Key().ConvertibleTo(dt.Key()) { 285 return fmt.Errorf("cannot copy map with non-assignable keys: %v %v", st.Key(), dt.Key()) 286 } 287 288 if sv.IsNil() { 289 dv.Set(reflect.Zero(dt)) 290 return nil 291 } 292 dv.Set(reflect.MakeMap(dt)) 293 for _, key := range sv.MapKeys() { 294 value := reflect.New(dt.Elem()).Elem() 295 if val := unwrapInterface(sv.MapIndex(key)); val.IsValid() { 296 if err := fromUnstructured(val, value); err != nil { 297 return err 298 } 299 } else { 300 value.Set(reflect.Zero(dt.Elem())) 301 } 302 if st.Key().AssignableTo(dt.Key()) { 303 dv.SetMapIndex(key, value) 304 } else { 305 dv.SetMapIndex(key.Convert(dt.Key()), value) 306 } 307 } 308 return nil 309} 310 311func sliceFromUnstructured(sv, dv reflect.Value) error { 312 st, dt := sv.Type(), dv.Type() 313 if st.Kind() == reflect.String && dt.Elem().Kind() == reflect.Uint8 { 314 // We store original []byte representation as string. 315 // This conversion is allowed, but we need to be careful about 316 // marshaling data appropriately. 317 if len(sv.Interface().(string)) > 0 { 318 marshalled, err := json.Marshal(sv.Interface()) 319 if err != nil { 320 return fmt.Errorf("error encoding %s to json: %v", st, err) 321 } 322 // TODO: Is this Unmarshal needed? 323 var data []byte 324 err = json.Unmarshal(marshalled, &data) 325 if err != nil { 326 return fmt.Errorf("error decoding from json: %v", err) 327 } 328 dv.SetBytes(data) 329 } else { 330 dv.Set(reflect.Zero(dt)) 331 } 332 return nil 333 } 334 if st.Kind() != reflect.Slice { 335 return fmt.Errorf("cannot restore slice from %v", st.Kind()) 336 } 337 338 if sv.IsNil() { 339 dv.Set(reflect.Zero(dt)) 340 return nil 341 } 342 dv.Set(reflect.MakeSlice(dt, sv.Len(), sv.Cap())) 343 for i := 0; i < sv.Len(); i++ { 344 if err := fromUnstructured(sv.Index(i), dv.Index(i)); err != nil { 345 return err 346 } 347 } 348 return nil 349} 350 351func pointerFromUnstructured(sv, dv reflect.Value) error { 352 st, dt := sv.Type(), dv.Type() 353 354 if st.Kind() == reflect.Ptr && sv.IsNil() { 355 dv.Set(reflect.Zero(dt)) 356 return nil 357 } 358 dv.Set(reflect.New(dt.Elem())) 359 switch st.Kind() { 360 case reflect.Ptr, reflect.Interface: 361 return fromUnstructured(sv.Elem(), dv.Elem()) 362 default: 363 return fromUnstructured(sv, dv.Elem()) 364 } 365} 366 367func structFromUnstructured(sv, dv reflect.Value) error { 368 st, dt := sv.Type(), dv.Type() 369 if st.Kind() != reflect.Map { 370 return fmt.Errorf("cannot restore struct from: %v", st.Kind()) 371 } 372 373 for i := 0; i < dt.NumField(); i++ { 374 fieldInfo := fieldInfoFromField(dt, i) 375 fv := dv.Field(i) 376 377 if len(fieldInfo.name) == 0 { 378 // This field is inlined. 379 if err := fromUnstructured(sv, fv); err != nil { 380 return err 381 } 382 } else { 383 value := unwrapInterface(sv.MapIndex(fieldInfo.nameValue)) 384 if value.IsValid() { 385 if err := fromUnstructured(value, fv); err != nil { 386 return err 387 } 388 } else { 389 fv.Set(reflect.Zero(fv.Type())) 390 } 391 } 392 } 393 return nil 394} 395 396func interfaceFromUnstructured(sv, dv reflect.Value) error { 397 // TODO: Is this conversion safe? 398 dv.Set(sv) 399 return nil 400} 401 402// ToUnstructured converts an object into map[string]interface{} representation. 403// It uses encoding/json/Marshaler if object implements it or reflection if not. 404func (c *unstructuredConverter) ToUnstructured(obj interface{}) (map[string]interface{}, error) { 405 var u map[string]interface{} 406 var err error 407 if unstr, ok := obj.(Unstructured); ok { 408 u = unstr.UnstructuredContent() 409 } else { 410 t := reflect.TypeOf(obj) 411 value := reflect.ValueOf(obj) 412 if t.Kind() != reflect.Ptr || value.IsNil() { 413 return nil, fmt.Errorf("ToUnstructured requires a non-nil pointer to an object, got %v", t) 414 } 415 u = map[string]interface{}{} 416 err = toUnstructured(value.Elem(), reflect.ValueOf(&u).Elem()) 417 } 418 if c.mismatchDetection { 419 newUnstr := map[string]interface{}{} 420 newErr := toUnstructuredViaJSON(obj, &newUnstr) 421 if (err != nil) != (newErr != nil) { 422 klog.Fatalf("ToUnstructured unexpected error for %v: error: %v; newErr: %v", obj, err, newErr) 423 } 424 if err == nil && !c.comparison.DeepEqual(u, newUnstr) { 425 klog.Fatalf("ToUnstructured mismatch\nobj1: %#v\nobj2: %#v", u, newUnstr) 426 } 427 } 428 if err != nil { 429 return nil, err 430 } 431 return u, nil 432} 433 434// DeepCopyJSON deep copies the passed value, assuming it is a valid JSON representation i.e. only contains 435// types produced by json.Unmarshal() and also int64. 436// bool, int64, float64, string, []interface{}, map[string]interface{}, json.Number and nil 437func DeepCopyJSON(x map[string]interface{}) map[string]interface{} { 438 return DeepCopyJSONValue(x).(map[string]interface{}) 439} 440 441// DeepCopyJSONValue deep copies the passed value, assuming it is a valid JSON representation i.e. only contains 442// types produced by json.Unmarshal() and also int64. 443// bool, int64, float64, string, []interface{}, map[string]interface{}, json.Number and nil 444func DeepCopyJSONValue(x interface{}) interface{} { 445 switch x := x.(type) { 446 case map[string]interface{}: 447 if x == nil { 448 // Typed nil - an interface{} that contains a type map[string]interface{} with a value of nil 449 return x 450 } 451 clone := make(map[string]interface{}, len(x)) 452 for k, v := range x { 453 clone[k] = DeepCopyJSONValue(v) 454 } 455 return clone 456 case []interface{}: 457 if x == nil { 458 // Typed nil - an interface{} that contains a type []interface{} with a value of nil 459 return x 460 } 461 clone := make([]interface{}, len(x)) 462 for i, v := range x { 463 clone[i] = DeepCopyJSONValue(v) 464 } 465 return clone 466 case string, int64, bool, float64, nil, encodingjson.Number: 467 return x 468 default: 469 panic(fmt.Errorf("cannot deep copy %T", x)) 470 } 471} 472 473func toUnstructuredViaJSON(obj interface{}, u *map[string]interface{}) error { 474 data, err := json.Marshal(obj) 475 if err != nil { 476 return err 477 } 478 return json.Unmarshal(data, u) 479} 480 481func toUnstructured(sv, dv reflect.Value) error { 482 // Check if the object has a custom string converter. 483 entry := value.TypeReflectEntryOf(sv.Type()) 484 if entry.CanConvertToUnstructured() { 485 v, err := entry.ToUnstructured(sv) 486 if err != nil { 487 return err 488 } 489 if v != nil { 490 dv.Set(reflect.ValueOf(v)) 491 } 492 return nil 493 } 494 st := sv.Type() 495 switch st.Kind() { 496 case reflect.String: 497 dv.Set(reflect.ValueOf(sv.String())) 498 return nil 499 case reflect.Bool: 500 dv.Set(reflect.ValueOf(sv.Bool())) 501 return nil 502 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 503 dv.Set(reflect.ValueOf(sv.Int())) 504 return nil 505 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 506 uVal := sv.Uint() 507 if uVal > math.MaxInt64 { 508 return fmt.Errorf("unsigned value %d does not fit into int64 (overflow)", uVal) 509 } 510 dv.Set(reflect.ValueOf(int64(uVal))) 511 return nil 512 case reflect.Float32, reflect.Float64: 513 dv.Set(reflect.ValueOf(sv.Float())) 514 return nil 515 case reflect.Map: 516 return mapToUnstructured(sv, dv) 517 case reflect.Slice: 518 return sliceToUnstructured(sv, dv) 519 case reflect.Ptr: 520 return pointerToUnstructured(sv, dv) 521 case reflect.Struct: 522 return structToUnstructured(sv, dv) 523 case reflect.Interface: 524 return interfaceToUnstructured(sv, dv) 525 default: 526 return fmt.Errorf("unrecognized type: %v", st.Kind()) 527 } 528} 529 530func mapToUnstructured(sv, dv reflect.Value) error { 531 st, dt := sv.Type(), dv.Type() 532 if sv.IsNil() { 533 dv.Set(reflect.Zero(dt)) 534 return nil 535 } 536 if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 { 537 if st.Key().Kind() == reflect.String { 538 switch st.Elem().Kind() { 539 // TODO It should be possible to reuse the slice for primitive types. 540 // However, it is panicing in the following form. 541 // case reflect.String, reflect.Bool, 542 // reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 543 // reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 544 // sv.Set(sv) 545 // return nil 546 default: 547 // We need to do a proper conversion. 548 } 549 } 550 dv.Set(reflect.MakeMap(mapStringInterfaceType)) 551 dv = dv.Elem() 552 dt = dv.Type() 553 } 554 if dt.Kind() != reflect.Map { 555 return fmt.Errorf("cannot convert struct to: %v", dt.Kind()) 556 } 557 558 if !st.Key().AssignableTo(dt.Key()) && !st.Key().ConvertibleTo(dt.Key()) { 559 return fmt.Errorf("cannot copy map with non-assignable keys: %v %v", st.Key(), dt.Key()) 560 } 561 562 for _, key := range sv.MapKeys() { 563 value := reflect.New(dt.Elem()).Elem() 564 if err := toUnstructured(sv.MapIndex(key), value); err != nil { 565 return err 566 } 567 if st.Key().AssignableTo(dt.Key()) { 568 dv.SetMapIndex(key, value) 569 } else { 570 dv.SetMapIndex(key.Convert(dt.Key()), value) 571 } 572 } 573 return nil 574} 575 576func sliceToUnstructured(sv, dv reflect.Value) error { 577 st, dt := sv.Type(), dv.Type() 578 if sv.IsNil() { 579 dv.Set(reflect.Zero(dt)) 580 return nil 581 } 582 if st.Elem().Kind() == reflect.Uint8 { 583 dv.Set(reflect.New(stringType)) 584 data, err := json.Marshal(sv.Bytes()) 585 if err != nil { 586 return err 587 } 588 var result string 589 if err = json.Unmarshal(data, &result); err != nil { 590 return err 591 } 592 dv.Set(reflect.ValueOf(result)) 593 return nil 594 } 595 if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 { 596 switch st.Elem().Kind() { 597 // TODO It should be possible to reuse the slice for primitive types. 598 // However, it is panicing in the following form. 599 // case reflect.String, reflect.Bool, 600 // reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 601 // reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 602 // sv.Set(sv) 603 // return nil 604 default: 605 // We need to do a proper conversion. 606 dv.Set(reflect.MakeSlice(reflect.SliceOf(dt), sv.Len(), sv.Cap())) 607 dv = dv.Elem() 608 dt = dv.Type() 609 } 610 } 611 if dt.Kind() != reflect.Slice { 612 return fmt.Errorf("cannot convert slice to: %v", dt.Kind()) 613 } 614 for i := 0; i < sv.Len(); i++ { 615 if err := toUnstructured(sv.Index(i), dv.Index(i)); err != nil { 616 return err 617 } 618 } 619 return nil 620} 621 622func pointerToUnstructured(sv, dv reflect.Value) error { 623 if sv.IsNil() { 624 // We're done - we don't need to store anything. 625 return nil 626 } 627 return toUnstructured(sv.Elem(), dv) 628} 629 630func isZero(v reflect.Value) bool { 631 switch v.Kind() { 632 case reflect.Array, reflect.String: 633 return v.Len() == 0 634 case reflect.Bool: 635 return !v.Bool() 636 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 637 return v.Int() == 0 638 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 639 return v.Uint() == 0 640 case reflect.Float32, reflect.Float64: 641 return v.Float() == 0 642 case reflect.Map, reflect.Slice: 643 // TODO: It seems that 0-len maps are ignored in it. 644 return v.IsNil() || v.Len() == 0 645 case reflect.Ptr, reflect.Interface: 646 return v.IsNil() 647 } 648 return false 649} 650 651func structToUnstructured(sv, dv reflect.Value) error { 652 st, dt := sv.Type(), dv.Type() 653 if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 { 654 dv.Set(reflect.MakeMapWithSize(mapStringInterfaceType, st.NumField())) 655 dv = dv.Elem() 656 dt = dv.Type() 657 } 658 if dt.Kind() != reflect.Map { 659 return fmt.Errorf("cannot convert struct to: %v", dt.Kind()) 660 } 661 realMap := dv.Interface().(map[string]interface{}) 662 663 for i := 0; i < st.NumField(); i++ { 664 fieldInfo := fieldInfoFromField(st, i) 665 fv := sv.Field(i) 666 667 if fieldInfo.name == "-" { 668 // This field should be skipped. 669 continue 670 } 671 if fieldInfo.omitempty && isZero(fv) { 672 // omitempty fields should be ignored. 673 continue 674 } 675 if len(fieldInfo.name) == 0 { 676 // This field is inlined. 677 if err := toUnstructured(fv, dv); err != nil { 678 return err 679 } 680 continue 681 } 682 switch fv.Type().Kind() { 683 case reflect.String: 684 realMap[fieldInfo.name] = fv.String() 685 case reflect.Bool: 686 realMap[fieldInfo.name] = fv.Bool() 687 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 688 realMap[fieldInfo.name] = fv.Int() 689 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 690 realMap[fieldInfo.name] = fv.Uint() 691 case reflect.Float32, reflect.Float64: 692 realMap[fieldInfo.name] = fv.Float() 693 default: 694 subv := reflect.New(dt.Elem()).Elem() 695 if err := toUnstructured(fv, subv); err != nil { 696 return err 697 } 698 dv.SetMapIndex(fieldInfo.nameValue, subv) 699 } 700 } 701 return nil 702} 703 704func interfaceToUnstructured(sv, dv reflect.Value) error { 705 if !sv.IsValid() || sv.IsNil() { 706 dv.Set(reflect.Zero(dv.Type())) 707 return nil 708 } 709 return toUnstructured(sv.Elem(), dv) 710} 711