Commit fd91d3f0 authored by Tim Hockin's avatar Tim Hockin

Make patch-up conversions simpler

Rather than an "all or nothing" approach to defining a custom conversion function (which seems destined to cause problems eventually), this is an attempt to make it possible to call the auto-generated code and then "fix it up". Specifically, consider you have a fooBar struct. If you don't define a conversion for FooBar, you will get a generated function like: convert_v1_FooBar_To_api_FooBar() Before this PR, if you define your own conversion function, you get no generated function. After this PR you get: autoconvert_v1_FooBar_To_api_FooBar() ...which you can call yourself in your custom function.
parent 2cc9ed6b
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -44,6 +44,7 @@ func NewConversionGenerator(scheme *conversion.Scheme, targetPkg string) Convers ...@@ -44,6 +44,7 @@ func NewConversionGenerator(scheme *conversion.Scheme, targetPkg string) Convers
scheme: scheme, scheme: scheme,
targetPkg: targetPkg, targetPkg: targetPkg,
convertibles: make(map[reflect.Type]reflect.Type), convertibles: make(map[reflect.Type]reflect.Type),
overridden: make(map[reflect.Type]bool),
pkgOverwrites: make(map[string]string), pkgOverwrites: make(map[string]string),
imports: make(map[string]string), imports: make(map[string]string),
shortImports: make(map[string]string), shortImports: make(map[string]string),
...@@ -60,6 +61,7 @@ type conversionGenerator struct { ...@@ -60,6 +61,7 @@ type conversionGenerator struct {
scheme *conversion.Scheme scheme *conversion.Scheme
targetPkg string targetPkg string
convertibles map[reflect.Type]reflect.Type convertibles map[reflect.Type]reflect.Type
overridden map[reflect.Type]bool
// If pkgOverwrites is set for a given package name, that package name // If pkgOverwrites is set for a given package name, that package name
// will be replaced while writing conversion function. If empty, package // will be replaced while writing conversion function. If empty, package
// name will be omitted. // name will be omitted.
...@@ -165,9 +167,10 @@ func (g *conversionGenerator) generateConversionsBetween(inType, outType reflect ...@@ -165,9 +167,10 @@ func (g *conversionGenerator) generateConversionsBetween(inType, outType reflect
if !existingConversion && (inErr != nil || outErr != nil) { if !existingConversion && (inErr != nil || outErr != nil) {
return inErr return inErr
} }
if !existingConversion { if existingConversion {
g.convertibles[inType] = outType g.overridden[inType] = true
} }
g.convertibles[inType] = outType
return nil return nil
default: default:
// All simple types should be handled correctly with default conversion. // All simple types should be handled correctly with default conversion.
...@@ -368,7 +371,7 @@ func (g *conversionGenerator) RegisterConversionFunctions(w io.Writer, pkg strin ...@@ -368,7 +371,7 @@ func (g *conversionGenerator) RegisterConversionFunctions(w io.Writer, pkg strin
// Write conversion function names alphabetically ordered. // Write conversion function names alphabetically ordered.
var names []string var names []string
for inType, outType := range g.convertibles { for inType, outType := range g.convertibles {
names = append(names, g.conversionFunctionName(inType, outType)) names = append(names, g.generatedFunctionName(inType, outType))
} }
sort.Strings(names) sort.Strings(names)
...@@ -482,6 +485,10 @@ func (g *conversionGenerator) conversionFunctionName(inType, outType reflect.Typ ...@@ -482,6 +485,10 @@ func (g *conversionGenerator) conversionFunctionName(inType, outType reflect.Typ
return funcName return funcName
} }
func (g *conversionGenerator) generatedFunctionName(inType, outType reflect.Type) string {
return "auto" + g.conversionFunctionName(inType, outType)
}
func (g *conversionGenerator) writeHeader(b *buffer, name, inType, outType string, indent int) { func (g *conversionGenerator) writeHeader(b *buffer, name, inType, outType string, indent int) {
format := "func %s(in *%s, out *%s, s conversion.Scope) error {\n" format := "func %s(in *%s, out *%s, s conversion.Scope) error {\n"
stmt := fmt.Sprintf(format, name, inType, outType) stmt := fmt.Sprintf(format, name, inType, outType)
...@@ -654,10 +661,28 @@ func (g *conversionGenerator) writeConversionForPtr(b *buffer, inField, outField ...@@ -654,10 +661,28 @@ func (g *conversionGenerator) writeConversionForPtr(b *buffer, inField, outField
return nil return nil
} }
func (g *conversionGenerator) canTryConversion(b *buffer, inType reflect.Type, inField, outField reflect.StructField, indent int) (bool, error) {
if inField.Type.Kind() != outField.Type.Kind() {
if !g.overridden[inType] {
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())
}
b.addLine(fmt.Sprintf("// in.%s has no peer in out\n", inField.Name), indent)
return false, nil
}
return true, nil
}
func (g *conversionGenerator) writeConversionForStruct(b *buffer, inType, outType reflect.Type, indent int) error { func (g *conversionGenerator) writeConversionForStruct(b *buffer, inType, outType reflect.Type, indent int) error {
for i := 0; i < inType.NumField(); i++ { for i := 0; i < inType.NumField(); i++ {
inField := inType.Field(i) inField := inType.Field(i)
outField, _ := outType.FieldByName(inField.Name) outField, found := outType.FieldByName(inField.Name)
if !found {
if !g.overridden[inType] {
return fmt.Errorf("input %s.%s has no peer in output %s and conversion is not overridden", inType, inField.Name, outType)
}
b.addLine(fmt.Sprintf("// in.%s has no peer in out\n", inField.Name), indent)
continue
}
existsConversion := g.scheme.Converter().HasConversionFunc(inField.Type, outField.Type) existsConversion := g.scheme.Converter().HasConversionFunc(inField.Type, outField.Type)
if existsConversion && !g.existsDedicatedConversionFunction(inField.Type, outField.Type) { if existsConversion && !g.existsDedicatedConversionFunction(inField.Type, outField.Type) {
...@@ -672,16 +697,31 @@ func (g *conversionGenerator) writeConversionForStruct(b *buffer, inType, outTyp ...@@ -672,16 +697,31 @@ func (g *conversionGenerator) writeConversionForStruct(b *buffer, inType, outTyp
switch inField.Type.Kind() { switch inField.Type.Kind() {
case reflect.Map: case reflect.Map:
if try, err := g.canTryConversion(b, inType, inField, outField, indent); err != nil {
return err
} else if !try {
continue
}
if err := g.writeConversionForMap(b, inField, outField, indent); err != nil { if err := g.writeConversionForMap(b, inField, outField, indent); err != nil {
return err return err
} }
continue continue
case reflect.Ptr: case reflect.Ptr:
if try, err := g.canTryConversion(b, inType, inField, outField, indent); err != nil {
return err
} else if !try {
continue
}
if err := g.writeConversionForPtr(b, inField, outField, indent); err != nil { if err := g.writeConversionForPtr(b, inField, outField, indent); err != nil {
return err return err
} }
continue continue
case reflect.Slice: case reflect.Slice:
if try, err := g.canTryConversion(b, inType, inField, outField, indent); err != nil {
return err
} else if !try {
continue
}
if err := g.writeConversionForSlice(b, inField, outField, indent); err != nil { if err := g.writeConversionForSlice(b, inField, outField, indent); err != nil {
return err return err
} }
...@@ -721,8 +761,9 @@ func (g *conversionGenerator) writeConversionForStruct(b *buffer, inType, outTyp ...@@ -721,8 +761,9 @@ func (g *conversionGenerator) writeConversionForStruct(b *buffer, inType, outTyp
} }
func (g *conversionGenerator) writeConversionForType(b *buffer, inType, outType reflect.Type, indent int) error { func (g *conversionGenerator) writeConversionForType(b *buffer, inType, outType reflect.Type, indent int) error {
funcName := g.conversionFunctionName(inType, outType) // Always emit the auto-generated name.
g.writeHeader(b, funcName, g.typeName(inType), g.typeName(outType), indent) autoFuncName := g.generatedFunctionName(inType, outType)
g.writeHeader(b, autoFuncName, g.typeName(inType), g.typeName(outType), indent)
if err := g.writeDefaultingFunc(b, inType, indent+1); err != nil { if err := g.writeDefaultingFunc(b, inType, indent+1); err != nil {
return err return err
} }
...@@ -736,6 +777,15 @@ func (g *conversionGenerator) writeConversionForType(b *buffer, inType, outType ...@@ -736,6 +777,15 @@ func (g *conversionGenerator) writeConversionForType(b *buffer, inType, outType
} }
g.writeFooter(b, indent) g.writeFooter(b, indent)
b.addLine("\n", 0) b.addLine("\n", 0)
if !g.overridden[inType] {
// Also emit the "user-facing" name.
userFuncName := g.conversionFunctionName(inType, outType)
g.writeHeader(b, userFuncName, g.typeName(inType), g.typeName(outType), indent)
b.addLine(fmt.Sprintf("return %s(in, out, s)\n", autoFuncName), indent+1)
b.addLine("}\n\n", 0)
}
return nil return nil
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment