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