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