2 Copyright 2014 The Kubernetes Authors.
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
24 type typePair struct {
29 type typeNamePair struct {
30 fieldType reflect.Type
34 // DebugLogger allows you to get debugging messages if necessary.
35 type DebugLogger interface {
36 Logf(format string, args ...interface{})
39 type NameFunc func(t reflect.Type) string
41 var DefaultNameFunc = func(t reflect.Type) string { return t.Name() }
43 // ConversionFunc converts the object a into the object b, reusing arrays or objects
44 // or pointers if necessary. It should return an error if the object cannot be converted
45 // or if some data is invalid. If you do not wish a and b to share fields or nested
46 // objects, you must copy a before calling this function.
47 type ConversionFunc func(a, b interface{}, scope Scope) error
49 // Converter knows how to convert one type to another.
50 type Converter struct {
51 // Map from the conversion pair to a function which can
53 conversionFuncs ConversionFuncs
54 generatedConversionFuncs ConversionFuncs
56 // Set of conversions that should be treated as a no-op
57 ignoredConversions map[typePair]struct{}
59 // This is a map from a source field type and name, to a list of destination
60 // field type and name.
61 structFieldDests map[typeNamePair][]typeNamePair
63 // Allows for the opposite lookup of structFieldDests. So that SourceFromDest
64 // copy flag also works. So this is a map of destination field name, to potential
65 // source field name and type to look for.
66 structFieldSources map[typeNamePair][]typeNamePair
68 // Map from an input type to a function which can apply a key name mapping
69 inputFieldMappingFuncs map[reflect.Type]FieldMappingFunc
71 // Map from an input type to a set of default conversion flags.
72 inputDefaultFlags map[reflect.Type]FieldMatchingFlags
74 // If non-nil, will be called to print helpful debugging info. Quite verbose.
77 // nameFunc is called to retrieve the name of a type; this name is used for the
78 // purpose of deciding whether two types match or not (i.e., will we attempt to
79 // do a conversion). The default returns the go type name.
80 nameFunc func(t reflect.Type) string
83 // NewConverter creates a new Converter object.
84 func NewConverter(nameFn NameFunc) *Converter {
86 conversionFuncs: NewConversionFuncs(),
87 generatedConversionFuncs: NewConversionFuncs(),
88 ignoredConversions: make(map[typePair]struct{}),
90 structFieldDests: make(map[typeNamePair][]typeNamePair),
91 structFieldSources: make(map[typeNamePair][]typeNamePair),
93 inputFieldMappingFuncs: make(map[reflect.Type]FieldMappingFunc),
94 inputDefaultFlags: make(map[reflect.Type]FieldMatchingFlags),
96 c.RegisterConversionFunc(Convert_Slice_byte_To_Slice_byte)
100 // WithConversions returns a Converter that is a copy of c but with the additional
101 // fns merged on top.
102 func (c *Converter) WithConversions(fns ConversionFuncs) *Converter {
104 copied.conversionFuncs = c.conversionFuncs.Merge(fns)
108 // DefaultMeta returns the conversion FieldMappingFunc and meta for a given type.
109 func (c *Converter) DefaultMeta(t reflect.Type) (FieldMatchingFlags, *Meta) {
110 return c.inputDefaultFlags[t], &Meta{
111 KeyNameMapping: c.inputFieldMappingFuncs[t],
115 // Convert_Slice_byte_To_Slice_byte prevents recursing into every byte
116 func Convert_Slice_byte_To_Slice_byte(in *[]byte, out *[]byte, s Scope) error {
121 *out = make([]byte, len(*in))
126 // Scope is passed to conversion funcs to allow them to continue an ongoing conversion.
127 // If multiple converters exist in the system, Scope will allow you to use the correct one
128 // from a conversion function--that is, the one your conversion function was called by.
129 type Scope interface {
130 // Call Convert to convert sub-objects. Note that if you call it with your own exact
131 // parameters, you'll run out of stack space before anything useful happens.
132 Convert(src, dest interface{}, flags FieldMatchingFlags) error
134 // DefaultConvert performs the default conversion, without calling a conversion func
135 // on the current stack frame. This makes it safe to call from a conversion func.
136 DefaultConvert(src, dest interface{}, flags FieldMatchingFlags) error
138 // SrcTags and DestTags contain the struct tags that src and dest had, respectively.
139 // If the enclosing object was not a struct, then these will contain no tags, of course.
140 SrcTag() reflect.StructTag
141 DestTag() reflect.StructTag
143 // Flags returns the flags with which the conversion was started.
144 Flags() FieldMatchingFlags
146 // Meta returns any information originally passed to Convert.
150 // FieldMappingFunc can convert an input field value into different values, depending on
151 // the value of the source or destination struct tags.
152 type FieldMappingFunc func(key string, sourceTag, destTag reflect.StructTag) (source string, dest string)
154 func NewConversionFuncs() ConversionFuncs {
155 return ConversionFuncs{
156 fns: make(map[typePair]reflect.Value),
157 untyped: make(map[typePair]ConversionFunc),
161 type ConversionFuncs struct {
162 fns map[typePair]reflect.Value
163 untyped map[typePair]ConversionFunc
166 // Add adds the provided conversion functions to the lookup table - they must have the signature
167 // `func(type1, type2, Scope) error`. Functions are added in the order passed and will override
168 // previously registered pairs.
169 func (c ConversionFuncs) Add(fns ...interface{}) error {
170 for _, fn := range fns {
171 fv := reflect.ValueOf(fn)
173 if err := verifyConversionFunctionSignature(ft); err != nil {
176 c.fns[typePair{ft.In(0).Elem(), ft.In(1).Elem()}] = fv
181 // AddUntyped adds the provided conversion function to the lookup table for the types that are
182 // supplied as a and b. a and b must be pointers or an error is returned. This method overwrites
183 // previously defined functions.
184 func (c ConversionFuncs) AddUntyped(a, b interface{}, fn ConversionFunc) error {
185 tA, tB := reflect.TypeOf(a), reflect.TypeOf(b)
186 if tA.Kind() != reflect.Ptr {
187 return fmt.Errorf("the type %T must be a pointer to register as an untyped conversion", a)
189 if tB.Kind() != reflect.Ptr {
190 return fmt.Errorf("the type %T must be a pointer to register as an untyped conversion", b)
192 c.untyped[typePair{tA, tB}] = fn
196 // Merge returns a new ConversionFuncs that contains all conversions from
197 // both other and c, with other conversions taking precedence.
198 func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs {
199 merged := NewConversionFuncs()
200 for k, v := range c.fns {
203 for k, v := range other.fns {
206 for k, v := range c.untyped {
207 merged.untyped[k] = v
209 for k, v := range other.untyped {
210 merged.untyped[k] = v
215 // Meta is supplied by Scheme, when it calls Convert.
217 // KeyNameMapping is an optional function which may map the listed key (field name)
218 // into a source and destination value.
219 KeyNameMapping FieldMappingFunc
220 // Context is an optional field that callers may use to pass info to conversion functions.
224 // scope contains information about an ongoing conversion.
228 flags FieldMatchingFlags
230 // srcStack & destStack are separate because they may not have a 1:1
236 type scopeStackElem struct {
237 tag reflect.StructTag
242 type scopeStack []scopeStackElem
244 func (s *scopeStack) pop() {
249 func (s *scopeStack) push(e scopeStackElem) {
253 func (s *scopeStack) top() *scopeStackElem {
254 return &(*s)[len(*s)-1]
257 func (s scopeStack) describe() string {
260 desc = "(" + s[1].value.Type().String() + ")"
262 for i, v := range s {
264 // First layer on stack is not real; second is handled specially above.
268 desc += fmt.Sprintf(".%v", v.value.Type())
270 desc += fmt.Sprintf(".%v", v.key)
276 // Formats src & dest as indices for printing.
277 func (s *scope) setIndices(src, dest int) {
278 s.srcStack.top().key = fmt.Sprintf("[%v]", src)
279 s.destStack.top().key = fmt.Sprintf("[%v]", dest)
282 // Formats src & dest as map keys for printing.
283 func (s *scope) setKeys(src, dest interface{}) {
284 s.srcStack.top().key = fmt.Sprintf(`["%v"]`, src)
285 s.destStack.top().key = fmt.Sprintf(`["%v"]`, dest)
288 // Convert continues a conversion.
289 func (s *scope) Convert(src, dest interface{}, flags FieldMatchingFlags) error {
290 return s.converter.Convert(src, dest, flags, s.meta)
293 // DefaultConvert continues a conversion, performing a default conversion (no conversion func)
294 // for the current stack frame.
295 func (s *scope) DefaultConvert(src, dest interface{}, flags FieldMatchingFlags) error {
296 return s.converter.DefaultConvert(src, dest, flags, s.meta)
299 // SrcTag returns the tag of the struct containing the current source item, if any.
300 func (s *scope) SrcTag() reflect.StructTag {
301 return s.srcStack.top().tag
304 // DestTag returns the tag of the struct containing the current dest item, if any.
305 func (s *scope) DestTag() reflect.StructTag {
306 return s.destStack.top().tag
309 // Flags returns the flags with which the current conversion was started.
310 func (s *scope) Flags() FieldMatchingFlags {
314 // Meta returns the meta object that was originally passed to Convert.
315 func (s *scope) Meta() *Meta {
319 // describe prints the path to get to the current (source, dest) values.
320 func (s *scope) describe() (src, dest string) {
321 return s.srcStack.describe(), s.destStack.describe()
324 // error makes an error that includes information about where we were in the objects
325 // we were asked to convert.
326 func (s *scope) errorf(message string, args ...interface{}) error {
327 srcPath, destPath := s.describe()
328 where := fmt.Sprintf("converting %v to %v: ", srcPath, destPath)
329 return fmt.Errorf(where+message, args...)
332 // Verifies whether a conversion function has a correct signature.
333 func verifyConversionFunctionSignature(ft reflect.Type) error {
334 if ft.Kind() != reflect.Func {
335 return fmt.Errorf("expected func, got: %v", ft)
338 return fmt.Errorf("expected three 'in' params, got: %v", ft)
340 if ft.NumOut() != 1 {
341 return fmt.Errorf("expected one 'out' param, got: %v", ft)
343 if ft.In(0).Kind() != reflect.Ptr {
344 return fmt.Errorf("expected pointer arg for 'in' param 0, got: %v", ft)
346 if ft.In(1).Kind() != reflect.Ptr {
347 return fmt.Errorf("expected pointer arg for 'in' param 1, got: %v", ft)
349 scopeType := Scope(nil)
350 if e, a := reflect.TypeOf(&scopeType).Elem(), ft.In(2); e != a {
351 return fmt.Errorf("expected '%v' arg for 'in' param 2, got '%v' (%v)", e, a, ft)
353 var forErrorType error
354 // This convolution is necessary, otherwise TypeOf picks up on the fact
355 // that forErrorType is nil.
356 errorType := reflect.TypeOf(&forErrorType).Elem()
357 if ft.Out(0) != errorType {
358 return fmt.Errorf("expected error return, got: %v", ft)
363 // RegisterConversionFunc registers a conversion func with the
364 // Converter. conversionFunc must take three parameters: a pointer to the input
365 // type, a pointer to the output type, and a conversion.Scope (which should be
366 // used if recursive conversion calls are desired). It must return an error.
369 // c.RegisterConversionFunc(
370 // func(in *Pod, out *v1.Pod, s Scope) error {
371 // // conversion logic...
374 // DEPRECATED: Will be removed in favor of RegisterUntypedConversionFunc
375 func (c *Converter) RegisterConversionFunc(conversionFunc interface{}) error {
376 return c.conversionFuncs.Add(conversionFunc)
379 // Similar to RegisterConversionFunc, but registers conversion function that were
380 // automatically generated.
381 // DEPRECATED: Will be removed in favor of RegisterGeneratedUntypedConversionFunc
382 func (c *Converter) RegisterGeneratedConversionFunc(conversionFunc interface{}) error {
383 return c.generatedConversionFuncs.Add(conversionFunc)
386 // RegisterUntypedConversionFunc registers a function that converts between a and b by passing objects of those
387 // types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce
388 // any other guarantee.
389 func (c *Converter) RegisterUntypedConversionFunc(a, b interface{}, fn ConversionFunc) error {
390 return c.conversionFuncs.AddUntyped(a, b, fn)
393 // RegisterGeneratedUntypedConversionFunc registers a function that converts between a and b by passing objects of those
394 // types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce
395 // any other guarantee.
396 func (c *Converter) RegisterGeneratedUntypedConversionFunc(a, b interface{}, fn ConversionFunc) error {
397 return c.generatedConversionFuncs.AddUntyped(a, b, fn)
400 // RegisterIgnoredConversion registers a "no-op" for conversion, where any requested
401 // conversion between from and to is ignored.
402 func (c *Converter) RegisterIgnoredConversion(from, to interface{}) error {
403 typeFrom := reflect.TypeOf(from)
404 typeTo := reflect.TypeOf(to)
405 if reflect.TypeOf(from).Kind() != reflect.Ptr {
406 return fmt.Errorf("expected pointer arg for 'from' param 0, got: %v", typeFrom)
408 if typeTo.Kind() != reflect.Ptr {
409 return fmt.Errorf("expected pointer arg for 'to' param 1, got: %v", typeTo)
411 c.ignoredConversions[typePair{typeFrom.Elem(), typeTo.Elem()}] = struct{}{}
415 // RegisterInputDefaults registers a field name mapping function, used when converting
416 // from maps to structs. Inputs to the conversion methods are checked for this type and a mapping
417 // applied automatically if the input matches in. A set of default flags for the input conversion
418 // may also be provided, which will be used when no explicit flags are requested.
419 func (c *Converter) RegisterInputDefaults(in interface{}, fn FieldMappingFunc, defaultFlags FieldMatchingFlags) error {
420 fv := reflect.ValueOf(in)
422 if ft.Kind() != reflect.Ptr {
423 return fmt.Errorf("expected pointer 'in' argument, got: %v", ft)
425 c.inputFieldMappingFuncs[ft] = fn
426 c.inputDefaultFlags[ft] = defaultFlags
430 // FieldMatchingFlags contains a list of ways in which struct fields could be
431 // copied. These constants may be | combined.
432 type FieldMatchingFlags int
435 // Loop through destination fields, search for matching source
436 // field to copy it from. Source fields with no corresponding
437 // destination field will be ignored. If SourceToDest is
438 // specified, this flag is ignored. If neither is specified,
439 // or no flags are passed, this flag is the default.
440 DestFromSource FieldMatchingFlags = 0
441 // Loop through source fields, search for matching dest field
442 // to copy it into. Destination fields with no corresponding
443 // source field will be ignored.
444 SourceToDest FieldMatchingFlags = 1 << iota
445 // Don't treat it as an error if the corresponding source or
446 // dest field can't be found.
448 // Don't require type names to match.
449 AllowDifferentFieldTypeNames
452 // IsSet returns true if the given flag or combination of flags is set.
453 func (f FieldMatchingFlags) IsSet(flag FieldMatchingFlags) bool {
454 if flag == DestFromSource {
455 // The bit logic doesn't work on the default value.
456 return f&SourceToDest != SourceToDest
458 return f&flag == flag
461 // Convert will translate src to dest if it knows how. Both must be pointers.
462 // If no conversion func is registered and the default copying mechanism
463 // doesn't work on this type pair, an error will be returned.
464 // Read the comments on the various FieldMatchingFlags constants to understand
465 // what the 'flags' parameter does.
466 // 'meta' is given to allow you to pass information to conversion functions,
467 // it is not used by Convert() other than storing it in the scope.
468 // Not safe for objects with cyclic references!
469 func (c *Converter) Convert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error {
470 return c.doConversion(src, dest, flags, meta, c.convert)
473 // DefaultConvert will translate src to dest if it knows how. Both must be pointers.
474 // No conversion func is used. If the default copying mechanism
475 // doesn't work on this type pair, an error will be returned.
476 // Read the comments on the various FieldMatchingFlags constants to understand
477 // what the 'flags' parameter does.
478 // 'meta' is given to allow you to pass information to conversion functions,
479 // it is not used by DefaultConvert() other than storing it in the scope.
480 // Not safe for objects with cyclic references!
481 func (c *Converter) DefaultConvert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error {
482 return c.doConversion(src, dest, flags, meta, c.defaultConvert)
485 type conversionFunc func(sv, dv reflect.Value, scope *scope) error
487 func (c *Converter) doConversion(src, dest interface{}, flags FieldMatchingFlags, meta *Meta, f conversionFunc) error {
488 pair := typePair{reflect.TypeOf(src), reflect.TypeOf(dest)}
494 if fn, ok := c.conversionFuncs.untyped[pair]; ok {
495 return fn(src, dest, scope)
497 if fn, ok := c.generatedConversionFuncs.untyped[pair]; ok {
498 return fn(src, dest, scope)
500 // TODO: consider everything past this point deprecated - we want to support only point to point top level
503 dv, err := EnforcePtr(dest)
507 if !dv.CanAddr() && !dv.CanSet() {
508 return fmt.Errorf("can't write to dest")
510 sv, err := EnforcePtr(src)
514 // Leave something on the stack, so that calls to struct tag getters never fail.
515 scope.srcStack.push(scopeStackElem{})
516 scope.destStack.push(scopeStackElem{})
517 return f(sv, dv, scope)
520 // callCustom calls 'custom' with sv & dv. custom must be a conversion function.
521 func (c *Converter) callCustom(sv, dv, custom reflect.Value, scope *scope) error {
523 sv2 := reflect.New(sv.Type())
531 return scope.errorf("can't addr or set dest.")
534 dv := reflect.New(dvOrig.Type())
535 defer func() { dvOrig.Set(dv) }()
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
549 // convert recursively copies sv into dv, calling an appropriate conversion function if
550 // one is registered.
551 func (c *Converter) convert(sv, dv reflect.Value, scope *scope) error {
552 dt, st := dv.Type(), sv.Type()
553 pair := typePair{st, dt}
555 // ignore conversions of this type
556 if _, ok := c.ignoredConversions[pair]; ok {
558 c.Debug.Logf("Ignoring conversion of '%v' to '%v'", st, dt)
564 if fv, ok := c.conversionFuncs.fns[pair]; ok {
566 c.Debug.Logf("Calling custom conversion of '%v' to '%v'", st, dt)
568 return c.callCustom(sv, dv, fv, scope)
570 if fv, ok := c.generatedConversionFuncs.fns[pair]; ok {
572 c.Debug.Logf("Calling generated conversion of '%v' to '%v'", st, dt)
574 return c.callCustom(sv, dv, fv, scope)
577 return c.defaultConvert(sv, dv, scope)
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)
582 func (c *Converter) defaultConvert(sv, dv reflect.Value, scope *scope) error {
583 dt, st := dv.Type(), sv.Type()
586 return scope.errorf("Cannot set dest. (Tried to deep copy something with unexported fields?)")
589 if !scope.flags.IsSet(AllowDifferentFieldTypeNames) && c.nameFunc(dt) != c.nameFunc(st) {
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)
596 case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct:
597 // Don't copy these via assignment/conversion!
599 // This should handle all simple types.
600 if st.AssignableTo(dt) {
604 if st.ConvertibleTo(dt) {
605 dv.Set(sv.Convert(dt))
611 c.Debug.Logf("Trying to convert '%v' to '%v'", st, dt)
614 scope.srcStack.push(scopeStackElem{value: sv})
615 scope.destStack.push(scopeStackElem{value: dv})
616 defer scope.srcStack.pop()
617 defer scope.destStack.pop()
621 return c.convertKV(toKVValue(sv), toKVValue(dv), scope)
624 // Don't make a zero-length slice.
625 dv.Set(reflect.Zero(dt))
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 {
637 // Don't copy a nil ptr!
638 dv.Set(reflect.Zero(dt))
641 dv.Set(reflect.New(dt.Elem()))
643 case reflect.Ptr, reflect.Interface:
644 return c.convert(sv.Elem(), dv.Elem(), scope)
646 return c.convert(sv, dv.Elem(), scope)
650 // Don't copy a nil ptr!
651 dv.Set(reflect.Zero(dt))
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 {
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 {
669 dv.SetMapIndex(dk, dkv)
671 case reflect.Interface:
673 // Don't copy a nil interface!
674 dv.Set(reflect.Zero(dt))
677 tmpdv := reflect.New(sv.Elem().Type()).Elem()
678 if err := c.convert(sv.Elem(), tmpdv, scope); err != nil {
681 dv.Set(reflect.ValueOf(tmpdv.Interface()))
684 return scope.errorf("couldn't copy '%v' into '%v'; didn't understand types", st, dt)
689 var stringType = reflect.TypeOf("")
691 func toKVValue(v reflect.Value) kvValue {
694 return structAdaptor(v)
696 if v.Type().Key().AssignableTo(stringType) {
697 return stringMapAdaptor(v)
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.
706 type kvValue interface {
707 // returns all keys, as a []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
718 type stringMapAdaptor reflect.Value
720 func (a stringMapAdaptor) len() int {
721 return reflect.Value(a).Len()
724 func (a stringMapAdaptor) keys() []string {
725 v := reflect.Value(a)
726 keys := make([]string, v.Len())
727 for i, v := range v.MapKeys() {
731 switch t := v.Interface().(type) {
739 func (a stringMapAdaptor) tagOf(key string) reflect.StructTag {
743 func (a stringMapAdaptor) value(key string) reflect.Value {
744 return reflect.Value(a).MapIndex(reflect.ValueOf(key))
747 func (a stringMapAdaptor) confirmSet(key string, v reflect.Value) bool {
751 type structAdaptor reflect.Value
753 func (a structAdaptor) len() int {
754 v := reflect.Value(a)
755 return v.Type().NumField()
758 func (a structAdaptor) keys() []string {
759 v := reflect.Value(a)
761 keys := make([]string, t.NumField())
762 for i := range keys {
763 keys[i] = t.Field(i).Name
768 func (a structAdaptor) tagOf(key string) reflect.StructTag {
769 v := reflect.Value(a)
770 field, ok := v.Type().FieldByName(key)
777 func (a structAdaptor) value(key string) reflect.Value {
778 v := reflect.Value(a)
779 return v.FieldByName(key)
782 func (a structAdaptor) confirmSet(key string, v reflect.Value) bool {
786 // convertKV can convert things that consist of key/value pairs, like structs
788 func (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)
795 if scope.flags.IsSet(SourceToDest) {
799 var mapping FieldMappingFunc
800 if scope.meta != nil && scope.meta.KeyNameMapping != nil {
801 mapping = scope.meta.KeyNameMapping
804 for _, key := range lister.keys() {
805 if found, err := c.checkField(key, skv, dkv, scope); found {
811 stag := skv.tagOf(key)
812 dtag := dkv.tagOf(key)
816 skey, dkey = scope.meta.KeyNameMapping(key, stag, dtag)
819 df := dkv.value(dkey)
820 sf := skv.value(skey)
821 if !df.IsValid() || !sf.IsValid() {
823 case scope.flags.IsSet(IgnoreMissingFields):
825 case scope.flags.IsSet(SourceToDest):
826 return scope.errorf("%v not present in dest", dkey)
828 return scope.errorf("%v not present in src", skey)
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 {
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.
845 func (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)
852 destKey := typeNamePair{df.Type(), fieldName}
853 // Check each of the potential source (type, name) pairs to see if they're
855 for _, potentialSourceKey := range c.structFieldSources[destKey] {
856 sf := skv.value(potentialSourceKey.fieldName)
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 {
867 dkv.confirmSet(fieldName, df)
868 replacementMade = true
871 return replacementMade, nil
874 sf := skv.value(fieldName)
878 srcKey := typeNamePair{sf.Type(), fieldName}
879 // Check each of the potential dest (type, name) pairs to see if they're
881 for _, potentialDestKey := range c.structFieldDests[srcKey] {
882 df := dkv.value(potentialDestKey.fieldName)
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 {
893 dkv.confirmSet(potentialDestKey.fieldName, df)
894 replacementMade = true
897 return replacementMade, nil