github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/k8s.io/kubernetes/pkg/runtime/conversion_generator.go (about) 1 /* 2 Copyright 2015 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 runtime 18 19 import ( 20 "fmt" 21 "io" 22 "path" 23 "reflect" 24 "sort" 25 "strings" 26 27 "k8s.io/kubernetes/pkg/conversion" 28 "k8s.io/kubernetes/pkg/util/sets" 29 ) 30 31 type ConversionGenerator interface { 32 GenerateConversionsForType(version string, reflection reflect.Type) error 33 WriteConversionFunctions(w io.Writer) error 34 RegisterConversionFunctions(w io.Writer, pkg string) error 35 AddImport(pkg string) string 36 RepackImports(exclude sets.String) 37 WriteImports(w io.Writer) error 38 OverwritePackage(pkg, overwrite string) 39 AssumePrivateConversions() 40 } 41 42 func NewConversionGenerator(scheme *conversion.Scheme, targetPkg string) ConversionGenerator { 43 g := &conversionGenerator{ 44 scheme: scheme, 45 targetPkg: targetPkg, 46 convertibles: make(map[reflect.Type]reflect.Type), 47 overridden: make(map[reflect.Type]bool), 48 pkgOverwrites: make(map[string]string), 49 imports: make(map[string]string), 50 shortImports: make(map[string]string), 51 } 52 g.targetPackage(targetPkg) 53 g.AddImport("reflect") 54 g.AddImport("k8s.io/kubernetes/pkg/conversion") 55 return g 56 } 57 58 var complexTypes []reflect.Kind = []reflect.Kind{reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct} 59 60 type conversionGenerator struct { 61 scheme *conversion.Scheme 62 targetPkg string 63 convertibles map[reflect.Type]reflect.Type 64 overridden map[reflect.Type]bool 65 // If pkgOverwrites is set for a given package name, that package name 66 // will be replaced while writing conversion function. If empty, package 67 // name will be omitted. 68 pkgOverwrites map[string]string 69 // map of package names to shortname 70 imports map[string]string 71 // map of short names to package names 72 shortImports map[string]string 73 74 // A buffer that is used for storing lines that needs to be written. 75 linesToPrint []string 76 77 // if true, we assume conversions on the scheme are not available to us in the current package 78 assumePrivateConversions bool 79 } 80 81 func (g *conversionGenerator) AssumePrivateConversions() { 82 g.assumePrivateConversions = true 83 } 84 85 func (g *conversionGenerator) AddImport(pkg string) string { 86 return g.addImportByPath(pkg) 87 } 88 89 func (g *conversionGenerator) GenerateConversionsForType(version string, reflection reflect.Type) error { 90 kind := reflection.Name() 91 internalObj, err := g.scheme.NewObject(g.scheme.InternalVersion, kind) 92 if err != nil { 93 return fmt.Errorf("cannot create an object of type %v in internal version", kind) 94 } 95 internalObjType := reflect.TypeOf(internalObj) 96 if internalObjType.Kind() != reflect.Ptr { 97 return fmt.Errorf("created object should be of type Ptr: %v", internalObjType.Kind()) 98 } 99 inErr := g.generateConversionsBetween(reflection, internalObjType.Elem()) 100 outErr := g.generateConversionsBetween(internalObjType.Elem(), reflection) 101 if inErr != nil || outErr != nil { 102 return fmt.Errorf("errors: %v, %v", inErr, outErr) 103 } 104 return nil 105 } 106 107 func (g *conversionGenerator) generateConversionsBetween(inType, outType reflect.Type) error { 108 existingConversion := g.scheme.Converter().HasConversionFunc(inType, outType) && g.scheme.Converter().HasConversionFunc(outType, inType) 109 110 // Avoid processing the same type multiple times. 111 if value, found := g.convertibles[inType]; found { 112 if value != outType { 113 return fmt.Errorf("multiple possible convertibles for %v", inType) 114 } 115 return nil 116 } 117 if inType == outType { 118 // Don't generate conversion methods for the same type. 119 return nil 120 } 121 122 if inType.Kind() != outType.Kind() { 123 if existingConversion { 124 return nil 125 } 126 return fmt.Errorf("cannot convert types of different kinds: %v %v", inType, outType) 127 } 128 129 g.addImportByPath(inType.PkgPath()) 130 g.addImportByPath(outType.PkgPath()) 131 132 // We should be able to generate conversions both sides. 133 switch inType.Kind() { 134 case reflect.Map: 135 inErr := g.generateConversionsForMap(inType, outType) 136 outErr := g.generateConversionsForMap(outType, inType) 137 if !existingConversion && (inErr != nil || outErr != nil) { 138 return inErr 139 } 140 // We don't add it to g.convertibles - maps should be handled correctly 141 // inside appropriate conversion functions. 142 return nil 143 case reflect.Ptr: 144 inErr := g.generateConversionsBetween(inType.Elem(), outType.Elem()) 145 outErr := g.generateConversionsBetween(outType.Elem(), inType.Elem()) 146 if !existingConversion && (inErr != nil || outErr != nil) { 147 return inErr 148 } 149 // We don't add it to g.convertibles - maps should be handled correctly 150 // inside appropriate conversion functions. 151 return nil 152 case reflect.Slice: 153 inErr := g.generateConversionsForSlice(inType, outType) 154 outErr := g.generateConversionsForSlice(outType, inType) 155 if !existingConversion && (inErr != nil || outErr != nil) { 156 return inErr 157 } 158 // We don't add it to g.convertibles - slices should be handled correctly 159 // inside appropriate conversion functions. 160 return nil 161 case reflect.Interface: 162 // TODO(wojtek-t): Currently we don't support converting interfaces. 163 return fmt.Errorf("interfaces are not supported") 164 case reflect.Struct: 165 inErr := g.generateConversionsForStruct(inType, outType) 166 outErr := g.generateConversionsForStruct(outType, inType) 167 if !existingConversion && (inErr != nil || outErr != nil) { 168 return inErr 169 } 170 if existingConversion { 171 g.overridden[inType] = true 172 } 173 g.convertibles[inType] = outType 174 return nil 175 default: 176 // All simple types should be handled correctly with default conversion. 177 return nil 178 } 179 } 180 181 func isComplexType(reflection reflect.Type) bool { 182 for _, complexType := range complexTypes { 183 if complexType == reflection.Kind() { 184 return true 185 } 186 } 187 return false 188 } 189 190 func (g *conversionGenerator) generateConversionsForMap(inType, outType reflect.Type) error { 191 inKey := inType.Key() 192 outKey := outType.Key() 193 g.addImportByPath(inKey.PkgPath()) 194 g.addImportByPath(outKey.PkgPath()) 195 if err := g.generateConversionsBetween(inKey, outKey); err != nil { 196 return err 197 } 198 inValue := inType.Elem() 199 outValue := outType.Elem() 200 g.addImportByPath(inValue.PkgPath()) 201 g.addImportByPath(outValue.PkgPath()) 202 if err := g.generateConversionsBetween(inValue, outValue); err != nil { 203 return err 204 } 205 return nil 206 } 207 208 func (g *conversionGenerator) generateConversionsForSlice(inType, outType reflect.Type) error { 209 inElem := inType.Elem() 210 outElem := outType.Elem() 211 if err := g.generateConversionsBetween(inElem, outElem); err != nil { 212 return err 213 } 214 return nil 215 } 216 217 func (g *conversionGenerator) generateConversionsForStruct(inType, outType reflect.Type) error { 218 for i := 0; i < inType.NumField(); i++ { 219 inField := inType.Field(i) 220 outField, found := outType.FieldByName(inField.Name) 221 if !found { 222 return fmt.Errorf("couldn't find a corresponding field %v in %v", inField.Name, outType) 223 } 224 if isComplexType(inField.Type) { 225 if err := g.generateConversionsBetween(inField.Type, outField.Type); err != nil { 226 return err 227 } 228 } 229 } 230 return nil 231 } 232 233 // A buffer of lines that will be written. 234 type bufferedLine struct { 235 line string 236 indentation int 237 } 238 239 type buffer struct { 240 lines []bufferedLine 241 } 242 243 func newBuffer() *buffer { 244 return &buffer{ 245 lines: make([]bufferedLine, 0), 246 } 247 } 248 249 func (b *buffer) addLine(line string, indent int) { 250 b.lines = append(b.lines, bufferedLine{line, indent}) 251 } 252 253 func (b *buffer) flushLines(w io.Writer) error { 254 for _, line := range b.lines { 255 indentation := strings.Repeat("\t", line.indentation) 256 fullLine := fmt.Sprintf("%s%s", indentation, line.line) 257 if _, err := io.WriteString(w, fullLine); err != nil { 258 return err 259 } 260 } 261 return nil 262 } 263 264 type byName []reflect.Type 265 266 func (s byName) Len() int { 267 return len(s) 268 } 269 270 func (s byName) Less(i, j int) bool { 271 fullNameI := s[i].PkgPath() + "/" + s[i].Name() 272 fullNameJ := s[j].PkgPath() + "/" + s[j].Name() 273 return fullNameI < fullNameJ 274 } 275 276 func (s byName) Swap(i, j int) { 277 s[i], s[j] = s[j], s[i] 278 } 279 280 func (g *conversionGenerator) targetPackage(pkg string) { 281 g.imports[pkg] = "" 282 g.shortImports[""] = pkg 283 } 284 285 func (g *conversionGenerator) RepackImports(exclude sets.String) { 286 var packages []string 287 for key := range g.imports { 288 packages = append(packages, key) 289 } 290 sort.Strings(packages) 291 g.imports = make(map[string]string) 292 g.shortImports = make(map[string]string) 293 g.targetPackage(g.targetPkg) 294 for _, pkg := range packages { 295 if !exclude.Has(pkg) { 296 g.addImportByPath(pkg) 297 } 298 } 299 } 300 301 func (g *conversionGenerator) WriteImports(w io.Writer) error { 302 var packages []string 303 for key := range g.imports { 304 packages = append(packages, key) 305 } 306 sort.Strings(packages) 307 308 buffer := newBuffer() 309 indent := 0 310 buffer.addLine("import (\n", indent) 311 for _, importPkg := range packages { 312 if len(importPkg) == 0 { 313 continue 314 } 315 if len(g.imports[importPkg]) == 0 { 316 continue 317 } 318 buffer.addLine(fmt.Sprintf("%s \"%s\"\n", g.imports[importPkg], importPkg), indent+1) 319 } 320 buffer.addLine(")\n", indent) 321 buffer.addLine("\n", indent) 322 if err := buffer.flushLines(w); err != nil { 323 return err 324 } 325 return nil 326 } 327 328 func (g *conversionGenerator) WriteConversionFunctions(w io.Writer) error { 329 // It's desired to print conversion functions always in the same order 330 // (e.g. for better tracking of what has really been added). 331 var keys []reflect.Type 332 for key := range g.convertibles { 333 keys = append(keys, key) 334 } 335 sort.Sort(byName(keys)) 336 337 buffer := newBuffer() 338 indent := 0 339 for _, inType := range keys { 340 outType := g.convertibles[inType] 341 // All types in g.convertibles are structs. 342 if inType.Kind() != reflect.Struct { 343 return fmt.Errorf("non-struct conversions are not-supported") 344 } 345 if err := g.writeConversionForType(buffer, inType, outType, indent); err != nil { 346 return err 347 } 348 } 349 if err := buffer.flushLines(w); err != nil { 350 return err 351 } 352 return nil 353 } 354 355 func (g *conversionGenerator) writeRegisterHeader(b *buffer, pkg string, indent int) { 356 b.addLine("func init() {\n", indent) 357 b.addLine(fmt.Sprintf("err := %s.AddGeneratedConversionFuncs(\n", pkg), indent+1) 358 } 359 360 func (g *conversionGenerator) writeRegisterFooter(b *buffer, indent int) { 361 b.addLine(")\n", indent+1) 362 b.addLine("if err != nil {\n", indent+1) 363 b.addLine("// If one of the conversion functions is malformed, detect it immediately.\n", indent+2) 364 b.addLine("panic(err)\n", indent+2) 365 b.addLine("}\n", indent+1) 366 b.addLine("}\n", indent) 367 b.addLine("\n", indent) 368 } 369 370 func (g *conversionGenerator) RegisterConversionFunctions(w io.Writer, pkg string) error { 371 // Write conversion function names alphabetically ordered. 372 var names []string 373 for inType, outType := range g.convertibles { 374 names = append(names, g.generatedFunctionName(inType, outType)) 375 } 376 sort.Strings(names) 377 378 buffer := newBuffer() 379 indent := 0 380 g.writeRegisterHeader(buffer, pkg, indent) 381 for _, name := range names { 382 buffer.addLine(fmt.Sprintf("%s,\n", name), indent+2) 383 } 384 g.writeRegisterFooter(buffer, indent) 385 if err := buffer.flushLines(w); err != nil { 386 return err 387 } 388 return nil 389 } 390 391 func (g *conversionGenerator) addImportByPath(pkg string) string { 392 if name, ok := g.imports[pkg]; ok { 393 return name 394 } 395 name := path.Base(pkg) 396 if _, ok := g.shortImports[name]; !ok { 397 g.imports[pkg] = name 398 g.shortImports[name] = pkg 399 return name 400 } 401 if dirname := path.Base(path.Dir(pkg)); len(dirname) > 0 { 402 name = dirname + name 403 if _, ok := g.shortImports[name]; !ok { 404 g.imports[pkg] = name 405 g.shortImports[name] = pkg 406 return name 407 } 408 if subdirname := path.Base(path.Dir(path.Dir(pkg))); len(subdirname) > 0 { 409 name = subdirname + name 410 if _, ok := g.shortImports[name]; !ok { 411 g.imports[pkg] = name 412 g.shortImports[name] = pkg 413 return name 414 } 415 } 416 } 417 for i := 2; i < 100; i++ { 418 generatedName := fmt.Sprintf("%s%d", name, i) 419 if _, ok := g.shortImports[generatedName]; !ok { 420 g.imports[pkg] = generatedName 421 g.shortImports[generatedName] = pkg 422 return generatedName 423 } 424 } 425 panic(fmt.Sprintf("unable to find a unique name for the package path %q: %v", pkg, g.shortImports)) 426 } 427 428 func (g *conversionGenerator) typeName(inType reflect.Type) string { 429 switch inType.Kind() { 430 case reflect.Slice: 431 return fmt.Sprintf("[]%s", g.typeName(inType.Elem())) 432 case reflect.Ptr: 433 return fmt.Sprintf("*%s", g.typeName(inType.Elem())) 434 case reflect.Map: 435 if len(inType.Name()) == 0 { 436 return fmt.Sprintf("map[%s]%s", g.typeName(inType.Key()), g.typeName(inType.Elem())) 437 } 438 fallthrough 439 default: 440 pkg, name := inType.PkgPath(), inType.Name() 441 if len(name) == 0 && inType.Kind() == reflect.Struct { 442 return "struct{}" 443 } 444 if len(pkg) == 0 { 445 // Default package. 446 return name 447 } 448 if val, found := g.pkgOverwrites[pkg]; found { 449 pkg = val 450 } 451 if len(pkg) == 0 { 452 return name 453 } 454 short := g.addImportByPath(pkg) 455 if len(short) > 0 { 456 return fmt.Sprintf("%s.%s", short, name) 457 } 458 return name 459 } 460 } 461 462 func (g *conversionGenerator) writeDefaultingFunc(b *buffer, inType reflect.Type, indent int) error { 463 getStmt := "if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {\n" 464 b.addLine(getStmt, indent) 465 callFormat := "defaulting.(func(*%s))(in)\n" 466 callStmt := fmt.Sprintf(callFormat, g.typeName(inType)) 467 b.addLine(callStmt, indent+1) 468 b.addLine("}\n", indent) 469 return nil 470 } 471 472 func packageForName(inType reflect.Type) string { 473 if inType.PkgPath() == "" { 474 return "" 475 } 476 slices := strings.Split(inType.PkgPath(), "/") 477 return slices[len(slices)-1] 478 } 479 480 func (g *conversionGenerator) conversionFunctionName(inType, outType reflect.Type) string { 481 funcNameFormat := "convert_%s_%s_To_%s_%s" 482 inPkg := packageForName(inType) 483 outPkg := packageForName(outType) 484 funcName := fmt.Sprintf(funcNameFormat, inPkg, inType.Name(), outPkg, outType.Name()) 485 return funcName 486 } 487 488 func (g *conversionGenerator) generatedFunctionName(inType, outType reflect.Type) string { 489 return "auto" + g.conversionFunctionName(inType, outType) 490 } 491 492 func (g *conversionGenerator) writeHeader(b *buffer, name, inType, outType string, indent int) { 493 format := "func %s(in *%s, out *%s, s conversion.Scope) error {\n" 494 stmt := fmt.Sprintf(format, name, inType, outType) 495 b.addLine(stmt, indent) 496 } 497 498 func (g *conversionGenerator) writeFooter(b *buffer, indent int) { 499 b.addLine("return nil\n", indent+1) 500 b.addLine("}\n", indent) 501 } 502 503 func (g *conversionGenerator) writeConversionForMap(b *buffer, inField, outField reflect.StructField, indent int) error { 504 ifFormat := "if in.%s != nil {\n" 505 ifStmt := fmt.Sprintf(ifFormat, inField.Name) 506 b.addLine(ifStmt, indent) 507 makeFormat := "out.%s = make(%s)\n" 508 makeStmt := fmt.Sprintf(makeFormat, outField.Name, g.typeName(outField.Type)) 509 b.addLine(makeStmt, indent+1) 510 forFormat := "for key, val := range in.%s {\n" 511 forStmt := fmt.Sprintf(forFormat, inField.Name) 512 b.addLine(forStmt, indent+1) 513 514 // Whether we need to explicitly create a new value. 515 newValue := false 516 if isComplexType(inField.Type.Elem()) || !inField.Type.Elem().ConvertibleTo(outField.Type.Elem()) { 517 newValue = true 518 newFormat := "newVal := %s{}\n" 519 newStmt := fmt.Sprintf(newFormat, g.typeName(outField.Type.Elem())) 520 b.addLine(newStmt, indent+2) 521 convertStmt := "if err := s.Convert(&val, &newVal, 0); err != nil {\n" 522 b.addLine(convertStmt, indent+2) 523 b.addLine("return err\n", indent+3) 524 b.addLine("}\n", indent+2) 525 } 526 if inField.Type.Key().ConvertibleTo(outField.Type.Key()) { 527 value := "val" 528 if newValue { 529 value = "newVal" 530 } 531 assignStmt := "" 532 if inField.Type.Key().AssignableTo(outField.Type.Key()) { 533 assignStmt = fmt.Sprintf("out.%s[key] = %s\n", outField.Name, value) 534 } else { 535 assignStmt = fmt.Sprintf("out.%s[%s(key)] = %s\n", outField.Name, g.typeName(outField.Type.Key()), value) 536 } 537 b.addLine(assignStmt, indent+2) 538 } else { 539 // TODO(wojtek-t): Support maps with keys that are non-convertible to each other. 540 return fmt.Errorf("conversions between unconvertible keys in map are not supported.") 541 } 542 b.addLine("}\n", indent+1) 543 b.addLine("} else {\n", indent) 544 nilFormat := "out.%s = nil\n" 545 nilStmt := fmt.Sprintf(nilFormat, outField.Name) 546 b.addLine(nilStmt, indent+1) 547 b.addLine("}\n", indent) 548 return nil 549 } 550 551 func (g *conversionGenerator) writeConversionForSlice(b *buffer, inField, outField reflect.StructField, indent int) error { 552 ifFormat := "if in.%s != nil {\n" 553 ifStmt := fmt.Sprintf(ifFormat, inField.Name) 554 b.addLine(ifStmt, indent) 555 makeFormat := "out.%s = make(%s, len(in.%s))\n" 556 makeStmt := fmt.Sprintf(makeFormat, outField.Name, g.typeName(outField.Type), inField.Name) 557 b.addLine(makeStmt, indent+1) 558 forFormat := "for i := range in.%s {\n" 559 forStmt := fmt.Sprintf(forFormat, inField.Name) 560 b.addLine(forStmt, indent+1) 561 562 assigned := false 563 switch inField.Type.Elem().Kind() { 564 case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct: 565 // Don't copy these via assignment/conversion! 566 default: 567 // This should handle all simple types. 568 if inField.Type.Elem().AssignableTo(outField.Type.Elem()) { 569 assignFormat := "out.%s[i] = in.%s[i]\n" 570 assignStmt := fmt.Sprintf(assignFormat, outField.Name, inField.Name) 571 b.addLine(assignStmt, indent+2) 572 assigned = true 573 } else if inField.Type.Elem().ConvertibleTo(outField.Type.Elem()) { 574 assignFormat := "out.%s[i] = %s(in.%s[i])\n" 575 assignStmt := fmt.Sprintf(assignFormat, outField.Name, g.typeName(outField.Type.Elem()), inField.Name) 576 b.addLine(assignStmt, indent+2) 577 assigned = true 578 } 579 } 580 if !assigned { 581 assignStmt := "" 582 if g.existsDedicatedConversionFunction(inField.Type.Elem(), outField.Type.Elem()) { 583 assignFormat := "if err := %s(&in.%s[i], &out.%s[i], s); err != nil {\n" 584 funcName := g.conversionFunctionName(inField.Type.Elem(), outField.Type.Elem()) 585 assignStmt = fmt.Sprintf(assignFormat, funcName, inField.Name, outField.Name) 586 } else { 587 assignFormat := "if err := s.Convert(&in.%s[i], &out.%s[i], 0); err != nil {\n" 588 assignStmt = fmt.Sprintf(assignFormat, inField.Name, outField.Name) 589 } 590 b.addLine(assignStmt, indent+2) 591 b.addLine("return err\n", indent+3) 592 b.addLine("}\n", indent+2) 593 } 594 b.addLine("}\n", indent+1) 595 b.addLine("} else {\n", indent) 596 nilFormat := "out.%s = nil\n" 597 nilStmt := fmt.Sprintf(nilFormat, outField.Name) 598 b.addLine(nilStmt, indent+1) 599 b.addLine("}\n", indent) 600 return nil 601 } 602 603 func (g *conversionGenerator) writeConversionForPtr(b *buffer, inField, outField reflect.StructField, indent int) error { 604 switch inField.Type.Elem().Kind() { 605 case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct: 606 // Don't copy these via assignment/conversion! 607 default: 608 // This should handle pointers to all simple types. 609 assignable := inField.Type.Elem().AssignableTo(outField.Type.Elem()) 610 convertible := inField.Type.Elem().ConvertibleTo(outField.Type.Elem()) 611 if assignable || convertible { 612 ifFormat := "if in.%s != nil {\n" 613 ifStmt := fmt.Sprintf(ifFormat, inField.Name) 614 b.addLine(ifStmt, indent) 615 newFormat := "out.%s = new(%s)\n" 616 newStmt := fmt.Sprintf(newFormat, outField.Name, g.typeName(outField.Type.Elem())) 617 b.addLine(newStmt, indent+1) 618 } 619 if assignable { 620 assignFormat := "*out.%s = *in.%s\n" 621 assignStmt := fmt.Sprintf(assignFormat, outField.Name, inField.Name) 622 b.addLine(assignStmt, indent+1) 623 } else if convertible { 624 assignFormat := "*out.%s = %s(*in.%s)\n" 625 assignStmt := fmt.Sprintf(assignFormat, outField.Name, g.typeName(outField.Type.Elem()), inField.Name) 626 b.addLine(assignStmt, indent+1) 627 } 628 if assignable || convertible { 629 b.addLine("} else {\n", indent) 630 nilFormat := "out.%s = nil\n" 631 nilStmt := fmt.Sprintf(nilFormat, outField.Name) 632 b.addLine(nilStmt, indent+1) 633 b.addLine("}\n", indent) 634 return nil 635 } 636 } 637 638 ifFormat := "if in.%s != nil {\n" 639 ifStmt := fmt.Sprintf(ifFormat, inField.Name) 640 b.addLine(ifStmt, indent) 641 assignStmt := "" 642 if g.existsDedicatedConversionFunction(inField.Type.Elem(), outField.Type.Elem()) { 643 newFormat := "out.%s = new(%s)\n" 644 newStmt := fmt.Sprintf(newFormat, outField.Name, g.typeName(outField.Type.Elem())) 645 b.addLine(newStmt, indent+1) 646 assignFormat := "if err := %s(in.%s, out.%s, s); err != nil {\n" 647 funcName := g.conversionFunctionName(inField.Type.Elem(), outField.Type.Elem()) 648 assignStmt = fmt.Sprintf(assignFormat, funcName, inField.Name, outField.Name) 649 } else { 650 assignFormat := "if err := s.Convert(&in.%s, &out.%s, 0); err != nil {\n" 651 assignStmt = fmt.Sprintf(assignFormat, inField.Name, outField.Name) 652 } 653 b.addLine(assignStmt, indent+1) 654 b.addLine("return err\n", indent+2) 655 b.addLine("}\n", indent+1) 656 b.addLine("} else {\n", indent) 657 nilFormat := "out.%s = nil\n" 658 nilStmt := fmt.Sprintf(nilFormat, outField.Name) 659 b.addLine(nilStmt, indent+1) 660 b.addLine("}\n", indent) 661 return nil 662 } 663 664 func (g *conversionGenerator) canTryConversion(b *buffer, inType reflect.Type, inField, outField reflect.StructField, indent int) (bool, error) { 665 if inField.Type.Kind() != outField.Type.Kind() { 666 if !g.overridden[inType] { 667 return false, fmt.Errorf("input %s.%s (%s) does not match output (%s) and conversion is not overridden", inType, inField.Name, inField.Type.Kind(), outField.Type.Kind()) 668 } 669 b.addLine(fmt.Sprintf("// in.%s has no peer in out\n", inField.Name), indent) 670 return false, nil 671 } 672 return true, nil 673 } 674 675 func (g *conversionGenerator) writeConversionForStruct(b *buffer, inType, outType reflect.Type, indent int) error { 676 for i := 0; i < inType.NumField(); i++ { 677 inField := inType.Field(i) 678 outField, found := outType.FieldByName(inField.Name) 679 if !found { 680 if !g.overridden[inType] { 681 return fmt.Errorf("input %s.%s has no peer in output %s and conversion is not overridden", inType, inField.Name, outType) 682 } 683 b.addLine(fmt.Sprintf("// in.%s has no peer in out\n", inField.Name), indent) 684 continue 685 } 686 687 existsConversion := g.scheme.Converter().HasConversionFunc(inField.Type, outField.Type) 688 if existsConversion && !g.existsDedicatedConversionFunction(inField.Type, outField.Type) { 689 // Use the conversion method that is already defined. 690 assignFormat := "if err := s.Convert(&in.%s, &out.%s, 0); err != nil {\n" 691 assignStmt := fmt.Sprintf(assignFormat, inField.Name, outField.Name) 692 b.addLine(assignStmt, indent) 693 b.addLine("return err\n", indent+1) 694 b.addLine("}\n", indent) 695 continue 696 } 697 698 switch inField.Type.Kind() { 699 case reflect.Map: 700 if try, err := g.canTryConversion(b, inType, inField, outField, indent); err != nil { 701 return err 702 } else if !try { 703 continue 704 } 705 if err := g.writeConversionForMap(b, inField, outField, indent); err != nil { 706 return err 707 } 708 continue 709 case reflect.Ptr: 710 if try, err := g.canTryConversion(b, inType, inField, outField, indent); err != nil { 711 return err 712 } else if !try { 713 continue 714 } 715 if err := g.writeConversionForPtr(b, inField, outField, indent); err != nil { 716 return err 717 } 718 continue 719 case reflect.Slice: 720 if try, err := g.canTryConversion(b, inType, inField, outField, indent); err != nil { 721 return err 722 } else if !try { 723 continue 724 } 725 if err := g.writeConversionForSlice(b, inField, outField, indent); err != nil { 726 return err 727 } 728 continue 729 case reflect.Interface, reflect.Struct: 730 // Don't copy these via assignment/conversion! 731 default: 732 // This should handle all simple types. 733 if inField.Type.AssignableTo(outField.Type) { 734 assignFormat := "out.%s = in.%s\n" 735 assignStmt := fmt.Sprintf(assignFormat, outField.Name, inField.Name) 736 b.addLine(assignStmt, indent) 737 continue 738 } 739 if inField.Type.ConvertibleTo(outField.Type) { 740 assignFormat := "out.%s = %s(in.%s)\n" 741 assignStmt := fmt.Sprintf(assignFormat, outField.Name, g.typeName(outField.Type), inField.Name) 742 b.addLine(assignStmt, indent) 743 continue 744 } 745 } 746 747 assignStmt := "" 748 if g.existsDedicatedConversionFunction(inField.Type, outField.Type) { 749 assignFormat := "if err := %s(&in.%s, &out.%s, s); err != nil {\n" 750 funcName := g.conversionFunctionName(inField.Type, outField.Type) 751 assignStmt = fmt.Sprintf(assignFormat, funcName, inField.Name, outField.Name) 752 } else { 753 assignFormat := "if err := s.Convert(&in.%s, &out.%s, 0); err != nil {\n" 754 assignStmt = fmt.Sprintf(assignFormat, inField.Name, outField.Name) 755 } 756 b.addLine(assignStmt, indent) 757 b.addLine("return err\n", indent+1) 758 b.addLine("}\n", indent) 759 } 760 return nil 761 } 762 763 func (g *conversionGenerator) writeConversionForType(b *buffer, inType, outType reflect.Type, indent int) error { 764 // Always emit the auto-generated name. 765 autoFuncName := g.generatedFunctionName(inType, outType) 766 g.writeHeader(b, autoFuncName, g.typeName(inType), g.typeName(outType), indent) 767 if err := g.writeDefaultingFunc(b, inType, indent+1); err != nil { 768 return err 769 } 770 switch inType.Kind() { 771 case reflect.Struct: 772 if err := g.writeConversionForStruct(b, inType, outType, indent+1); err != nil { 773 return err 774 } 775 default: 776 return fmt.Errorf("type not supported: %v", inType) 777 } 778 g.writeFooter(b, indent) 779 b.addLine("\n", 0) 780 781 if !g.overridden[inType] { 782 // Also emit the "user-facing" name. 783 userFuncName := g.conversionFunctionName(inType, outType) 784 g.writeHeader(b, userFuncName, g.typeName(inType), g.typeName(outType), indent) 785 b.addLine(fmt.Sprintf("return %s(in, out, s)\n", autoFuncName), indent+1) 786 b.addLine("}\n\n", 0) 787 } 788 789 return nil 790 } 791 792 func (g *conversionGenerator) existsConversionFunction(inType, outType reflect.Type) bool { 793 if val, found := g.convertibles[inType]; found && val == outType { 794 return true 795 } 796 if val, found := g.convertibles[outType]; found && val == inType { 797 return true 798 } 799 return false 800 } 801 802 // TODO(wojtek-t): We should somehow change the conversion methods registered under: 803 // pkg/runtime/scheme.go to implement the naming convention for conversion functions 804 // and get rid of this hack. 805 type typePair struct { 806 inType reflect.Type 807 outType reflect.Type 808 } 809 810 var defaultConversions []typePair = []typePair{ 811 {reflect.TypeOf([]RawExtension{}), reflect.TypeOf([]Object{})}, 812 {reflect.TypeOf([]Object{}), reflect.TypeOf([]RawExtension{})}, 813 {reflect.TypeOf(RawExtension{}), reflect.TypeOf(EmbeddedObject{})}, 814 {reflect.TypeOf(EmbeddedObject{}), reflect.TypeOf(RawExtension{})}, 815 } 816 817 func (g *conversionGenerator) existsDedicatedConversionFunction(inType, outType reflect.Type) bool { 818 if inType == outType { 819 // Assume that conversion are not defined for "deep copies". 820 return false 821 } 822 823 if g.existsConversionFunction(inType, outType) { 824 return true 825 } 826 827 for _, conv := range defaultConversions { 828 if conv.inType == inType && conv.outType == outType { 829 return false 830 } 831 } 832 if inType.Kind() != outType.Kind() { 833 // TODO(wojtek-t): Currently all conversions between types of different kinds are 834 // unnamed. Thus we return false here. 835 return false 836 } 837 // TODO: no way to handle private conversions in different packages 838 if g.assumePrivateConversions { 839 return false 840 } 841 return g.scheme.Converter().HasConversionFunc(inType, outType) 842 } 843 844 func (g *conversionGenerator) OverwritePackage(pkg, overwrite string) { 845 g.pkgOverwrites[pkg] = overwrite 846 }