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 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 62 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 67 68 // Map from an input type to a function which can apply a key name mapping 69 inputFieldMappingFuncs map[reflect.Type]FieldMappingFunc 70 71 // Map from an input type to a set of default conversion flags. 72 inputDefaultFlags map[reflect.Type]FieldMatchingFlags 73 74 // If non-nil, will be called to print helpful debugging info. Quite verbose. 75 Debug DebugLogger 76 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 81} 82 83// NewConverter creates a new Converter object. 84func NewConverter(nameFn NameFunc) *Converter { 85 c := &Converter{ 86 conversionFuncs: NewConversionFuncs(), 87 generatedConversionFuncs: NewConversionFuncs(), 88 ignoredConversions: make(map[typePair]struct{}), 89 nameFunc: nameFn, 90 structFieldDests: make(map[typeNamePair][]typeNamePair), 91 structFieldSources: make(map[typeNamePair][]typeNamePair), 92 93 inputFieldMappingFuncs: make(map[reflect.Type]FieldMappingFunc), 94 inputDefaultFlags: make(map[reflect.Type]FieldMatchingFlags), 95 } 96 c.RegisterConversionFunc(Convert_Slice_byte_To_Slice_byte) 97 return c 98} 99 100// WithConversions returns a Converter that is a copy of c but with the additional 101// fns merged on top. 102func (c *Converter) WithConversions(fns ConversionFuncs) *Converter { 103 copied := *c 104 copied.conversionFuncs = c.conversionFuncs.Merge(fns) 105 return &copied 106} 107 108// DefaultMeta returns the conversion FieldMappingFunc and meta for a given type. 109func (c *Converter) DefaultMeta(t reflect.Type) (FieldMatchingFlags, *Meta) { 110 return c.inputDefaultFlags[t], &Meta{ 111 KeyNameMapping: c.inputFieldMappingFuncs[t], 112 } 113} 114 115// Convert_Slice_byte_To_Slice_byte prevents recursing into every byte 116func Convert_Slice_byte_To_Slice_byte(in *[]byte, out *[]byte, s Scope) error { 117 if *in == nil { 118 *out = nil 119 return nil 120 } 121 *out = make([]byte, len(*in)) 122 copy(*out, *in) 123 return nil 124} 125 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. 129type 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 133 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 137 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 142 143 // Flags returns the flags with which the conversion was started. 144 Flags() FieldMatchingFlags 145 146 // Meta returns any information originally passed to Convert. 147 Meta() *Meta 148} 149 150// FieldMappingFunc can convert an input field value into different values, depending on 151// the value of the source or destination struct tags. 152type FieldMappingFunc func(key string, sourceTag, destTag reflect.StructTag) (source string, dest string) 153 154func NewConversionFuncs() ConversionFuncs { 155 return ConversionFuncs{ 156 fns: make(map[typePair]reflect.Value), 157 untyped: make(map[typePair]ConversionFunc), 158 } 159} 160 161type ConversionFuncs struct { 162 fns map[typePair]reflect.Value 163 untyped map[typePair]ConversionFunc 164} 165 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. 169func (c ConversionFuncs) Add(fns ...interface{}) error { 170 for _, fn := range fns { 171 fv := reflect.ValueOf(fn) 172 ft := fv.Type() 173 if err := verifyConversionFunctionSignature(ft); err != nil { 174 return err 175 } 176 c.fns[typePair{ft.In(0).Elem(), ft.In(1).Elem()}] = fv 177 } 178 return nil 179} 180 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. 184func (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) 188 } 189 if tB.Kind() != reflect.Ptr { 190 return fmt.Errorf("the type %T must be a pointer to register as an untyped conversion", b) 191 } 192 c.untyped[typePair{tA, tB}] = fn 193 return nil 194} 195 196// Merge returns a new ConversionFuncs that contains all conversions from 197// both other and c, with other conversions taking precedence. 198func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs { 199 merged := NewConversionFuncs() 200 for k, v := range c.fns { 201 merged.fns[k] = v 202 } 203 for k, v := range other.fns { 204 merged.fns[k] = v 205 } 206 for k, v := range c.untyped { 207 merged.untyped[k] = v 208 } 209 for k, v := range other.untyped { 210 merged.untyped[k] = v 211 } 212 return merged 213} 214 215// Meta is supplied by Scheme, when it calls Convert. 216type Meta struct { 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. 221 Context interface{} 222} 223 224// scope contains information about an ongoing conversion. 225type scope struct { 226 converter *Converter 227 meta *Meta 228 flags FieldMatchingFlags 229 230 // srcStack & destStack are separate because they may not have a 1:1 231 // relationship. 232 srcStack scopeStack 233 destStack scopeStack 234} 235 236type scopeStackElem struct { 237 tag reflect.StructTag 238 value reflect.Value 239 key string 240} 241 242type scopeStack []scopeStackElem 243 244func (s *scopeStack) pop() { 245 n := len(*s) 246 *s = (*s)[:n-1] 247} 248 249func (s *scopeStack) push(e scopeStackElem) { 250 *s = append(*s, e) 251} 252 253func (s *scopeStack) top() *scopeStackElem { 254 return &(*s)[len(*s)-1] 255} 256 257func (s scopeStack) describe() string { 258 desc := "" 259 if len(s) > 1 { 260 desc = "(" + s[1].value.Type().String() + ")" 261 } 262 for i, v := range s { 263 if i < 2 { 264 // First layer on stack is not real; second is handled specially above. 265 continue 266 } 267 if v.key == "" { 268 desc += fmt.Sprintf(".%v", v.value.Type()) 269 } else { 270 desc += fmt.Sprintf(".%v", v.key) 271 } 272 } 273 return desc 274} 275 276// Formats src & dest as indices for printing. 277func (s *scope) setIndices(src, dest int) { 278 s.srcStack.top().key = fmt.Sprintf("[%v]", src) 279 s.destStack.top().key = fmt.Sprintf("[%v]", dest) 280} 281 282// Formats src & dest as map keys for printing. 283func (s *scope) setKeys(src, dest interface{}) { 284 s.srcStack.top().key = fmt.Sprintf(`["%v"]`, src) 285 s.destStack.top().key = fmt.Sprintf(`["%v"]`, dest) 286} 287 288// Convert continues a conversion. 289func (s *scope) Convert(src, dest interface{}, flags FieldMatchingFlags) error { 290 return s.converter.Convert(src, dest, flags, s.meta) 291} 292 293// DefaultConvert continues a conversion, performing a default conversion (no conversion func) 294// for the current stack frame. 295func (s *scope) DefaultConvert(src, dest interface{}, flags FieldMatchingFlags) error { 296 return s.converter.DefaultConvert(src, dest, flags, s.meta) 297} 298 299// SrcTag returns the tag of the struct containing the current source item, if any. 300func (s *scope) SrcTag() reflect.StructTag { 301 return s.srcStack.top().tag 302} 303 304// DestTag returns the tag of the struct containing the current dest item, if any. 305func (s *scope) DestTag() reflect.StructTag { 306 return s.destStack.top().tag 307} 308 309// Flags returns the flags with which the current conversion was started. 310func (s *scope) Flags() FieldMatchingFlags { 311 return s.flags 312} 313 314// Meta returns the meta object that was originally passed to Convert. 315func (s *scope) Meta() *Meta { 316 return s.meta 317} 318 319// describe prints the path to get to the current (source, dest) values. 320func (s *scope) describe() (src, dest string) { 321 return s.srcStack.describe(), s.destStack.describe() 322} 323 324// error makes an error that includes information about where we were in the objects 325// we were asked to convert. 326func (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...) 330} 331 332// Verifies whether a conversion function has a correct signature. 333func verifyConversionFunctionSignature(ft reflect.Type) error { 334 if ft.Kind() != reflect.Func { 335 return fmt.Errorf("expected func, got: %v", ft) 336 } 337 if ft.NumIn() != 3 { 338 return fmt.Errorf("expected three 'in' params, got: %v", ft) 339 } 340 if ft.NumOut() != 1 { 341 return fmt.Errorf("expected one 'out' param, got: %v", ft) 342 } 343 if ft.In(0).Kind() != reflect.Ptr { 344 return fmt.Errorf("expected pointer arg for 'in' param 0, got: %v", ft) 345 } 346 if ft.In(1).Kind() != reflect.Ptr { 347 return fmt.Errorf("expected pointer arg for 'in' param 1, got: %v", ft) 348 } 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) 352 } 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) 359 } 360 return nil 361} 362 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. 367// 368// Example: 369// c.RegisterConversionFunc( 370// func(in *Pod, out *v1.Pod, s Scope) error { 371// // conversion logic... 372// return nil 373// }) 374// DEPRECATED: Will be removed in favor of RegisterUntypedConversionFunc 375func (c *Converter) RegisterConversionFunc(conversionFunc interface{}) error { 376 return c.conversionFuncs.Add(conversionFunc) 377} 378 379// Similar to RegisterConversionFunc, but registers conversion function that were 380// automatically generated. 381// DEPRECATED: Will be removed in favor of RegisterGeneratedUntypedConversionFunc 382func (c *Converter) RegisterGeneratedConversionFunc(conversionFunc interface{}) error { 383 return c.generatedConversionFuncs.Add(conversionFunc) 384} 385 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. 389func (c *Converter) RegisterUntypedConversionFunc(a, b interface{}, fn ConversionFunc) error { 390 return c.conversionFuncs.AddUntyped(a, b, fn) 391} 392 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. 396func (c *Converter) RegisterGeneratedUntypedConversionFunc(a, b interface{}, fn ConversionFunc) error { 397 return c.generatedConversionFuncs.AddUntyped(a, b, fn) 398} 399 400// RegisterIgnoredConversion registers a "no-op" for conversion, where any requested 401// conversion between from and to is ignored. 402func (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) 407 } 408 if typeTo.Kind() != reflect.Ptr { 409 return fmt.Errorf("expected pointer arg for 'to' param 1, got: %v", typeTo) 410 } 411 c.ignoredConversions[typePair{typeFrom.Elem(), typeTo.Elem()}] = struct{}{} 412 return nil 413} 414 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. 419func (c *Converter) RegisterInputDefaults(in interface{}, fn FieldMappingFunc, defaultFlags FieldMatchingFlags) error { 420 fv := reflect.ValueOf(in) 421 ft := fv.Type() 422 if ft.Kind() != reflect.Ptr { 423 return fmt.Errorf("expected pointer 'in' argument, got: %v", ft) 424 } 425 c.inputFieldMappingFuncs[ft] = fn 426 c.inputDefaultFlags[ft] = defaultFlags 427 return nil 428} 429 430// FieldMatchingFlags contains a list of ways in which struct fields could be 431// copied. These constants may be | combined. 432type FieldMatchingFlags int 433 434const ( 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. 447 IgnoreMissingFields 448 // Don't require type names to match. 449 AllowDifferentFieldTypeNames 450) 451 452// IsSet returns true if the given flag or combination of flags is set. 453func (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 457 } 458 return f&flag == flag 459} 460 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! 469func (c *Converter) Convert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error { 470 return c.doConversion(src, dest, flags, meta, c.convert) 471} 472 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! 481func (c *Converter) DefaultConvert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error { 482 return c.doConversion(src, dest, flags, meta, c.defaultConvert) 483} 484 485type conversionFunc func(sv, dv reflect.Value, scope *scope) error 486 487func (c *Converter) doConversion(src, dest interface{}, flags FieldMatchingFlags, meta *Meta, f conversionFunc) error { 488 pair := typePair{reflect.TypeOf(src), reflect.TypeOf(dest)} 489 scope := &scope{ 490 converter: c, 491 flags: flags, 492 meta: meta, 493 } 494 if fn, ok := c.conversionFuncs.untyped[pair]; ok { 495 return fn(src, dest, scope) 496 } 497 if fn, ok := c.generatedConversionFuncs.untyped[pair]; ok { 498 return fn(src, dest, scope) 499 } 500 // TODO: consider everything past this point deprecated - we want to support only point to point top level 501 // conversions 502 503 dv, err := EnforcePtr(dest) 504 if err != nil { 505 return err 506 } 507 if !dv.CanAddr() && !dv.CanSet() { 508 return fmt.Errorf("can't write to dest") 509 } 510 sv, err := EnforcePtr(src) 511 if err != nil { 512 return err 513 } 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) 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} 899