blob: 7854c207c72a613abe373046e02d7b210d458550 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001/*
2Copyright 2014 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 conversion
18
19import (
20 "fmt"
21 "reflect"
22)
23
24type typePair struct {
25 source reflect.Type
26 dest reflect.Type
27}
28
29type typeNamePair struct {
30 fieldType reflect.Type
31 fieldName string
32}
33
34// DebugLogger allows you to get debugging messages if necessary.
35type DebugLogger interface {
36 Logf(format string, args ...interface{})
37}
38
39type NameFunc func(t reflect.Type) string
40
41var DefaultNameFunc = func(t reflect.Type) string { return t.Name() }
42
43type GenericConversionFunc func(a, b interface{}, scope Scope) (bool, error)
44
45// Converter knows how to convert one type to another.
46type Converter struct {
47 // Map from the conversion pair to a function which can
48 // do the conversion.
49 conversionFuncs ConversionFuncs
50 generatedConversionFuncs ConversionFuncs
51
52 // genericConversions are called during normal conversion to offer a "fast-path"
53 // that avoids all reflection. These methods are not called outside of the .Convert()
54 // method.
55 genericConversions []GenericConversionFunc
56
57 // Set of conversions that should be treated as a no-op
58 ignoredConversions map[typePair]struct{}
59
60 // This is a map from a source field type and name, to a list of destination
61 // field type and name.
62 structFieldDests map[typeNamePair][]typeNamePair
63
64 // Allows for the opposite lookup of structFieldDests. So that SourceFromDest
65 // copy flag also works. So this is a map of destination field name, to potential
66 // source field name and type to look for.
67 structFieldSources map[typeNamePair][]typeNamePair
68
69 // Map from an input type to a function which can apply a key name mapping
70 inputFieldMappingFuncs map[reflect.Type]FieldMappingFunc
71
72 // Map from an input type to a set of default conversion flags.
73 inputDefaultFlags map[reflect.Type]FieldMatchingFlags
74
75 // If non-nil, will be called to print helpful debugging info. Quite verbose.
76 Debug DebugLogger
77
78 // nameFunc is called to retrieve the name of a type; this name is used for the
79 // purpose of deciding whether two types match or not (i.e., will we attempt to
80 // do a conversion). The default returns the go type name.
81 nameFunc func(t reflect.Type) string
82}
83
84// NewConverter creates a new Converter object.
85func NewConverter(nameFn NameFunc) *Converter {
86 c := &Converter{
87 conversionFuncs: NewConversionFuncs(),
88 generatedConversionFuncs: NewConversionFuncs(),
89 ignoredConversions: make(map[typePair]struct{}),
90 nameFunc: nameFn,
91 structFieldDests: make(map[typeNamePair][]typeNamePair),
92 structFieldSources: make(map[typeNamePair][]typeNamePair),
93
94 inputFieldMappingFuncs: make(map[reflect.Type]FieldMappingFunc),
95 inputDefaultFlags: make(map[reflect.Type]FieldMatchingFlags),
96 }
97 c.RegisterConversionFunc(Convert_Slice_byte_To_Slice_byte)
98 return c
99}
100
101// AddGenericConversionFunc adds a function that accepts the ConversionFunc call pattern
102// (for two conversion types) to the converter. These functions are checked first during
103// a normal conversion, but are otherwise not called. Use AddConversionFuncs when registering
104// typed conversions.
105func (c *Converter) AddGenericConversionFunc(fn GenericConversionFunc) {
106 c.genericConversions = append(c.genericConversions, fn)
107}
108
109// WithConversions returns a Converter that is a copy of c but with the additional
110// fns merged on top.
111func (c *Converter) WithConversions(fns ConversionFuncs) *Converter {
112 copied := *c
113 copied.conversionFuncs = c.conversionFuncs.Merge(fns)
114 return &copied
115}
116
117// DefaultMeta returns the conversion FieldMappingFunc and meta for a given type.
118func (c *Converter) DefaultMeta(t reflect.Type) (FieldMatchingFlags, *Meta) {
119 return c.inputDefaultFlags[t], &Meta{
120 KeyNameMapping: c.inputFieldMappingFuncs[t],
121 }
122}
123
124// Convert_Slice_byte_To_Slice_byte prevents recursing into every byte
125func Convert_Slice_byte_To_Slice_byte(in *[]byte, out *[]byte, s Scope) error {
126 if *in == nil {
127 *out = nil
128 return nil
129 }
130 *out = make([]byte, len(*in))
131 copy(*out, *in)
132 return nil
133}
134
135// Scope is passed to conversion funcs to allow them to continue an ongoing conversion.
136// If multiple converters exist in the system, Scope will allow you to use the correct one
137// from a conversion function--that is, the one your conversion function was called by.
138type Scope interface {
139 // Call Convert to convert sub-objects. Note that if you call it with your own exact
140 // parameters, you'll run out of stack space before anything useful happens.
141 Convert(src, dest interface{}, flags FieldMatchingFlags) error
142
143 // DefaultConvert performs the default conversion, without calling a conversion func
144 // on the current stack frame. This makes it safe to call from a conversion func.
145 DefaultConvert(src, dest interface{}, flags FieldMatchingFlags) error
146
147 // SrcTags and DestTags contain the struct tags that src and dest had, respectively.
148 // If the enclosing object was not a struct, then these will contain no tags, of course.
149 SrcTag() reflect.StructTag
150 DestTag() reflect.StructTag
151
152 // Flags returns the flags with which the conversion was started.
153 Flags() FieldMatchingFlags
154
155 // Meta returns any information originally passed to Convert.
156 Meta() *Meta
157}
158
159// FieldMappingFunc can convert an input field value into different values, depending on
160// the value of the source or destination struct tags.
161type FieldMappingFunc func(key string, sourceTag, destTag reflect.StructTag) (source string, dest string)
162
163func NewConversionFuncs() ConversionFuncs {
164 return ConversionFuncs{fns: make(map[typePair]reflect.Value)}
165}
166
167type ConversionFuncs struct {
168 fns map[typePair]reflect.Value
169}
170
171// Add adds the provided conversion functions to the lookup table - they must have the signature
172// `func(type1, type2, Scope) error`. Functions are added in the order passed and will override
173// previously registered pairs.
174func (c ConversionFuncs) Add(fns ...interface{}) error {
175 for _, fn := range fns {
176 fv := reflect.ValueOf(fn)
177 ft := fv.Type()
178 if err := verifyConversionFunctionSignature(ft); err != nil {
179 return err
180 }
181 c.fns[typePair{ft.In(0).Elem(), ft.In(1).Elem()}] = fv
182 }
183 return nil
184}
185
186// Merge returns a new ConversionFuncs that contains all conversions from
187// both other and c, with other conversions taking precedence.
188func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs {
189 merged := NewConversionFuncs()
190 for k, v := range c.fns {
191 merged.fns[k] = v
192 }
193 for k, v := range other.fns {
194 merged.fns[k] = v
195 }
196 return merged
197}
198
199// Meta is supplied by Scheme, when it calls Convert.
200type Meta struct {
201 // KeyNameMapping is an optional function which may map the listed key (field name)
202 // into a source and destination value.
203 KeyNameMapping FieldMappingFunc
204 // Context is an optional field that callers may use to pass info to conversion functions.
205 Context interface{}
206}
207
208// scope contains information about an ongoing conversion.
209type scope struct {
210 converter *Converter
211 meta *Meta
212 flags FieldMatchingFlags
213
214 // srcStack & destStack are separate because they may not have a 1:1
215 // relationship.
216 srcStack scopeStack
217 destStack scopeStack
218}
219
220type scopeStackElem struct {
221 tag reflect.StructTag
222 value reflect.Value
223 key string
224}
225
226type scopeStack []scopeStackElem
227
228func (s *scopeStack) pop() {
229 n := len(*s)
230 *s = (*s)[:n-1]
231}
232
233func (s *scopeStack) push(e scopeStackElem) {
234 *s = append(*s, e)
235}
236
237func (s *scopeStack) top() *scopeStackElem {
238 return &(*s)[len(*s)-1]
239}
240
241func (s scopeStack) describe() string {
242 desc := ""
243 if len(s) > 1 {
244 desc = "(" + s[1].value.Type().String() + ")"
245 }
246 for i, v := range s {
247 if i < 2 {
248 // First layer on stack is not real; second is handled specially above.
249 continue
250 }
251 if v.key == "" {
252 desc += fmt.Sprintf(".%v", v.value.Type())
253 } else {
254 desc += fmt.Sprintf(".%v", v.key)
255 }
256 }
257 return desc
258}
259
260// Formats src & dest as indices for printing.
261func (s *scope) setIndices(src, dest int) {
262 s.srcStack.top().key = fmt.Sprintf("[%v]", src)
263 s.destStack.top().key = fmt.Sprintf("[%v]", dest)
264}
265
266// Formats src & dest as map keys for printing.
267func (s *scope) setKeys(src, dest interface{}) {
268 s.srcStack.top().key = fmt.Sprintf(`["%v"]`, src)
269 s.destStack.top().key = fmt.Sprintf(`["%v"]`, dest)
270}
271
272// Convert continues a conversion.
273func (s *scope) Convert(src, dest interface{}, flags FieldMatchingFlags) error {
274 return s.converter.Convert(src, dest, flags, s.meta)
275}
276
277// DefaultConvert continues a conversion, performing a default conversion (no conversion func)
278// for the current stack frame.
279func (s *scope) DefaultConvert(src, dest interface{}, flags FieldMatchingFlags) error {
280 return s.converter.DefaultConvert(src, dest, flags, s.meta)
281}
282
283// SrcTag returns the tag of the struct containing the current source item, if any.
284func (s *scope) SrcTag() reflect.StructTag {
285 return s.srcStack.top().tag
286}
287
288// DestTag returns the tag of the struct containing the current dest item, if any.
289func (s *scope) DestTag() reflect.StructTag {
290 return s.destStack.top().tag
291}
292
293// Flags returns the flags with which the current conversion was started.
294func (s *scope) Flags() FieldMatchingFlags {
295 return s.flags
296}
297
298// Meta returns the meta object that was originally passed to Convert.
299func (s *scope) Meta() *Meta {
300 return s.meta
301}
302
303// describe prints the path to get to the current (source, dest) values.
304func (s *scope) describe() (src, dest string) {
305 return s.srcStack.describe(), s.destStack.describe()
306}
307
308// error makes an error that includes information about where we were in the objects
309// we were asked to convert.
310func (s *scope) errorf(message string, args ...interface{}) error {
311 srcPath, destPath := s.describe()
312 where := fmt.Sprintf("converting %v to %v: ", srcPath, destPath)
313 return fmt.Errorf(where+message, args...)
314}
315
316// Verifies whether a conversion function has a correct signature.
317func verifyConversionFunctionSignature(ft reflect.Type) error {
318 if ft.Kind() != reflect.Func {
319 return fmt.Errorf("expected func, got: %v", ft)
320 }
321 if ft.NumIn() != 3 {
322 return fmt.Errorf("expected three 'in' params, got: %v", ft)
323 }
324 if ft.NumOut() != 1 {
325 return fmt.Errorf("expected one 'out' param, got: %v", ft)
326 }
327 if ft.In(0).Kind() != reflect.Ptr {
328 return fmt.Errorf("expected pointer arg for 'in' param 0, got: %v", ft)
329 }
330 if ft.In(1).Kind() != reflect.Ptr {
331 return fmt.Errorf("expected pointer arg for 'in' param 1, got: %v", ft)
332 }
333 scopeType := Scope(nil)
334 if e, a := reflect.TypeOf(&scopeType).Elem(), ft.In(2); e != a {
335 return fmt.Errorf("expected '%v' arg for 'in' param 2, got '%v' (%v)", e, a, ft)
336 }
337 var forErrorType error
338 // This convolution is necessary, otherwise TypeOf picks up on the fact
339 // that forErrorType is nil.
340 errorType := reflect.TypeOf(&forErrorType).Elem()
341 if ft.Out(0) != errorType {
342 return fmt.Errorf("expected error return, got: %v", ft)
343 }
344 return nil
345}
346
347// RegisterConversionFunc registers a conversion func with the
348// Converter. conversionFunc must take three parameters: a pointer to the input
349// type, a pointer to the output type, and a conversion.Scope (which should be
350// used if recursive conversion calls are desired). It must return an error.
351//
352// Example:
353// c.RegisterConversionFunc(
354// func(in *Pod, out *v1.Pod, s Scope) error {
355// // conversion logic...
356// return nil
357// })
358func (c *Converter) RegisterConversionFunc(conversionFunc interface{}) error {
359 return c.conversionFuncs.Add(conversionFunc)
360}
361
362// Similar to RegisterConversionFunc, but registers conversion function that were
363// automatically generated.
364func (c *Converter) RegisterGeneratedConversionFunc(conversionFunc interface{}) error {
365 return c.generatedConversionFuncs.Add(conversionFunc)
366}
367
368// RegisterIgnoredConversion registers a "no-op" for conversion, where any requested
369// conversion between from and to is ignored.
370func (c *Converter) RegisterIgnoredConversion(from, to interface{}) error {
371 typeFrom := reflect.TypeOf(from)
372 typeTo := reflect.TypeOf(to)
373 if reflect.TypeOf(from).Kind() != reflect.Ptr {
374 return fmt.Errorf("expected pointer arg for 'from' param 0, got: %v", typeFrom)
375 }
376 if typeTo.Kind() != reflect.Ptr {
377 return fmt.Errorf("expected pointer arg for 'to' param 1, got: %v", typeTo)
378 }
379 c.ignoredConversions[typePair{typeFrom.Elem(), typeTo.Elem()}] = struct{}{}
380 return nil
381}
382
383// IsConversionIgnored returns true if the specified objects should be dropped during
384// conversion.
385func (c *Converter) IsConversionIgnored(inType, outType reflect.Type) bool {
386 _, found := c.ignoredConversions[typePair{inType, outType}]
387 return found
388}
389
390func (c *Converter) HasConversionFunc(inType, outType reflect.Type) bool {
391 _, found := c.conversionFuncs.fns[typePair{inType, outType}]
392 return found
393}
394
395func (c *Converter) ConversionFuncValue(inType, outType reflect.Type) (reflect.Value, bool) {
396 value, found := c.conversionFuncs.fns[typePair{inType, outType}]
397 return value, found
398}
399
400// SetStructFieldCopy registers a correspondence. Whenever a struct field is encountered
401// which has a type and name matching srcFieldType and srcFieldName, it wil be copied
402// into the field in the destination struct matching destFieldType & Name, if such a
403// field exists.
404// May be called multiple times, even for the same source field & type--all applicable
405// copies will be performed.
406func (c *Converter) SetStructFieldCopy(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, destFieldName string) error {
407 st := reflect.TypeOf(srcFieldType)
408 dt := reflect.TypeOf(destFieldType)
409 srcKey := typeNamePair{st, srcFieldName}
410 destKey := typeNamePair{dt, destFieldName}
411 c.structFieldDests[srcKey] = append(c.structFieldDests[srcKey], destKey)
412 c.structFieldSources[destKey] = append(c.structFieldSources[destKey], srcKey)
413 return nil
414}
415
416// RegisterInputDefaults registers a field name mapping function, used when converting
417// from maps to structs. Inputs to the conversion methods are checked for this type and a mapping
418// applied automatically if the input matches in. A set of default flags for the input conversion
419// may also be provided, which will be used when no explicit flags are requested.
420func (c *Converter) RegisterInputDefaults(in interface{}, fn FieldMappingFunc, defaultFlags FieldMatchingFlags) error {
421 fv := reflect.ValueOf(in)
422 ft := fv.Type()
423 if ft.Kind() != reflect.Ptr {
424 return fmt.Errorf("expected pointer 'in' argument, got: %v", ft)
425 }
426 c.inputFieldMappingFuncs[ft] = fn
427 c.inputDefaultFlags[ft] = defaultFlags
428 return nil
429}
430
431// FieldMatchingFlags contains a list of ways in which struct fields could be
432// copied. These constants may be | combined.
433type FieldMatchingFlags int
434
435const (
436 // Loop through destination fields, search for matching source
437 // field to copy it from. Source fields with no corresponding
438 // destination field will be ignored. If SourceToDest is
439 // specified, this flag is ignored. If neither is specified,
440 // or no flags are passed, this flag is the default.
441 DestFromSource FieldMatchingFlags = 0
442 // Loop through source fields, search for matching dest field
443 // to copy it into. Destination fields with no corresponding
444 // source field will be ignored.
445 SourceToDest FieldMatchingFlags = 1 << iota
446 // Don't treat it as an error if the corresponding source or
447 // dest field can't be found.
448 IgnoreMissingFields
449 // Don't require type names to match.
450 AllowDifferentFieldTypeNames
451)
452
453// IsSet returns true if the given flag or combination of flags is set.
454func (f FieldMatchingFlags) IsSet(flag FieldMatchingFlags) bool {
455 if flag == DestFromSource {
456 // The bit logic doesn't work on the default value.
457 return f&SourceToDest != SourceToDest
458 }
459 return f&flag == flag
460}
461
462// Convert will translate src to dest if it knows how. Both must be pointers.
463// If no conversion func is registered and the default copying mechanism
464// doesn't work on this type pair, an error will be returned.
465// Read the comments on the various FieldMatchingFlags constants to understand
466// what the 'flags' parameter does.
467// 'meta' is given to allow you to pass information to conversion functions,
468// it is not used by Convert() other than storing it in the scope.
469// Not safe for objects with cyclic references!
470func (c *Converter) Convert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error {
471 if len(c.genericConversions) > 0 {
472 // TODO: avoid scope allocation
473 s := &scope{converter: c, flags: flags, meta: meta}
474 for _, fn := range c.genericConversions {
475 if ok, err := fn(src, dest, s); ok {
476 return err
477 }
478 }
479 }
480 return c.doConversion(src, dest, flags, meta, c.convert)
481}
482
483// DefaultConvert will translate src to dest if it knows how. Both must be pointers.
484// No conversion func is used. If the default copying mechanism
485// doesn't work on this type pair, an error will be returned.
486// Read the comments on the various FieldMatchingFlags constants to understand
487// what the 'flags' parameter does.
488// 'meta' is given to allow you to pass information to conversion functions,
489// it is not used by DefaultConvert() other than storing it in the scope.
490// Not safe for objects with cyclic references!
491func (c *Converter) DefaultConvert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error {
492 return c.doConversion(src, dest, flags, meta, c.defaultConvert)
493}
494
495type conversionFunc func(sv, dv reflect.Value, scope *scope) error
496
497func (c *Converter) doConversion(src, dest interface{}, flags FieldMatchingFlags, meta *Meta, f conversionFunc) error {
498 dv, err := EnforcePtr(dest)
499 if err != nil {
500 return err
501 }
502 if !dv.CanAddr() && !dv.CanSet() {
503 return fmt.Errorf("can't write to dest")
504 }
505 sv, err := EnforcePtr(src)
506 if err != nil {
507 return err
508 }
509 s := &scope{
510 converter: c,
511 flags: flags,
512 meta: meta,
513 }
514 // Leave something on the stack, so that calls to struct tag getters never fail.
515 s.srcStack.push(scopeStackElem{})
516 s.destStack.push(scopeStackElem{})
517 return f(sv, dv, s)
518}
519
520// callCustom calls 'custom' with sv & dv. custom must be a conversion function.
521func (c *Converter) callCustom(sv, dv, custom reflect.Value, scope *scope) error {
522 if !sv.CanAddr() {
523 sv2 := reflect.New(sv.Type())
524 sv2.Elem().Set(sv)
525 sv = sv2
526 } else {
527 sv = sv.Addr()
528 }
529 if !dv.CanAddr() {
530 if !dv.CanSet() {
531 return scope.errorf("can't addr or set dest.")
532 }
533 dvOrig := dv
534 dv := reflect.New(dvOrig.Type())
535 defer func() { dvOrig.Set(dv) }()
536 } else {
537 dv = dv.Addr()
538 }
539 args := []reflect.Value{sv, dv, reflect.ValueOf(scope)}
540 ret := custom.Call(args)[0].Interface()
541 // This convolution is necessary because nil interfaces won't convert
542 // to errors.
543 if ret == nil {
544 return nil
545 }
546 return ret.(error)
547}
548
549// convert recursively copies sv into dv, calling an appropriate conversion function if
550// one is registered.
551func (c *Converter) convert(sv, dv reflect.Value, scope *scope) error {
552 dt, st := dv.Type(), sv.Type()
553 pair := typePair{st, dt}
554
555 // ignore conversions of this type
556 if _, ok := c.ignoredConversions[pair]; ok {
557 if c.Debug != nil {
558 c.Debug.Logf("Ignoring conversion of '%v' to '%v'", st, dt)
559 }
560 return nil
561 }
562
563 // Convert sv to dv.
564 if fv, ok := c.conversionFuncs.fns[pair]; ok {
565 if c.Debug != nil {
566 c.Debug.Logf("Calling custom conversion of '%v' to '%v'", st, dt)
567 }
568 return c.callCustom(sv, dv, fv, scope)
569 }
570 if fv, ok := c.generatedConversionFuncs.fns[pair]; ok {
571 if c.Debug != nil {
572 c.Debug.Logf("Calling generated conversion of '%v' to '%v'", st, dt)
573 }
574 return c.callCustom(sv, dv, fv, scope)
575 }
576
577 return c.defaultConvert(sv, dv, scope)
578}
579
580// defaultConvert recursively copies sv into dv. no conversion function is called
581// for the current stack frame (but conversion functions may be called for nested objects)
582func (c *Converter) defaultConvert(sv, dv reflect.Value, scope *scope) error {
583 dt, st := dv.Type(), sv.Type()
584
585 if !dv.CanSet() {
586 return scope.errorf("Cannot set dest. (Tried to deep copy something with unexported fields?)")
587 }
588
589 if !scope.flags.IsSet(AllowDifferentFieldTypeNames) && c.nameFunc(dt) != c.nameFunc(st) {
590 return scope.errorf(
591 "type names don't match (%v, %v), and no conversion 'func (%v, %v) error' registered.",
592 c.nameFunc(st), c.nameFunc(dt), st, dt)
593 }
594
595 switch st.Kind() {
596 case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct:
597 // Don't copy these via assignment/conversion!
598 default:
599 // This should handle all simple types.
600 if st.AssignableTo(dt) {
601 dv.Set(sv)
602 return nil
603 }
604 if st.ConvertibleTo(dt) {
605 dv.Set(sv.Convert(dt))
606 return nil
607 }
608 }
609
610 if c.Debug != nil {
611 c.Debug.Logf("Trying to convert '%v' to '%v'", st, dt)
612 }
613
614 scope.srcStack.push(scopeStackElem{value: sv})
615 scope.destStack.push(scopeStackElem{value: dv})
616 defer scope.srcStack.pop()
617 defer scope.destStack.pop()
618
619 switch dv.Kind() {
620 case reflect.Struct:
621 return c.convertKV(toKVValue(sv), toKVValue(dv), scope)
622 case reflect.Slice:
623 if sv.IsNil() {
624 // Don't make a zero-length slice.
625 dv.Set(reflect.Zero(dt))
626 return nil
627 }
628 dv.Set(reflect.MakeSlice(dt, sv.Len(), sv.Cap()))
629 for i := 0; i < sv.Len(); i++ {
630 scope.setIndices(i, i)
631 if err := c.convert(sv.Index(i), dv.Index(i), scope); err != nil {
632 return err
633 }
634 }
635 case reflect.Ptr:
636 if sv.IsNil() {
637 // Don't copy a nil ptr!
638 dv.Set(reflect.Zero(dt))
639 return nil
640 }
641 dv.Set(reflect.New(dt.Elem()))
642 switch st.Kind() {
643 case reflect.Ptr, reflect.Interface:
644 return c.convert(sv.Elem(), dv.Elem(), scope)
645 default:
646 return c.convert(sv, dv.Elem(), scope)
647 }
648 case reflect.Map:
649 if sv.IsNil() {
650 // Don't copy a nil ptr!
651 dv.Set(reflect.Zero(dt))
652 return nil
653 }
654 dv.Set(reflect.MakeMap(dt))
655 for _, sk := range sv.MapKeys() {
656 dk := reflect.New(dt.Key()).Elem()
657 if err := c.convert(sk, dk, scope); err != nil {
658 return err
659 }
660 dkv := reflect.New(dt.Elem()).Elem()
661 scope.setKeys(sk.Interface(), dk.Interface())
662 // TODO: sv.MapIndex(sk) may return a value with CanAddr() == false,
663 // because a map[string]struct{} does not allow a pointer reference.
664 // Calling a custom conversion function defined for the map value
665 // will panic. Example is PodInfo map[string]ContainerStatus.
666 if err := c.convert(sv.MapIndex(sk), dkv, scope); err != nil {
667 return err
668 }
669 dv.SetMapIndex(dk, dkv)
670 }
671 case reflect.Interface:
672 if sv.IsNil() {
673 // Don't copy a nil interface!
674 dv.Set(reflect.Zero(dt))
675 return nil
676 }
677 tmpdv := reflect.New(sv.Elem().Type()).Elem()
678 if err := c.convert(sv.Elem(), tmpdv, scope); err != nil {
679 return err
680 }
681 dv.Set(reflect.ValueOf(tmpdv.Interface()))
682 return nil
683 default:
684 return scope.errorf("couldn't copy '%v' into '%v'; didn't understand types", st, dt)
685 }
686 return nil
687}
688
689var stringType = reflect.TypeOf("")
690
691func toKVValue(v reflect.Value) kvValue {
692 switch v.Kind() {
693 case reflect.Struct:
694 return structAdaptor(v)
695 case reflect.Map:
696 if v.Type().Key().AssignableTo(stringType) {
697 return stringMapAdaptor(v)
698 }
699 }
700
701 return nil
702}
703
704// kvValue lets us write the same conversion logic to work with both maps
705// and structs. Only maps with string keys make sense for this.
706type kvValue interface {
707 // returns all keys, as a []string.
708 keys() []string
709 // Will just return "" for maps.
710 tagOf(key string) reflect.StructTag
711 // Will return the zero Value if the key doesn't exist.
712 value(key string) reflect.Value
713 // Maps require explicit setting-- will do nothing for structs.
714 // Returns false on failure.
715 confirmSet(key string, v reflect.Value) bool
716}
717
718type stringMapAdaptor reflect.Value
719
720func (a stringMapAdaptor) len() int {
721 return reflect.Value(a).Len()
722}
723
724func (a stringMapAdaptor) keys() []string {
725 v := reflect.Value(a)
726 keys := make([]string, v.Len())
727 for i, v := range v.MapKeys() {
728 if v.IsNil() {
729 continue
730 }
731 switch t := v.Interface().(type) {
732 case string:
733 keys[i] = t
734 }
735 }
736 return keys
737}
738
739func (a stringMapAdaptor) tagOf(key string) reflect.StructTag {
740 return ""
741}
742
743func (a stringMapAdaptor) value(key string) reflect.Value {
744 return reflect.Value(a).MapIndex(reflect.ValueOf(key))
745}
746
747func (a stringMapAdaptor) confirmSet(key string, v reflect.Value) bool {
748 return true
749}
750
751type structAdaptor reflect.Value
752
753func (a structAdaptor) len() int {
754 v := reflect.Value(a)
755 return v.Type().NumField()
756}
757
758func (a structAdaptor) keys() []string {
759 v := reflect.Value(a)
760 t := v.Type()
761 keys := make([]string, t.NumField())
762 for i := range keys {
763 keys[i] = t.Field(i).Name
764 }
765 return keys
766}
767
768func (a structAdaptor) tagOf(key string) reflect.StructTag {
769 v := reflect.Value(a)
770 field, ok := v.Type().FieldByName(key)
771 if ok {
772 return field.Tag
773 }
774 return ""
775}
776
777func (a structAdaptor) value(key string) reflect.Value {
778 v := reflect.Value(a)
779 return v.FieldByName(key)
780}
781
782func (a structAdaptor) confirmSet(key string, v reflect.Value) bool {
783 return true
784}
785
786// convertKV can convert things that consist of key/value pairs, like structs
787// and some maps.
788func (c *Converter) convertKV(skv, dkv kvValue, scope *scope) error {
789 if skv == nil || dkv == nil {
790 // TODO: add keys to stack to support really understandable error messages.
791 return fmt.Errorf("Unable to convert %#v to %#v", skv, dkv)
792 }
793
794 lister := dkv
795 if scope.flags.IsSet(SourceToDest) {
796 lister = skv
797 }
798
799 var mapping FieldMappingFunc
800 if scope.meta != nil && scope.meta.KeyNameMapping != nil {
801 mapping = scope.meta.KeyNameMapping
802 }
803
804 for _, key := range lister.keys() {
805 if found, err := c.checkField(key, skv, dkv, scope); found {
806 if err != nil {
807 return err
808 }
809 continue
810 }
811 stag := skv.tagOf(key)
812 dtag := dkv.tagOf(key)
813 skey := key
814 dkey := key
815 if mapping != nil {
816 skey, dkey = scope.meta.KeyNameMapping(key, stag, dtag)
817 }
818
819 df := dkv.value(dkey)
820 sf := skv.value(skey)
821 if !df.IsValid() || !sf.IsValid() {
822 switch {
823 case scope.flags.IsSet(IgnoreMissingFields):
824 // No error.
825 case scope.flags.IsSet(SourceToDest):
826 return scope.errorf("%v not present in dest", dkey)
827 default:
828 return scope.errorf("%v not present in src", skey)
829 }
830 continue
831 }
832 scope.srcStack.top().key = skey
833 scope.srcStack.top().tag = stag
834 scope.destStack.top().key = dkey
835 scope.destStack.top().tag = dtag
836 if err := c.convert(sf, df, scope); err != nil {
837 return err
838 }
839 }
840 return nil
841}
842
843// checkField returns true if the field name matches any of the struct
844// field copying rules. The error should be ignored if it returns false.
845func (c *Converter) checkField(fieldName string, skv, dkv kvValue, scope *scope) (bool, error) {
846 replacementMade := false
847 if scope.flags.IsSet(DestFromSource) {
848 df := dkv.value(fieldName)
849 if !df.IsValid() {
850 return false, nil
851 }
852 destKey := typeNamePair{df.Type(), fieldName}
853 // Check each of the potential source (type, name) pairs to see if they're
854 // present in sv.
855 for _, potentialSourceKey := range c.structFieldSources[destKey] {
856 sf := skv.value(potentialSourceKey.fieldName)
857 if !sf.IsValid() {
858 continue
859 }
860 if sf.Type() == potentialSourceKey.fieldType {
861 // Both the source's name and type matched, so copy.
862 scope.srcStack.top().key = potentialSourceKey.fieldName
863 scope.destStack.top().key = fieldName
864 if err := c.convert(sf, df, scope); err != nil {
865 return true, err
866 }
867 dkv.confirmSet(fieldName, df)
868 replacementMade = true
869 }
870 }
871 return replacementMade, nil
872 }
873
874 sf := skv.value(fieldName)
875 if !sf.IsValid() {
876 return false, nil
877 }
878 srcKey := typeNamePair{sf.Type(), fieldName}
879 // Check each of the potential dest (type, name) pairs to see if they're
880 // present in dv.
881 for _, potentialDestKey := range c.structFieldDests[srcKey] {
882 df := dkv.value(potentialDestKey.fieldName)
883 if !df.IsValid() {
884 continue
885 }
886 if df.Type() == potentialDestKey.fieldType {
887 // Both the dest's name and type matched, so copy.
888 scope.srcStack.top().key = fieldName
889 scope.destStack.top().key = potentialDestKey.fieldName
890 if err := c.convert(sf, df, scope); err != nil {
891 return true, err
892 }
893 dkv.confirmSet(potentialDestKey.fieldName, df)
894 replacementMade = true
895 }
896 }
897 return replacementMade, nil
898}