func (g *genConversion) doBuiltin(inType, outType *types.Type, sw *generator.SnippetWriter) { if inType == outType { sw.Do("*out = *in\n", nil) } else { sw.Do("*out = $.|raw$(*in)\n", outType) } }
func (g *genSet) lessBody(sw *generator.SnippetWriter, t *types.Type) { // TODO: make this recursive, handle pointers and multiple nested structs... switch t.Kind { case types.Struct: for _, m := range types.FlattenMembers(t.Members) { sw.Do("if lhs.$.Name$ < rhs.$.Name$ { return true }\n", m) sw.Do("if lhs.$.Name$ > rhs.$.Name$ { return false }\n", m) } sw.Do("return false\n", nil) default: sw.Do("return lhs < rhs\n", nil) } }
func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = make($.|raw$, len(*in))\n", t) if t.Elem.Kind == types.Builtin { sw.Do("copy(*out, *in)\n", nil) } else { sw.Do("for i := range *in {\n", nil) if hasDeepCopyMethod(t.Elem) { sw.Do("(*out)[i] = (*in)[i].DeepCopy()\n", nil) } else if t.Elem.IsAssignable() { sw.Do("(*out)[i] = (*in)[i]\n", nil) } else if g.copyableAndInBounds(t.Elem) { sw.Do("if err := $.type|dcFnName$(&(*in)[i], &(*out)[i], c); err != nil {\n", argsFromType(t.Elem)) sw.Do("return err\n", nil) sw.Do("}\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(&(*in)[i]); err != nil {\n", nil) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("(*out)[i] = *newVal.(*$.|raw$)\n", t.Elem) sw.Do("}\n", nil) } sw.Do("}\n", nil) } }
func (g *genConversion) doPointer(inType, outType *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = new($.Elem|raw$)\n", outType) if isDirectlyAssignable(inType.Elem, outType.Elem) { if inType.Elem == outType.Elem { sw.Do("**out = **in\n", nil) } else { sw.Do("**out = $.|raw$(**in)\n", outType.Elem) } } else { if function, ok := g.preexists(inType.Elem, outType.Elem); ok { sw.Do("if err := $.|raw$(*in, *out, s); err != nil {\n", function) } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { sw.Do("if err := "+nameTmpl+"(*in, *out, s); err != nil {\n", argsFromType(inType.Elem, outType.Elem)) } else { 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("return err\n", nil) sw.Do("}\n", nil) } }
func (g *genConversion) doSlice(inType, outType *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = make($.|raw$, len(*in))\n", outType) if inType.Elem == outType.Elem && inType.Elem.Kind == types.Builtin { sw.Do("copy(*out, *in)\n", nil) } else { sw.Do("for i := range *in {\n", nil) if isDirectlyAssignable(inType.Elem, outType.Elem) { if inType.Elem == outType.Elem { sw.Do("(*out)[i] = (*in)[i]\n", nil) } else { sw.Do("(*out)[i] = $.|raw$((*in)[i])\n", outType.Elem) } } else { if function, ok := g.preexists(inType.Elem, outType.Elem); ok { sw.Do("if err := $.|raw$(&(*in)[i], &(*out)[i], s); err != nil {\n", function) } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { sw.Do("if err := "+nameTmpl+"(&(*in)[i], &(*out)[i], s); err != nil {\n", argsFromType(inType.Elem, outType.Elem)) } else { // TODO: This triggers on v1.ObjectMeta <-> api.ObjectMeta and // similar because neither package is the target package, and // we really don't know which package will have the conversion // function defined. This fires on basically every object // conversion outside of pkg/api/v1. sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) sw.Do("if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil {\n", nil) } sw.Do("return err\n", nil) sw.Do("}\n", nil) } sw.Do("}\n", nil) } }
func (g *genDeepCopy) doUnknown(t *types.Type, sw *generator.SnippetWriter) { sw.Do("// FIXME: Type $.|raw$ is unsupported.\n", t) }
func (g *genConversion) generateConversion(inType, outType *types.Type, sw *generator.SnippetWriter) { funcName := g.funcNameTmpl(inType, outType) if g.targetPackage == conversionPackagePath { sw.Do(fmt.Sprintf("func auto%s(in *$.inType|raw$, out *$.outType|raw$, s Scope) error {\n", funcName), argsFromType(inType, outType)) } else { sw.Do(fmt.Sprintf("func auto%s(in *$.inType|raw$, out *$.outType|raw$, s conversion.Scope) error {\n", funcName), argsFromType(inType, outType)) } // if no defaulter of form SetDefaults_XXX is defined, do not inline a check for defaulting. if function, ok := g.defaulters[inType]; ok { sw.Do("$.|raw$(in)\n", function) } g.generateFor(inType, outType, sw) sw.Do("return nil\n", nil) sw.Do("}\n\n", nil) // If there is no public preexisting Convert method, generate it. if _, ok := g.preexists(inType, outType); !ok { if g.targetPackage == conversionPackagePath { sw.Do(fmt.Sprintf("func %s(in *$.inType|raw$, out *$.outType|raw$, s Scope) error {\n", funcName), argsFromType(inType, outType)) } else { sw.Do(fmt.Sprintf("func %s(in *$.inType|raw$, out *$.outType|raw$, s conversion.Scope) error {\n", funcName), argsFromType(inType, outType)) } sw.Do(fmt.Sprintf("return auto%s(in, out, s)\n", funcName), argsFromType(inType, outType)) sw.Do("}\n\n", nil) } }
func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) { for _, m := range t.Members { t := m.Type if t.Kind == types.Alias { copied := *t.Underlying copied.Name = t.Name t = &copied } args := map[string]interface{}{ "type": t, "name": m.Name, } switch t.Kind { case types.Builtin: sw.Do("out.$.name$ = in.$.name$\n", args) case types.Map, types.Slice, types.Pointer: sw.Do("if in.$.name$ != nil {\n", args) sw.Do("in, out := in.$.name$, &out.$.name$\n", args) g.generateFor(t, sw) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = nil\n", args) sw.Do("}\n", nil) case types.Struct: if hasDeepCopyMethod(t) { sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args) } else if t.IsAssignable() { sw.Do("out.$.name$ = in.$.name$\n", args) } else if g.copyableAndInBounds(t) { funcName := g.funcNameTmpl(t) 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("}\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(in.$.name$); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = newVal.($.type|raw$)\n", args) sw.Do("}\n", nil) } default: sw.Do("if in.$.name$ == nil {\n", args) sw.Do("out.$.name$ = nil\n", args) sw.Do("} else if newVal, err := c.DeepCopy(in.$.name$); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = newVal.($.type|raw$)\n", args) sw.Do("}\n", nil) } } }
func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = make($.|raw$, len(in))\n", t) if t.Elem.Kind == types.Builtin { sw.Do("copy(*out, in)\n", nil) } else { sw.Do("for i := range in {\n", nil) if t.Elem.IsAssignable() { sw.Do("(*out)[i] = in[i]\n", nil) } else if g.copyableWithinPackage(t.Elem) { sw.Do("if err := deepCopy_$.|public$(in[i], &(*out)[i], c); err != nil {\n", t.Elem) sw.Do("return err\n", nil) sw.Do("}\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(in[i]); err != nil {\n", nil) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("(*out)[i] = newVal.($.|raw$)\n", t.Elem) sw.Do("}\n", nil) } sw.Do("}\n", nil) } }
func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = new($.Elem|raw$)\n", t) if t.Elem.Kind == types.Builtin { sw.Do("**out = *in", nil) } else if g.copyableWithinPackage(t.Elem) { sw.Do("if err := deepCopy_$.|public$(*in, *out, c); err != nil {\n", t.Elem) sw.Do("return err\n", nil) sw.Do("}\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(*in); err != nil {\n", nil) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("**out = newVal.($.|raw$)\n", t.Elem) sw.Do("}\n", nil) } }
func (g *genConversion) generateConversion(inType, outType *types.Type, sw *generator.SnippetWriter) { funcName := g.funcNameTmpl(inType, outType) if g.targetPackage == conversionPackagePath { sw.Do(fmt.Sprintf("func auto%s(in *$.inType|raw$, out *$.outType|raw$, s Scope) error {\n", funcName), argsFromType(inType, outType)) } else { sw.Do(fmt.Sprintf("func auto%s(in *$.inType|raw$, out *$.outType|raw$, s conversion.Scope) error {\n", funcName), argsFromType(inType, outType)) } sw.Do("if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {\n", nil) sw.Do("defaulting.(func(*$.|raw$))(in)\n", inType) sw.Do("}\n", nil) g.generateFor(inType, outType, sw) sw.Do("return nil\n", nil) sw.Do("}\n\n", nil) // If there is no public preexisting Convert method, generate it. if _, ok := g.preexists(inType, outType); !ok { if g.targetPackage == conversionPackagePath { sw.Do(fmt.Sprintf("func %s(in *$.inType|raw$, out *$.outType|raw$, s Scope) error {\n", funcName), argsFromType(inType, outType)) } else { sw.Do(fmt.Sprintf("func %s(in *$.inType|raw$, out *$.outType|raw$, s conversion.Scope) error {\n", funcName), argsFromType(inType, outType)) } sw.Do(fmt.Sprintf("return auto%s(in, out, s)\n", funcName), argsFromType(inType, outType)) sw.Do("}\n\n", nil) } }
func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) { if hasDeepCopyMethod(t.Elem) { sw.Do("*out = new($.Elem|raw$)\n", t) sw.Do("**out = (*in).DeepCopy()\n", nil) } else if t.Elem.IsAssignable() { sw.Do("*out = new($.Elem|raw$)\n", t) sw.Do("**out = **in", nil) } else if g.copyableAndInBounds(t.Elem) { sw.Do("*out = new($.Elem|raw$)\n", t) sw.Do("if err := $.type|dcFnName$(*in, *out, c); err != nil {\n", argsFromType(t.Elem)) sw.Do("return err\n", nil) sw.Do("}\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(*in); err != nil {\n", nil) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("*out = newVal.(*$.|raw$)\n", t.Elem) sw.Do("}\n", nil) } }
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 { copied := *t.Underlying copied.Name = t.Name t = &copied } args := generator.Args{ "type": t, "name": m.Name, } switch t.Kind { case types.Builtin: sw.Do("out.$.name$ = in.$.name$\n", args) case types.Map, types.Slice, types.Pointer: sw.Do("if in.$.name$ != nil {\n", args) sw.Do("in, out := &in.$.name$, &out.$.name$\n", args) g.generateFor(t, sw) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = nil\n", args) sw.Do("}\n", nil) case types.Struct: if hasDeepCopyMethod(t) { sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args) } else if t.IsAssignable() { sw.Do("out.$.name$ = in.$.name$\n", args) } else if g.copyableAndInBounds(t) { sw.Do("if err := $.type|dcFnName$(&in.$.name$, &out.$.name$, c); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("}\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(&in.$.name$); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = *newVal.(*$.type|raw$)\n", args) sw.Do("}\n", nil) } default: sw.Do("if in.$.name$ == nil {\n", args) sw.Do("out.$.name$ = nil\n", args) sw.Do("} else if newVal, err := c.DeepCopy(&in.$.name$); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = *newVal.(*$.type|raw$)\n", args) sw.Do("}\n", nil) } } }
func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = make($.|raw$)\n", t) if t.Key.IsAssignable() { switch { case hasDeepCopyMethod(t.Elem): sw.Do("for key, val := range in {\n", nil) sw.Do("(*out)[key] = val.DeepCopy()\n", nil) sw.Do("}\n", nil) case t.Elem.IsAnonymousStruct(): sw.Do("for key := range in {\n", nil) sw.Do("(*out)[key] = struct{}{}\n", nil) sw.Do("}\n", nil) case t.Elem.IsAssignable(): sw.Do("for key, val := range in {\n", nil) sw.Do("(*out)[key] = val\n", nil) sw.Do("}\n", nil) default: sw.Do("for key, val := range in {\n", nil) if g.copyableAndInBounds(t.Elem) { sw.Do("newVal := new($.|raw$)\n", t.Elem) funcName := g.funcNameTmpl(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("}\n", nil) sw.Do("(*out)[key] = *newVal\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(val); err != nil {\n", nil) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("(*out)[key] = newVal.($.|raw$)\n", t.Elem) sw.Do("}\n", nil) } sw.Do("}\n", nil) } } else { // TODO: Implement it when necessary. sw.Do("for range in {\n", nil) sw.Do("// FIXME: Copying unassignable keys unsupported $.|raw$\n", t.Key) sw.Do("}\n", nil) } }
func (g *genConversion) doSlice(inType, outType *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = make($.|raw$, len(*in))\n", outType) if inType.Elem == outType.Elem && inType.Elem.Kind == types.Builtin { sw.Do("copy(*out, *in)\n", nil) } else { sw.Do("for i := range *in {\n", nil) if outType.Elem.IsAssignable() { if inType.Elem == outType.Elem { sw.Do("(*out)[i] = (*in)[i]\n", nil) } else { sw.Do("(*out)[i] = $.|raw$((*in)[i])\n", outType.Elem) } } else { if function, ok := g.preexists(inType.Elem, outType.Elem); ok { sw.Do("if err := $.|raw$(&(*in)[i], &(*out)[i], s); err != nil {\n", function) } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { funcName := g.funcNameTmpl(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 { sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) sw.Do("if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil {\n", nil) } sw.Do("return err\n", nil) sw.Do("}\n", nil) } sw.Do("}\n", nil) } }
func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = make($.|raw$, len(in))\n", t) if t.Elem.Kind == types.Builtin { sw.Do("copy(*out, in)\n", nil) } else { sw.Do("for i := range in {\n", nil) if hasDeepCopyMethod(t.Elem) { sw.Do("(*out)[i] = in[i].DeepCopy()\n", nil) } else if t.Elem.IsAssignable() { sw.Do("(*out)[i] = in[i]\n", nil) } else if g.copyableAndInBounds(t.Elem) { funcName := g.funcNameTmpl(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("}\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(in[i]); err != nil {\n", nil) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("(*out)[i] = newVal.($.|raw$)\n", t.Elem) sw.Do("}\n", nil) } sw.Do("}\n", nil) } }
func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.SnippetWriter) { for _, m := range inType.Members { outMember, isOutMember := findMember(outType, m.Name) if !isOutMember { // Since this object wasn't filtered out, this means that // this field has "genconversion=false" comment to ignore it. continue } args := map[string]interface{}{ "inType": m.Type, "outType": outMember.Type, "name": m.Name, } if function, ok := g.preexists(m.Type, outMember.Type); ok { args["function"] = function sw.Do("if err := $.function|raw$(&in.$.name$, &out.$.name$, s); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("}\n", nil) continue } switch m.Type.Kind { case types.Builtin: if m.Type == outMember.Type { sw.Do("out.$.name$ = in.$.name$\n", args) } else { sw.Do("out.$.name$ = $.outType|raw$(in.$.name$)\n", args) } case types.Map, types.Slice, types.Pointer: sw.Do("if in.$.name$ != nil {\n", args) sw.Do("in, out := &in.$.name$, &out.$.name$\n", args) g.generateFor(m.Type, outMember.Type, sw) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = nil\n", args) sw.Do("}\n", nil) case types.Struct: if g.convertibleOnlyWithinPackage(m.Type, outMember.Type) { funcName := g.funcNameTmpl(m.Type, outMember.Type) sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, s); err != nil {\n", funcName), args) } else { 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("return err\n", nil) sw.Do("}\n", nil) case types.Alias: if outMember.Type.IsAssignable() { if m.Type == outMember.Type { sw.Do("out.$.name$ = in.$.name$\n", args) } else { sw.Do("out.$.name$ = $.outType|raw$(in.$.name$)\n", args) } } else { if g.convertibleOnlyWithinPackage(m.Type, outMember.Type) { funcName := g.funcNameTmpl(m.Type, outMember.Type) sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, s); err != nil {\n", funcName), args) } else { 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("return err\n", nil) sw.Do("}\n", nil) } default: if g.convertibleOnlyWithinPackage(m.Type, outMember.Type) { funcName := g.funcNameTmpl(m.Type, outMember.Type) sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, s); err != nil {\n", funcName), args) } else { 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("return err\n", nil) sw.Do("}\n", nil) } } }
func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = new($.Elem|raw$)\n", t) if hasDeepCopyMethod(t.Elem) { sw.Do("**out = in.DeepCopy()\n", nil) } else if t.Elem.IsAssignable() { sw.Do("**out = *in", nil) } else if g.copyableAndInBounds(t.Elem) { funcName := g.funcNameTmpl(t.Elem) sw.Do(fmt.Sprintf("if err := %s(*in, *out, c); err != nil {\n", funcName), argsFromType(t.Elem)) sw.Do("return err\n", nil) sw.Do("}\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(*in); err != nil {\n", nil) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("**out = newVal.($.|raw$)\n", t.Elem) sw.Do("}\n", nil) } }
func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = make($.|raw$)\n", t) if t.Key.IsAssignable() { sw.Do("for key, val := range in {\n", nil) if t.Elem.IsAssignable() { sw.Do("(*out)[key] = val\n", nil) } else { if copyableWithinPackage(t.Elem) { sw.Do("newVal := new($.|raw$)\n", t.Elem) funcName := g.funcNameTmpl(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("}\n", nil) sw.Do("(*out)[key] = *newVal\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(val); err != nil {\n", nil) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("(*out)[key] = newVal.($.|raw$)\n", t.Elem) sw.Do("}\n", nil) } } } else { // TODO: Implement it when necessary. sw.Do("for range in {\n", nil) sw.Do("// FIXME: Copying unassignable keys unsupported $.|raw$\n", t.Key) } sw.Do("}\n", nil) }
func (g *genConversion) generateConversion(inType, outType *types.Type, sw *generator.SnippetWriter) { funcName := g.funcNameTmpl(inType, outType) sw.Do(fmt.Sprintf("func auto%s(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", funcName), g.withGlobals(argsFromType(inType, outType))) // if no defaulter of form SetDefaults_XXX is defined, do not inline a check for defaulting. if function, ok := g.manualDefaulters[inType]; ok { sw.Do("$.|raw$(in)\n", function) } g.generateFor(inType, outType, sw) sw.Do("return nil\n", nil) sw.Do("}\n\n", nil) // If there is no public manual Conversion method, generate it. 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(fmt.Sprintf("return auto%s(in, out, s)\n", funcName), argsFromType(inType, outType)) sw.Do("}\n\n", nil) } }
func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) { for _, m := range t.Members { args := map[string]interface{}{ "type": m.Type, "name": m.Name, } switch m.Type.Kind { case types.Builtin: sw.Do("out.$.name$ = in.$.name$\n", args) case types.Map, types.Slice, types.Pointer: sw.Do("if in.$.name$ != nil {\n", args) sw.Do("in, out := in.$.name$, &out.$.name$\n", args) g.generateFor(m.Type, sw) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = nil\n", args) sw.Do("}\n", nil) case types.Struct: if copyableWithinPackage(m.Type) { funcName := g.funcNameTmpl(m.Type) 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("}\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(in.$.name$); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = newVal.($.type|raw$)\n", args) sw.Do("}\n", nil) } default: if m.Type.Kind == types.Alias && m.Type.Underlying.Kind == types.Builtin { sw.Do("out.$.name$ = in.$.name$\n", args) } else { sw.Do("if in.$.name$ == nil {\n", args) sw.Do("out.$.name$ = nil\n", args) sw.Do("} else if newVal, err := c.DeepCopy(in.$.name$); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = newVal.($.type|raw$)\n", args) sw.Do("}\n", nil) } } } }
func (g *genConversion) generateConversion(inType, outType *types.Type, sw *generator.SnippetWriter) { args := argsFromType(inType, outType). With("Scope", types.Ref(conversionPackagePath, "Scope")) 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 function, ok := g.manualDefaulters[inType]; ok { sw.Do("$.|raw$(in)\n", function) } g.generateFor(inType, outType, sw) sw.Do("return nil\n", nil) sw.Do("}\n\n", nil) // If there is no public manual Conversion method, generate it. if _, ok := g.preexists(inType, outType); !ok { sw.Do("func "+nameTmpl+"(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", args) sw.Do("return auto"+nameTmpl+"(in, out, s)\n", args) sw.Do("}\n\n", nil) } }
func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = new($.Elem|raw$)\n", t) if t.Elem.Kind == types.Builtin { sw.Do("**out = *in", nil) } else if copyableWithinPackage(t.Elem) { funcName := g.funcNameTmpl(t.Elem) sw.Do(fmt.Sprintf("if err := %s(*in, *out, c); err != nil {\n", funcName), argsFromType(t.Elem)) sw.Do("return err\n", nil) sw.Do("}\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(*in); err != nil {\n", nil) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("**out = newVal.($.|raw$)\n", t.Elem) sw.Do("}\n", nil) } }
func (g *genConversion) doMap(inType, outType *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = make($.|raw$, len(*in))\n", outType) if isDirectlyAssignable(inType.Key, outType.Key) { sw.Do("for key, val := range *in {\n", nil) if isDirectlyAssignable(inType.Elem, outType.Elem) { if inType.Key == outType.Key { sw.Do("(*out)[key] = ", nil) } else { sw.Do("(*out)[$.|raw$(key)] = ", outType.Key) } if inType.Elem == outType.Elem { sw.Do("val\n", nil) } else { sw.Do("$.|raw$(val)\n", outType.Elem) } } else { sw.Do("newVal := new($.|raw$)\n", outType.Elem) if function, ok := g.preexists(inType.Elem, outType.Elem); ok { sw.Do("if err := $.|raw$(&val, newVal, s); err != nil {\n", function) } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { sw.Do("if err := "+nameTmpl+"(&val, newVal, s); err != nil {\n", argsFromType(inType.Elem, outType.Elem)) } else { 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("return err\n", nil) sw.Do("}\n", nil) if inType.Key == outType.Key { sw.Do("(*out)[key] = *newVal\n", nil) } else { sw.Do("(*out)[$.|raw$(key)] = *newVal\n", outType.Key) } } } else { // TODO: Implement it when necessary. sw.Do("for range *in {\n", nil) sw.Do("// FIXME: Converting unassignable keys unsupported $.|raw$\n", inType.Key) } sw.Do("}\n", nil) }
func (b bodyGen) doStruct(sw *generator.SnippetWriter) error { if len(b.t.Name.Name) == 0 { return nil } if namer.IsPrivateGoName(b.t.Name.Name) { return nil } var alias *types.Type var fields []protoField options := []string{} allOptions := types.ExtractCommentTags("+", b.t.CommentLines) for k, v := range allOptions { switch { case strings.HasPrefix(k, "protobuf.options."): key := strings.TrimPrefix(k, "protobuf.options.") switch key { case "marshal": if v == "false" { if !b.omitGogo { options = append(options, "(gogoproto.marshaler) = false", "(gogoproto.unmarshaler) = false", "(gogoproto.sizer) = false", ) } } default: if !b.omitGogo || !strings.HasPrefix(key, "(gogoproto.") { options = append(options, fmt.Sprintf("%s = %s", key, v)) } } // protobuf.as allows a type to have the same message contents as another Go type case k == "protobuf.as": fields = nil if alias = b.locator.GoTypeForName(types.Name{Name: v}); alias == nil { return fmt.Errorf("type %v references alias %q which does not exist", b.t, v) } // protobuf.embed instructs the generator to use the named type in this package // as an embedded message. case k == "protobuf.embed": fields = []protoField{ { Tag: 1, Name: v, Type: &types.Type{ Name: types.Name{ Name: v, Package: b.localPackage.Package, Path: b.localPackage.Path, }, }, }, } } } if alias == nil { alias = b.t } // If we don't explicitly embed anything, generate fields by traversing fields. if fields == nil { memberFields, err := membersToFields(b.locator, alias, b.localPackage, b.omitFieldTypes) if err != nil { return fmt.Errorf("type %v cannot be converted to protobuf: %v", b.t, err) } fields = memberFields } out := sw.Out() genComment(out, b.t.CommentLines, "") sw.Do(`message $.Name.Name$ { `, b.t) if len(options) > 0 { sort.Sort(sort.StringSlice(options)) for _, s := range options { fmt.Fprintf(out, " option %s;\n", s) } fmt.Fprintln(out) } for i, field := range fields { genComment(out, field.CommentLines, " ") fmt.Fprintf(out, " ") switch { case field.Map: case field.Repeated: fmt.Fprintf(out, "repeated ") case field.Required: fmt.Fprintf(out, "required ") default: fmt.Fprintf(out, "optional ") } sw.Do(`$.Type|local$ $.Name$ = $.Tag$`, field) if len(field.Extras) > 0 { extras := []string{} for k, v := range field.Extras { if b.omitGogo && strings.HasPrefix(k, "(gogoproto.") { continue } extras = append(extras, fmt.Sprintf("%s = %s", k, v)) } sort.Sort(sort.StringSlice(extras)) if len(extras) > 0 { fmt.Fprintf(out, " [") fmt.Fprint(out, strings.Join(extras, ", ")) fmt.Fprintf(out, "]") } } fmt.Fprintf(out, ";\n") if i != len(fields)-1 { fmt.Fprintf(out, "\n") } } fmt.Fprintf(out, "}\n\n") return nil }
func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.SnippetWriter) { for _, m := range inType.Members { // Check if this member is excluded from conversion if tagvals := extractTag(m.CommentLines); tagvals != nil && tagvals[0] == "false" { continue } outMember, isOutMember := findMember(outType, m.Name) if !isOutMember { // Since this object wasn't filtered out, this means that // this field has "+k8s:conversion-gen=false" comment to ignore it. continue } t, outT := m.Type, outMember.Type // create a copy of both underlying types but give them the top level alias name (since aliases // are assignable) if underlying := unwrapAlias(t); underlying != t { copied := *underlying copied.Name = t.Name t = &copied } if underlying := unwrapAlias(outT); underlying != outT { copied := *underlying copied.Name = outT.Name outT = &copied } args := map[string]interface{}{ "inType": t, "outType": outT, "name": m.Name, } // check based on the top level name, not the underlying names if function, ok := g.preexists(m.Type, outMember.Type); ok { args["function"] = function sw.Do("if err := $.function|raw$(&in.$.name$, &out.$.name$, s); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("}\n", nil) continue } switch t.Kind { case types.Builtin: if t == outT { sw.Do("out.$.name$ = in.$.name$\n", args) } else { sw.Do("out.$.name$ = $.outType|raw$(in.$.name$)\n", args) } case types.Map, types.Slice, types.Pointer: if g.isDirectlyAssignable(t, outT) { sw.Do("out.$.name$ = in.$.name$\n", args) continue } sw.Do("if in.$.name$ != nil {\n", args) sw.Do("in, out := &in.$.name$, &out.$.name$\n", args) g.generateFor(t, outT, sw) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = nil\n", args) sw.Do("}\n", nil) case types.Struct: if g.isDirectlyAssignable(t, outT) { sw.Do("out.$.name$ = in.$.name$\n", args) continue } if g.convertibleOnlyWithinPackage(t, outT) { sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) } else { 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("return err\n", nil) sw.Do("}\n", nil) case types.Alias: if isDirectlyAssignable(t, outT) { if t == outT { sw.Do("out.$.name$ = in.$.name$\n", args) } else { sw.Do("out.$.name$ = $.outType|raw$(in.$.name$)\n", args) } } else { if g.convertibleOnlyWithinPackage(t, outT) { sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) } else { 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("return err\n", nil) sw.Do("}\n", nil) } default: if g.convertibleOnlyWithinPackage(t, outT) { sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) } else { 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("return err\n", nil) sw.Do("}\n", nil) } } }
func (g *genDeepCopy) doBuiltin(t *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = in\n", nil) }
func (g *genConversion) doUnknown(inType, outType *types.Type, sw *generator.SnippetWriter) { sw.Do("// FIXME: Type $.|raw$ is unsupported.\n", inType) }
func (b bodyGen) doStruct(sw *generator.SnippetWriter) error { if len(b.t.Name.Name) == 0 { return nil } if isPrivateGoName(b.t.Name.Name) { return nil } var fields []protoField options := []string{} allOptions := types.ExtractCommentTags("+", b.t.CommentLines) for k, v := range allOptions { switch { case strings.HasPrefix(k, "protobuf.options."): key := strings.TrimPrefix(k, "protobuf.options.") switch key { case "marshal": if v == "false" { if !b.omitGogo { options = append(options, "(gogoproto.marshaler) = false", "(gogoproto.unmarshaler) = false", "(gogoproto.sizer) = false", ) } } default: if !b.omitGogo || !strings.HasPrefix(key, "(gogoproto.") { options = append(options, fmt.Sprintf("%s = %s", key, v)) } } case k == "protobuf.embed": fields = []protoField{ { Tag: 1, Name: v, Type: &types.Type{ Name: types.Name{ Name: v, Package: b.localPackage.Package, Path: b.localPackage.Path, }, }, }, } } } if fields == nil { memberFields, err := membersToFields(b.locator, b.t, b.localPackage, b.omitFieldTypes) if err != nil { return fmt.Errorf("type %v cannot be converted to protobuf: %v", b.t, err) } fields = memberFields } out := sw.Out() genComment(out, b.t.CommentLines, "") sw.Do(`message $.Name.Name$ { `, b.t) if len(options) > 0 { sort.Sort(sort.StringSlice(options)) for _, s := range options { fmt.Fprintf(out, " option %s;\n", s) } fmt.Fprintln(out) } for i, field := range fields { genComment(out, field.CommentLines, " ") fmt.Fprintf(out, " ") switch { case field.Map: case field.Repeated: fmt.Fprintf(out, "repeated ") case field.Required: fmt.Fprintf(out, "required ") default: fmt.Fprintf(out, "optional ") } sw.Do(`$.Type|local$ $.Name$ = $.Tag$`, field) if len(field.Extras) > 0 { extras := []string{} for k, v := range field.Extras { if b.omitGogo && strings.HasPrefix(k, "(gogoproto.") { continue } extras = append(extras, fmt.Sprintf("%s = %s", k, v)) } sort.Sort(sort.StringSlice(extras)) if len(extras) > 0 { fmt.Fprintf(out, " [") fmt.Fprint(out, strings.Join(extras, ", ")) fmt.Fprintf(out, "]") } } fmt.Fprintf(out, ";\n") if i != len(fields)-1 { fmt.Fprintf(out, "\n") } } fmt.Fprintf(out, "}\n\n") return nil }