From 61cde63622f78a8efaea5d766117cbde8ffa6e72 Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Fri, 8 Jul 2016 12:56:43 +0200 Subject: [PATCH] Switch to typeless generated deepcopy functions for less reflection --- .../deepcopy-gen/generators/deepcopy.go | 14 ++++++++--- pkg/conversion/cloner.go | 25 +++++++++++-------- pkg/runtime/scheme.go | 6 ++--- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go b/cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go index fd73d3aea2a..b12cc0381eb 100644 --- a/cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go +++ b/cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go @@ -204,6 +204,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat const ( apiPackagePath = "k8s.io/kubernetes/pkg/api" conversionPackagePath = "k8s.io/kubernetes/pkg/conversion" + runtimePackagePath = "k8s.io/kubernetes/pkg/runtime" ) // genDeepCopy produces a file with autogenerated deep-copy functions. @@ -384,8 +385,10 @@ func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error { sw.Do("if err := $.scheme|raw$.AddGeneratedDeepCopyFuncs(\n", map[string]interface{}{ "scheme": scheme, }) + reflect := c.Universe.Type(types.Name{Package: "reflect", Name: "TypeOf"}) for _, t := range g.typesForInit { - sw.Do(fmt.Sprintf("%s,\n", g.funcNameTmpl(t)), argsFromType(t)) + g.imports.AddType(reflect) + sw.Do(fmt.Sprintf("conversion.GeneratedDeepCopyFunc{Fn: %s, InType: reflect.TypeOf(func() *$.type|raw$ {var x *$.type|raw$; return x}())},\n", g.funcNameTmpl(t)), argsFromType(t)) } sw.Do("); err != nil {\n", nil) sw.Do("// if one of the deep copy functions is malformed, detect it immediately.\n", nil) @@ -425,10 +428,11 @@ func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Wri sw := generator.NewSnippetWriter(w, c, "$", "$") funcName := g.funcNameTmpl(t) - sw.Do(fmt.Sprintf("func %s(in *$.type|raw$, out *$.type|raw$, c *$.Cloner|raw$) error {\n", funcName), g.withGlobals(argsFromType(t))) + sw.Do(fmt.Sprintf("func %s(in interface{}, out interface{}, c *$.Cloner|raw$) error {{\n", funcName), g.withGlobals(argsFromType(t))) + sw.Do("in := in.(*$.type|raw$)\nout := out.(*$.type|raw$)\n", g.withGlobals(argsFromType(t))) g.generateFor(t, sw) sw.Do("return nil\n", nil) - sw.Do("}\n\n", nil) + sw.Do("}}\n\n", nil) return sw.Error() } @@ -531,6 +535,10 @@ func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) { } func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) { + if len(t.Members) == 0 { + // at least do something with in/out to avoid "declared and not used" errors + sw.Do("_ = in\n_ = out\n", nil) + } for _, m := range t.Members { t := m.Type if t.Kind == types.Alias { diff --git a/pkg/conversion/cloner.go b/pkg/conversion/cloner.go index 7df2dc48712..c5dec1f31e4 100644 --- a/pkg/conversion/cloner.go +++ b/pkg/conversion/cloner.go @@ -25,14 +25,14 @@ import ( type Cloner struct { // Map from the type to a function which can do the deep copy. deepCopyFuncs map[reflect.Type]reflect.Value - generatedDeepCopyFuncs map[reflect.Type]reflect.Value + generatedDeepCopyFuncs map[reflect.Type]func(in interface{}, out interface{}, c *Cloner) error } // NewCloner creates a new Cloner object. func NewCloner() *Cloner { c := &Cloner{ deepCopyFuncs: map[reflect.Type]reflect.Value{}, - generatedDeepCopyFuncs: map[reflect.Type]reflect.Value{}, + generatedDeepCopyFuncs: map[reflect.Type]func(in interface{}, out interface{}, c *Cloner) error{}, } if err := c.RegisterDeepCopyFunc(byteSliceDeepCopy); err != nil { // If one of the deep-copy functions is malformed, detect it immediately. @@ -103,15 +103,17 @@ func (c *Cloner) RegisterDeepCopyFunc(deepCopyFunc interface{}) error { return nil } +// GeneratedDeepCopyFunc bundles an untyped generated deep-copy function of a type +// with a reflection type object used as a key to lookup the deep-copy function. +type GeneratedDeepCopyFunc struct { + Fn func(in interface{}, out interface{}, c *Cloner) error + InType reflect.Type +} + // Similar to RegisterDeepCopyFunc, but registers deep copy function that were // automatically generated. -func (c *Cloner) RegisterGeneratedDeepCopyFunc(deepCopyFunc interface{}) error { - fv := reflect.ValueOf(deepCopyFunc) - ft := fv.Type() - if err := verifyDeepCopyFunctionSignature(ft); err != nil { - return err - } - c.generatedDeepCopyFuncs[ft.In(0)] = fv +func (c *Cloner) RegisterGeneratedDeepCopyFunc(fn GeneratedDeepCopyFunc) error { + c.generatedDeepCopyFuncs[fn.InType] = fn.Fn return nil } @@ -146,7 +148,10 @@ func (c *Cloner) deepCopy(src reflect.Value) (reflect.Value, error) { return c.customDeepCopy(src, fv) } if fv, ok := c.generatedDeepCopyFuncs[inType]; ok { - return c.customDeepCopy(src, fv) + var outValue reflect.Value + outValue = reflect.New(inType.Elem()) + err := fv(src.Interface(), outValue.Interface(), c) + return outValue, err } return c.defaultDeepCopy(src) } diff --git a/pkg/runtime/scheme.go b/pkg/runtime/scheme.go index f98ec54ab12..71b01073c4c 100644 --- a/pkg/runtime/scheme.go +++ b/pkg/runtime/scheme.go @@ -357,9 +357,9 @@ func (s *Scheme) AddDeepCopyFuncs(deepCopyFuncs ...interface{}) error { // Similar to AddDeepCopyFuncs, but registers deep-copy functions that were // automatically generated. -func (s *Scheme) AddGeneratedDeepCopyFuncs(deepCopyFuncs ...interface{}) error { - for _, f := range deepCopyFuncs { - if err := s.cloner.RegisterGeneratedDeepCopyFunc(f); err != nil { +func (s *Scheme) AddGeneratedDeepCopyFuncs(deepCopyFuncs ...conversion.GeneratedDeepCopyFunc) error { + for _, fn := range deepCopyFuncs { + if err := s.cloner.RegisterGeneratedDeepCopyFunc(fn); err != nil { return err } }