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