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  }