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