Merge pull request #30387 from lavalamp/refactor-generators

Automatic merge from submit-queue

Refactor generators

Extracting pure refactoring out of #25526 so I don't have to do it for a 4th time.

This makes no changes to the output of the generators.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.kubernetes.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.kubernetes.io/reviews/kubernetes/kubernetes/30387)
<!-- Reviewable:end -->
This commit is contained in:
Kubernetes Submit Queue 2016-08-11 10:04:09 -07:00 committed by GitHub
commit 475f6c5ef6
4 changed files with 109 additions and 94 deletions

View File

@ -104,8 +104,8 @@ type conversionFuncMap map[conversionPair]*types.Type
// Returns all manually-defined conversion functions in the package. // Returns all manually-defined conversion functions in the package.
func getManualConversionFunctions(context *generator.Context, pkg *types.Package, manualMap conversionFuncMap) { func getManualConversionFunctions(context *generator.Context, pkg *types.Package, manualMap conversionFuncMap) {
scopeName := types.Name{Package: conversionPackagePath, Name: "Scope"} scopeName := types.Ref(conversionPackagePath, "Scope").Name
errorName := types.Name{Package: "", Name: "error"} errorName := types.Ref("", "error").Name
buffer := &bytes.Buffer{} buffer := &bytes.Buffer{}
sw := generator.NewSnippetWriter(buffer, context, "$", "$") sw := generator.NewSnippetWriter(buffer, context, "$", "$")
@ -409,8 +409,6 @@ type genConversion struct {
manualDefaulters defaulterFuncMap manualDefaulters defaulterFuncMap
imports namer.ImportTracker imports namer.ImportTracker
typesForInit []conversionPair typesForInit []conversionPair
globalVariables map[string]interface{}
} }
func NewGenConversion(sanitizedName, targetPackage string, manualConversions conversionFuncMap, manualDefaulters defaulterFuncMap, peerPkgs []string) generator.Generator { func NewGenConversion(sanitizedName, targetPackage string, manualConversions conversionFuncMap, manualDefaulters defaulterFuncMap, peerPkgs []string) generator.Generator {
@ -429,7 +427,23 @@ func NewGenConversion(sanitizedName, targetPackage string, manualConversions con
func (g *genConversion) Namers(c *generator.Context) namer.NameSystems { func (g *genConversion) Namers(c *generator.Context) namer.NameSystems {
// Have the raw namer for this file track what it imports. // Have the raw namer for this file track what it imports.
return namer.NameSystems{"raw": namer.NewRawNamer(g.targetPackage, g.imports)} return namer.NameSystems{
"raw": namer.NewRawNamer(g.targetPackage, g.imports),
"publicIT": &namerPlusImportTracking{
delegate: conversionNamer(),
tracker: g.imports,
},
}
}
type namerPlusImportTracking struct {
delegate namer.Namer
tracker namer.ImportTracker
}
func (n *namerPlusImportTracking) Name(t *types.Type) string {
n.tracker.AddType(t)
return n.delegate.Name(t)
} }
func (g *genConversion) convertibleOnlyWithinPackage(inType, outType *types.Type) bool { func (g *genConversion) convertibleOnlyWithinPackage(inType, outType *types.Type) bool {
@ -506,33 +520,20 @@ func (g *genConversion) Imports(c *generator.Context) (imports []string) {
return importLines return importLines
} }
func (g *genConversion) withGlobals(args map[string]interface{}) map[string]interface{} { func argsFromType(inType, outType *types.Type) generator.Args {
for k, v := range g.globalVariables { return generator.Args{
if _, ok := args[k]; !ok {
args[k] = v
}
}
return args
}
func argsFromType(inType, outType *types.Type) map[string]interface{} {
return map[string]interface{}{
"inType": inType, "inType": inType,
"outType": outType, "outType": outType,
} }
} }
func defaultingArgsFromType(inType *types.Type) interface{} { func defaultingArgsFromType(inType *types.Type) generator.Args {
return map[string]interface{}{ return generator.Args{
"inType": inType, "inType": inType,
} }
} }
func (g *genConversion) funcNameTmpl(inType, outType *types.Type) string {
tmpl := "Convert_$.inType|public$_To_$.outType|public$" const nameTmpl = "Convert_$.inType|publicIT$_To_$.outType|publicIT$"
g.imports.AddType(inType)
g.imports.AddType(outType)
return tmpl
}
func (g *genConversion) preexists(inType, outType *types.Type) (*types.Type, bool) { func (g *genConversion) preexists(inType, outType *types.Type) (*types.Type, bool) {
function, ok := g.manualConversions[conversionPair{inType, outType}] function, ok := g.manualConversions[conversionPair{inType, outType}]
@ -540,23 +541,15 @@ func (g *genConversion) preexists(inType, outType *types.Type) (*types.Type, boo
} }
func (g *genConversion) Init(c *generator.Context, w io.Writer) error { func (g *genConversion) Init(c *generator.Context, w io.Writer) error {
scheme := c.Universe.Variable(types.Name{Package: apiPackagePath, Name: "Scheme"}) scheme := c.Universe.Package(apiPackagePath).Variable("Scheme")
g.imports.AddType(scheme)
scope := c.Universe.Type(types.Name{Package: conversionPackagePath, Name: "Scope"})
g.imports.AddType(scope)
g.globalVariables = map[string]interface{}{
"scheme": scheme,
"Scope": scope,
}
sw := generator.NewSnippetWriter(w, c, "$", "$") sw := generator.NewSnippetWriter(w, c, "$", "$")
sw.Do("func init() {\n", nil) sw.Do("func init() {\n", nil)
sw.Do("if err := $.scheme|raw$.AddGeneratedConversionFuncs(\n", map[string]interface{}{ sw.Do("if err := $.scheme|raw$.AddGeneratedConversionFuncs(\n", generator.Args{
"scheme": scheme, "scheme": scheme,
}) })
for _, conv := range g.typesForInit { for _, conv := range g.typesForInit {
funcName := g.funcNameTmpl(conv.inType, conv.outType) sw.Do(nameTmpl+",\n", argsFromType(conv.inType, conv.outType))
sw.Do(fmt.Sprintf("%s,\n", funcName), argsFromType(conv.inType, conv.outType))
} }
sw.Do("); err != nil {\n", nil) sw.Do("); err != nil {\n", nil)
sw.Do("// if one of the conversion functions is malformed, detect it immediately.\n", nil) sw.Do("// if one of the conversion functions is malformed, detect it immediately.\n", nil)
@ -595,9 +588,10 @@ func (g *genConversion) GenerateType(c *generator.Context, t *types.Type, w io.W
} }
func (g *genConversion) generateConversion(inType, outType *types.Type, sw *generator.SnippetWriter) { func (g *genConversion) generateConversion(inType, outType *types.Type, sw *generator.SnippetWriter) {
funcName := g.funcNameTmpl(inType, outType) args := argsFromType(inType, outType).
With("Scope", types.Ref(conversionPackagePath, "Scope"))
sw.Do(fmt.Sprintf("func auto%s(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", funcName), g.withGlobals(argsFromType(inType, outType))) sw.Do("func auto"+nameTmpl+"(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", args)
// if no defaulter of form SetDefaults_XXX is defined, do not inline a check for defaulting. // if no defaulter of form SetDefaults_XXX is defined, do not inline a check for defaulting.
if function, ok := g.manualDefaulters[inType]; ok { if function, ok := g.manualDefaulters[inType]; ok {
sw.Do("$.|raw$(in)\n", function) sw.Do("$.|raw$(in)\n", function)
@ -608,8 +602,8 @@ func (g *genConversion) generateConversion(inType, outType *types.Type, sw *gene
// If there is no public manual Conversion method, generate it. // If there is no public manual Conversion method, generate it.
if _, ok := g.preexists(inType, outType); !ok { if _, ok := g.preexists(inType, outType); !ok {
sw.Do(fmt.Sprintf("func %s(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", funcName), g.withGlobals(argsFromType(inType, outType))) sw.Do("func "+nameTmpl+"(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", args)
sw.Do(fmt.Sprintf("return auto%s(in, out, s)\n", funcName), argsFromType(inType, outType)) sw.Do("return auto"+nameTmpl+"(in, out, s)\n", args)
sw.Do("}\n\n", nil) sw.Do("}\n\n", nil)
} }
} }
@ -666,8 +660,7 @@ func (g *genConversion) doMap(inType, outType *types.Type, sw *generator.Snippet
if function, ok := g.preexists(inType.Elem, outType.Elem); ok { if function, ok := g.preexists(inType.Elem, outType.Elem); ok {
sw.Do("if err := $.|raw$(&val, newVal, s); err != nil {\n", function) sw.Do("if err := $.|raw$(&val, newVal, s); err != nil {\n", function)
} else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) {
funcName := g.funcNameTmpl(inType.Elem, outType.Elem) sw.Do("if err := "+nameTmpl+"(&val, newVal, s); err != nil {\n", argsFromType(inType.Elem, outType.Elem))
sw.Do(fmt.Sprintf("if err := %s(&val, newVal, s); err != nil {\n", funcName), argsFromType(inType.Elem, outType.Elem))
} else { } else {
sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil)
sw.Do("if err := s.Convert(&val, newVal, 0); err != nil {\n", nil) sw.Do("if err := s.Convert(&val, newVal, 0); err != nil {\n", nil)
@ -704,8 +697,7 @@ func (g *genConversion) doSlice(inType, outType *types.Type, sw *generator.Snipp
if function, ok := g.preexists(inType.Elem, outType.Elem); ok { if function, ok := g.preexists(inType.Elem, outType.Elem); ok {
sw.Do("if err := $.|raw$(&(*in)[i], &(*out)[i], s); err != nil {\n", function) sw.Do("if err := $.|raw$(&(*in)[i], &(*out)[i], s); err != nil {\n", function)
} else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) {
funcName := g.funcNameTmpl(inType.Elem, outType.Elem) sw.Do("if err := "+nameTmpl+"(&(*in)[i], &(*out)[i], s); err != nil {\n", argsFromType(inType.Elem, outType.Elem))
sw.Do(fmt.Sprintf("if err := %s(&(*in)[i], &(*out)[i], s); err != nil {\n", funcName), argsFromType(inType.Elem, outType.Elem))
} else { } else {
// TODO: This triggers on v1.ObjectMeta <-> api.ObjectMeta and // TODO: This triggers on v1.ObjectMeta <-> api.ObjectMeta and
// similar because neither package is the target package, and // similar because neither package is the target package, and
@ -785,8 +777,7 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip
continue continue
} }
if g.convertibleOnlyWithinPackage(t, outT) { if g.convertibleOnlyWithinPackage(t, outT) {
funcName := g.funcNameTmpl(t, outT) sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args)
sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, s); err != nil {\n", funcName), args)
} else { } else {
sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil)
sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args) sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args)
@ -802,8 +793,7 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip
} }
} else { } else {
if g.convertibleOnlyWithinPackage(t, outT) { if g.convertibleOnlyWithinPackage(t, outT) {
funcName := g.funcNameTmpl(t, outT) sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args)
sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, s); err != nil {\n", funcName), args)
} else { } else {
sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil)
sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args) sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args)
@ -813,8 +803,7 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip
} }
default: default:
if g.convertibleOnlyWithinPackage(t, outT) { if g.convertibleOnlyWithinPackage(t, outT) {
funcName := g.funcNameTmpl(t, outT) sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args)
sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, s); err != nil {\n", funcName), args)
} else { } else {
sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil)
sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args) sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args)
@ -841,8 +830,7 @@ func (g *genConversion) doPointer(inType, outType *types.Type, sw *generator.Sni
if function, ok := g.preexists(inType.Elem, outType.Elem); ok { if function, ok := g.preexists(inType.Elem, outType.Elem); ok {
sw.Do("if err := $.|raw$(*in, *out, s); err != nil {\n", function) sw.Do("if err := $.|raw$(*in, *out, s); err != nil {\n", function)
} else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) {
funcName := g.funcNameTmpl(inType.Elem, outType.Elem) sw.Do("if err := "+nameTmpl+"(*in, *out, s); err != nil {\n", argsFromType(inType.Elem, outType.Elem))
sw.Do(fmt.Sprintf("if err := %s(*in, *out, s); err != nil {\n", funcName), argsFromType(inType.Elem, outType.Elem))
} else { } else {
sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil)
sw.Do("if err := s.Convert(*in, *out, 0); err != nil {\n", nil) sw.Do("if err := s.Convert(*in, *out, 0); err != nil {\n", nil)

View File

@ -216,8 +216,6 @@ type genDeepCopy struct {
registerTypes bool registerTypes bool
imports namer.ImportTracker imports namer.ImportTracker
typesForInit []*types.Type typesForInit []*types.Type
globalVariables map[string]interface{}
} }
func NewGenDeepCopy(sanitizedName, targetPackage string, boundingDirs []string, allTypes, registerTypes bool) generator.Generator { func NewGenDeepCopy(sanitizedName, targetPackage string, boundingDirs []string, allTypes, registerTypes bool) generator.Generator {
@ -236,7 +234,14 @@ func NewGenDeepCopy(sanitizedName, targetPackage string, boundingDirs []string,
func (g *genDeepCopy) Namers(c *generator.Context) namer.NameSystems { func (g *genDeepCopy) Namers(c *generator.Context) namer.NameSystems {
// Have the raw namer for this file track what it imports. // Have the raw namer for this file track what it imports.
return namer.NameSystems{"raw": namer.NewRawNamer(g.targetPackage, g.imports)} return namer.NameSystems{
"raw": namer.NewRawNamer(g.targetPackage, g.imports),
"dcFnName": &dcFnNamer{
public: deepCopyNamer(),
tracker: g.imports,
myPackage: g.targetPackage,
},
}
} }
func (g *genDeepCopy) Filter(c *generator.Context, t *types.Type) bool { func (g *genDeepCopy) Filter(c *generator.Context, t *types.Type) bool {
@ -338,36 +343,30 @@ func (g *genDeepCopy) Imports(c *generator.Context) (imports []string) {
return importLines return importLines
} }
func (g *genDeepCopy) withGlobals(args map[string]interface{}) map[string]interface{} { func argsFromType(t *types.Type) generator.Args {
for k, v := range g.globalVariables { return generator.Args{
if _, ok := args[k]; !ok {
args[k] = v
}
}
return args
}
func argsFromType(t *types.Type) map[string]interface{} {
return map[string]interface{}{
"type": t, "type": t,
} }
} }
func (g *genDeepCopy) funcNameTmpl(t *types.Type) string { type dcFnNamer struct {
tmpl := "DeepCopy_$.type|public$" public namer.Namer
g.imports.AddType(t) tracker namer.ImportTracker
if t.Name.Package != g.targetPackage { myPackage string
tmpl = g.imports.LocalNameOf(t.Name.Package) + "." + tmpl }
func (n *dcFnNamer) Name(t *types.Type) string {
pubName := n.public.Name(t)
n.tracker.AddType(t)
if t.Name.Package == n.myPackage {
return "DeepCopy_" + pubName
} }
return tmpl return fmt.Sprintf("%s.DeepCopy_%s", n.tracker.LocalNameOf(t.Name.Package), pubName)
} }
func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error { func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error {
cloner := c.Universe.Type(types.Name{Package: conversionPackagePath, Name: "Cloner"}) cloner := c.Universe.Type(types.Name{Package: conversionPackagePath, Name: "Cloner"})
g.imports.AddType(cloner) g.imports.AddType(cloner)
g.globalVariables = map[string]interface{}{
"Cloner": cloner,
}
if !g.registerTypes { if !g.registerTypes {
// TODO: We should come up with a solution to register all generated // TODO: We should come up with a solution to register all generated
// deep-copy functions. However, for now, to avoid import cycles // deep-copy functions. However, for now, to avoid import cycles
@ -377,18 +376,15 @@ func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error {
glog.V(5).Infof("registering types in pkg %q", g.targetPackage) glog.V(5).Infof("registering types in pkg %q", g.targetPackage)
scheme := c.Universe.Variable(types.Name{Package: apiPackagePath, Name: "Scheme"}) scheme := c.Universe.Variable(types.Name{Package: apiPackagePath, Name: "Scheme"})
g.imports.AddType(scheme)
g.globalVariables["scheme"] = scheme
sw := generator.NewSnippetWriter(w, c, "$", "$") sw := generator.NewSnippetWriter(w, c, "$", "$")
sw.Do("func init() {\n", nil) sw.Do("func init() {\n", nil)
sw.Do("if err := $.scheme|raw$.AddGeneratedDeepCopyFuncs(\n", map[string]interface{}{ sw.Do("if err := $.scheme|raw$.AddGeneratedDeepCopyFuncs(\n", generator.Args{
"scheme": scheme, "scheme": scheme,
}) })
reflect := c.Universe.Type(types.Name{Package: "reflect", Name: "TypeOf"})
for _, t := range g.typesForInit { for _, t := range g.typesForInit {
g.imports.AddType(reflect) args := argsFromType(t).
sw.Do(fmt.Sprintf("conversion.GeneratedDeepCopyFunc{Fn: %s, InType: reflect.TypeOf(&$.type|raw${})},\n", g.funcNameTmpl(t)), argsFromType(t)) With("typeof", c.Universe.Package("reflect").Function("TypeOf"))
sw.Do("conversion.GeneratedDeepCopyFunc{Fn: $.type|dcFnName$, InType: $.typeof|raw$(&$.type|raw${})},\n", args)
} }
sw.Do("); err != nil {\n", nil) sw.Do("); err != nil {\n", nil)
sw.Do("// if one of the deep copy functions is malformed, detect it immediately.\n", nil) sw.Do("// if one of the deep copy functions is malformed, detect it immediately.\n", nil)
@ -427,9 +423,10 @@ func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Wri
glog.V(5).Infof("generating for type %v", t) glog.V(5).Infof("generating for type %v", t)
sw := generator.NewSnippetWriter(w, c, "$", "$") sw := generator.NewSnippetWriter(w, c, "$", "$")
funcName := g.funcNameTmpl(t) args := argsFromType(t).
sw.Do(fmt.Sprintf("func %s(in interface{}, out interface{}, c *$.Cloner|raw$) error {{\n", funcName), g.withGlobals(argsFromType(t))) With("clonerType", types.Ref(conversionPackagePath, "Cloner"))
sw.Do("in := in.(*$.type|raw$)\nout := out.(*$.type|raw$)\n", g.withGlobals(argsFromType(t))) sw.Do("func $.type|dcFnName$(in interface{}, out interface{}, c *$.clonerType|raw$) error {{\n", args)
sw.Do("in := in.(*$.type|raw$)\nout := out.(*$.type|raw$)\n", argsFromType(t))
g.generateFor(t, sw) g.generateFor(t, sw)
sw.Do("return nil\n", nil) sw.Do("return nil\n", nil)
sw.Do("}}\n\n", nil) sw.Do("}}\n\n", nil)
@ -486,8 +483,7 @@ func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) {
sw.Do("for key, val := range *in {\n", nil) sw.Do("for key, val := range *in {\n", nil)
if g.copyableAndInBounds(t.Elem) { if g.copyableAndInBounds(t.Elem) {
sw.Do("newVal := new($.|raw$)\n", t.Elem) sw.Do("newVal := new($.|raw$)\n", t.Elem)
funcName := g.funcNameTmpl(t.Elem) sw.Do("if err := $.type|dcFnName$(&val, newVal, c); err != nil {\n", argsFromType(t.Elem))
sw.Do(fmt.Sprintf("if err := %s(&val, newVal, c); err != nil {\n", funcName), argsFromType(t.Elem))
sw.Do("return err\n", nil) sw.Do("return err\n", nil)
sw.Do("}\n", nil) sw.Do("}\n", nil)
sw.Do("(*out)[key] = *newVal\n", nil) sw.Do("(*out)[key] = *newVal\n", nil)
@ -519,8 +515,7 @@ func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) {
} else if t.Elem.IsAssignable() { } else if t.Elem.IsAssignable() {
sw.Do("(*out)[i] = (*in)[i]\n", nil) sw.Do("(*out)[i] = (*in)[i]\n", nil)
} else if g.copyableAndInBounds(t.Elem) { } else if g.copyableAndInBounds(t.Elem) {
funcName := g.funcNameTmpl(t.Elem) sw.Do("if err := $.type|dcFnName$(&(*in)[i], &(*out)[i], c); err != nil {\n", argsFromType(t.Elem))
sw.Do(fmt.Sprintf("if err := %s(&(*in)[i], &(*out)[i], c); err != nil {\n", funcName), argsFromType(t.Elem))
sw.Do("return err\n", nil) sw.Do("return err\n", nil)
sw.Do("}\n", nil) sw.Do("}\n", nil)
} else { } else {
@ -546,7 +541,7 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
copied.Name = t.Name copied.Name = t.Name
t = &copied t = &copied
} }
args := map[string]interface{}{ args := generator.Args{
"type": t, "type": t,
"name": m.Name, "name": m.Name,
} }
@ -566,8 +561,7 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
} else if t.IsAssignable() { } else if t.IsAssignable() {
sw.Do("out.$.name$ = in.$.name$\n", args) sw.Do("out.$.name$ = in.$.name$\n", args)
} else if g.copyableAndInBounds(t) { } else if g.copyableAndInBounds(t) {
funcName := g.funcNameTmpl(t) sw.Do("if err := $.type|dcFnName$(&in.$.name$, &out.$.name$, c); err != nil {\n", args)
sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, c); err != nil {\n", funcName), args)
sw.Do("return err\n", nil) sw.Do("return err\n", nil)
sw.Do("}\n", nil) sw.Do("}\n", nil)
} else { } else {
@ -602,9 +596,8 @@ func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) {
sw.Do("*out = new($.Elem|raw$)\n", t) sw.Do("*out = new($.Elem|raw$)\n", t)
sw.Do("**out = **in", nil) sw.Do("**out = **in", nil)
} else if g.copyableAndInBounds(t.Elem) { } else if g.copyableAndInBounds(t.Elem) {
funcName := g.funcNameTmpl(t.Elem)
sw.Do("*out = new($.Elem|raw$)\n", t) sw.Do("*out = new($.Elem|raw$)\n", t)
sw.Do(fmt.Sprintf("if err := %s(*in, *out, c); err != nil {\n", funcName), argsFromType(t.Elem)) sw.Do("if err := $.type|dcFnName$(*in, *out, c); err != nil {\n", argsFromType(t.Elem))
sw.Do("return err\n", nil) sw.Do("return err\n", nil)
sw.Do("}\n", nil) sw.Do("}\n", nil)
} else { } else {

View File

@ -94,7 +94,7 @@ func NewSnippetWriter(w io.Writer, c *Context, left, right string) *SnippetWrite
// but you should consider doing the logic in go and stitching them together // but you should consider doing the logic in go and stitching them together
// for the sake of your readers. // for the sake of your readers.
// //
// TODO: Change Do() to optionally take a list of pairt of parameters (key, value) // TODO: Change Do() to optionally take a list of pairs of parameters (key, value)
// and have it construct a combined map with that and args. // and have it construct a combined map with that and args.
func (s *SnippetWriter) Do(format string, args interface{}) *SnippetWriter { func (s *SnippetWriter) Do(format string, args interface{}) *SnippetWriter {
if s.err != nil { if s.err != nil {
@ -119,6 +119,31 @@ func (s *SnippetWriter) Do(format string, args interface{}) *SnippetWriter {
return s return s
} }
// Args exists to make it convenient to construct arguments for
// SnippetWriter.Do.
type Args map[interface{}]interface{}
// With makes a copy of a and adds the given key, value pair.
func (a Args) With(key, value interface{}) Args {
a2 := Args{key: value}
for k, v := range a {
a2[k] = v
}
return a2
}
// WithArgs makes a copy of a and adds the given arguments.
func (a Args) WithArgs(rhs Args) Args {
a2 := Args{}
for k, v := range rhs {
a2[k] = v
}
for k, v := range a {
a2[k] = v
}
return a2
}
func (s *SnippetWriter) Out() io.Writer { func (s *SnippetWriter) Out() io.Writer {
return s.w return s.w
} }

View File

@ -16,6 +16,15 @@ limitations under the License.
package types package types
// Ref makes a reference to the given type. It can only be used for e.g.
// passing to namers.
func Ref(packageName, typeName string) *Type {
return &Type{Name: Name{
Name: typeName,
Package: packageName,
}}
}
// A type name may have a package qualifier. // A type name may have a package qualifier.
type Name struct { type Name struct {
// Empty if embedded or builtin. This is the package path unless Path is specified. // Empty if embedded or builtin. This is the package path unless Path is specified.