Beispiel #1
0
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)
	}
}
Beispiel #2
0
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)
	}
}
Beispiel #3
0
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)
	}
}
Beispiel #4
0
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)
	}
}
Beispiel #5
0
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)
	}
}
Beispiel #6
0
func (g *genDeepCopy) doUnknown(t *types.Type, sw *generator.SnippetWriter) {
	sw.Do("// FIXME: Type $.|raw$ is unsupported.\n", t)
}
Beispiel #7
0
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)
	}
}
Beispiel #8
0
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)
		}
	}
}
Beispiel #9
0
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)
	}
}
Beispiel #10
0
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)
	}
}
Beispiel #11
0
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)
	}
}
Beispiel #12
0
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)
	}
}
Beispiel #13
0
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)
		}
	}
}
Beispiel #14
0
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)
	}
}
Beispiel #15
0
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)
	}
}
Beispiel #16
0
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)
	}
}
Beispiel #17
0
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)
		}
	}
}
Beispiel #18
0
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)
	}
}
Beispiel #19
0
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)
}
Beispiel #20
0
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)
	}
}
Beispiel #21
0
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)
			}
		}
	}
}
Beispiel #22
0
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)
	}
}
Beispiel #23
0
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)
	}
}
Beispiel #24
0
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)
}
Beispiel #25
0
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
}
Beispiel #26
0
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)
		}
	}
}
Beispiel #27
0
func (g *genDeepCopy) doBuiltin(t *types.Type, sw *generator.SnippetWriter) {
	sw.Do("*out = in\n", nil)
}
Beispiel #28
0
func (g *genConversion) doUnknown(inType, outType *types.Type, sw *generator.SnippetWriter) {
	sw.Do("// FIXME: Type $.|raw$ is unsupported.\n", inType)
}
Beispiel #29
0
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
}