in dev/tools/controllerbuilder/pkg/codegen/mappergenerator.go [209:645]
func (v *MapperGenerator) writeMapFunctionsForPair(out io.Writer, srcDir string, pair *typePair) {
klog.V(2).InfoS("writeMapFunctionsForPair", "pair.Proto.FullName", pair.Proto.FullName(), "pair.KRMType.Name", pair.KRMType.Name)
msg := pair.Proto
pbTypeName := protoNameForType(msg)
goType := pair.KRMType
goTypeName := goType.Name
goFields := make(map[string]*gocode.StructField)
for _, f := range goType.Fields {
goFields[f.Name] = f
}
krmImportName := getKRMImportName(pair.KRMType.GoPackage)
if v.findFuncDeclaration(goTypeName+"_FromProto", srcDir, true) == nil {
fmt.Fprintf(out, "func %s_FromProto(mapCtx *direct.MapContext, in *pb.%s) *%s.%s {\n", goTypeName, pbTypeName, krmImportName, goTypeName)
fmt.Fprintf(out, "\tif in == nil {\n")
fmt.Fprintf(out, "\t\treturn nil\n")
fmt.Fprintf(out, "\t}\n")
fmt.Fprintf(out, "\tout := &%s.%s{}\n", krmImportName, goTypeName)
for i := 0; i < msg.Fields().Len(); i++ {
protoField := msg.Fields().Get(i)
protoFieldName := protoNameForField(protoField)
protoAccessor := "Get" + protoFieldName + "()"
krmFieldName := goFieldName(protoField)
krmField := goFields[krmFieldName]
if krmField == nil {
// Support refs
krmFieldRef := goFields[krmFieldName+"Ref"]
if krmFieldRef != nil {
fmt.Fprintf(out, "\tif in.%s != \"\" {\n", protoAccessor)
fmt.Fprintf(out, "\t out.%v = &refs.%v{External: in.%v}\n", krmFieldRef.Name, strings.TrimPrefix(krmFieldRef.Type, "*refs."), protoAccessor)
fmt.Fprintf(out, "\t}\n")
continue
}
if !v.fieldExistInCounterpartStruct(goType, krmFieldName) && !v.fieldExistInCounterpartStruct(goType, krmFieldName+"Ref") { // special handling for Spec and ObservedState structs which map to the same proto message.
fmt.Fprintf(out, "\t// MISSING: %s\n", krmFieldName)
for k := range goFields {
if strings.EqualFold(k, krmFieldName) {
fmt.Fprintf(out, "\t// (near miss): %q vs %q\n", krmFieldName, k)
}
}
}
continue
}
if protoField.Cardinality() == protoreflect.Repeated {
useSliceFromProtoFunction := ""
useCustomMethod := ""
switch protoField.Kind() {
case protoreflect.MessageKind:
krmElemTypeName := krmField.Type
krmElemTypeName = strings.TrimPrefix(krmElemTypeName, "*")
krmElemTypeName = strings.TrimPrefix(krmElemTypeName, "[]")
functionName := krmElemTypeName + "_FromProto"
useSliceFromProtoFunction = functionName
case protoreflect.StringKind:
if krmField.Type != "[]string" {
useCustomMethod = fmt.Sprintf("%s_%s_FromProto", goTypeName, protoFieldName)
}
case protoreflect.EnumKind:
krmElemTypeName := krmField.Type
krmElemTypeName = strings.TrimPrefix(krmElemTypeName, "*")
krmElemTypeName = strings.TrimPrefix(krmElemTypeName, "[]")
useCustomMethod = "direct.EnumSlice_FromProto"
case
protoreflect.FloatKind,
protoreflect.DoubleKind,
protoreflect.BoolKind,
protoreflect.Int64Kind,
protoreflect.Int32Kind,
protoreflect.Uint32Kind,
protoreflect.Uint64Kind,
protoreflect.BytesKind:
useSliceFromProtoFunction = ""
default:
klog.Fatalf("unhandled kind %q for repeated field %v", protoField.Kind(), protoField)
}
if protoField.IsMap() {
entryMsg := protoField.Message()
keyKind := entryMsg.Fields().ByName("key").Kind()
valueKind := entryMsg.Fields().ByName("value").Kind()
if keyKind == protoreflect.StringKind && valueKind == protoreflect.StringKind {
useSliceFromProtoFunction = ""
} else if keyKind == protoreflect.StringKind && valueKind == protoreflect.Int64Kind {
useSliceFromProtoFunction = ""
} else {
fmt.Fprintf(out, "\t// TODO: map type %v %v for field %v\n", keyKind, valueKind, krmFieldName)
continue
}
}
if useSliceFromProtoFunction != "" {
fmt.Fprintf(out, "\tout.%s = direct.Slice_FromProto(mapCtx, in.%s, %s)\n",
krmFieldName,
krmFieldName,
useSliceFromProtoFunction,
)
} else if useCustomMethod != "" {
fmt.Fprintf(out, "\tout.%s = %s(mapCtx, in.%s)\n",
krmFieldName,
useCustomMethod,
protoFieldName,
)
} else {
fmt.Fprintf(out, "\tout.%s = in.%s\n",
krmFieldName,
protoFieldName,
)
}
continue
}
switch protoField.Kind() {
case protoreflect.MessageKind:
krmTypeName := krmField.Type
krmTypeName = strings.TrimPrefix(krmTypeName, "*")
functionName := krmTypeName + "_FromProto"
switch krmTypeName {
case "string":
functionName = string(msg.Name()) + "_" + krmFieldName + "_FromProto"
}
// special handling for proto messages that mapped to KRM string
if _, ok := protoMessagesNotMappedToGoStruct[string(protoField.Message().FullName())]; ok {
functionName = krmFromProtoFunctionName(protoField, krmField.Name)
}
fmt.Fprintf(out, "\tout.%s = %s(mapCtx, in.%s)\n",
krmFieldName,
functionName,
protoAccessor,
)
case protoreflect.EnumKind:
functionName := "direct.Enum_FromProto"
// Not needed if we use the accessor:
// protoTypeName := "pb." + protoNameForEnum(protoField.Enum())
// if protoIsPointerInGo(protoField) {
// functionName = "EnumPtr_FromProto[" + protoTypeName + "]"
// }
fmt.Fprintf(out, "\tout.%s = %s(mapCtx, in.%s)\n",
krmFieldName,
functionName,
protoAccessor,
)
case protoreflect.StringKind,
protoreflect.FloatKind,
protoreflect.DoubleKind,
protoreflect.BoolKind,
protoreflect.Int64Kind,
protoreflect.Int32Kind,
protoreflect.Uint32Kind,
protoreflect.Uint64Kind,
protoreflect.Fixed64Kind:
if protoIsPointerInGo(protoField) {
fmt.Fprintf(out, "\tout.%s = in.%s\n",
krmFieldName,
protoFieldName,
)
} else {
fmt.Fprintf(out, "\tout.%s = direct.LazyPtr(in.%s)\n",
krmFieldName,
protoAccessor,
)
}
case protoreflect.BytesKind:
fmt.Fprintf(out, "\tout.%s = in.%s\n",
krmFieldName,
protoAccessor,
)
default:
klog.Fatalf("unhandled kind %q for field %v", protoField.Kind(), protoField)
}
}
fmt.Fprintf(out, "\treturn out\n")
fmt.Fprintf(out, "}\n")
} else {
klog.Infof("found existing non-generated mapping function %q, won't generate", goTypeName+"_FromProto")
}
if v.findFuncDeclaration(goTypeName+"_ToProto", srcDir, true) == nil {
fmt.Fprintf(out, "func %s_ToProto(mapCtx *direct.MapContext, in *%s.%s) *pb.%s {\n", goTypeName, krmImportName, goTypeName, pbTypeName)
fmt.Fprintf(out, "\tif in == nil {\n")
fmt.Fprintf(out, "\t\treturn nil\n")
fmt.Fprintf(out, "\t}\n")
fmt.Fprintf(out, "\tout := &pb.%s{}\n", pbTypeName)
for i := 0; i < msg.Fields().Len(); i++ {
protoField := msg.Fields().Get(i)
protoFieldName := protoNameForField(protoField)
krmFieldName := goFieldName(protoField)
krmField := goFields[krmFieldName]
if krmField == nil {
// Support refs
krmFieldRef := goFields[krmFieldName+"Ref"]
if krmFieldRef != nil {
fmt.Fprintf(out, "\tif in.%s != nil {\n", krmFieldRef.Name)
fmt.Fprintf(out, "\t out.%v = in.%v.External\n", protoFieldName, krmFieldRef.Name)
fmt.Fprintf(out, "\t}\n")
continue
}
if !v.fieldExistInCounterpartStruct(goType, krmFieldName) && !v.fieldExistInCounterpartStruct(goType, krmFieldName+"Ref") { // special handling for spec and observedState structs which map to the same proto message.
fmt.Fprintf(out, "\t// MISSING: %s\n", krmFieldName)
for k := range goFields {
if strings.EqualFold(k, krmFieldName) {
fmt.Fprintf(out, "\t// (near miss): %q vs %q\n", krmFieldName, k)
}
}
}
continue
}
if protoField.Cardinality() == protoreflect.Repeated {
useSliceToProtoFunction := ""
useCustomMethod := ""
switch protoField.Kind() {
case protoreflect.MessageKind:
krmElemTypeName := krmField.Type
krmElemTypeName = strings.TrimPrefix(krmElemTypeName, "*")
krmElemTypeName = strings.TrimPrefix(krmElemTypeName, "[]")
functionName := krmElemTypeName + "_ToProto"
useSliceToProtoFunction = functionName
case protoreflect.StringKind:
if krmField.Type != "[]string" {
useCustomMethod = fmt.Sprintf("%s_%s_ToProto", goTypeName, protoFieldName)
}
case protoreflect.EnumKind:
krmElemTypeName := krmField.Type
krmElemTypeName = strings.TrimPrefix(krmElemTypeName, "*")
krmElemTypeName = strings.TrimPrefix(krmElemTypeName, "[]")
protoTypeName := "pb." + protoNameForEnum(protoField.Enum())
useCustomMethod = fmt.Sprintf("direct.EnumSlice_ToProto[%s]", protoTypeName)
case protoreflect.FloatKind,
protoreflect.DoubleKind,
protoreflect.BoolKind,
protoreflect.Int64Kind,
protoreflect.Int32Kind,
protoreflect.Uint32Kind,
protoreflect.Uint64Kind,
protoreflect.BytesKind:
useSliceToProtoFunction = ""
default:
klog.Fatalf("unhandled kind %q for repeated field %v", protoField.Kind(), protoField)
}
if protoField.IsMap() {
entryMsg := protoField.Message()
keyKind := entryMsg.Fields().ByName("key").Kind()
valueKind := entryMsg.Fields().ByName("value").Kind()
if keyKind == protoreflect.StringKind && valueKind == protoreflect.StringKind {
useSliceToProtoFunction = ""
} else if keyKind == protoreflect.StringKind && valueKind == protoreflect.Int64Kind {
useSliceToProtoFunction = ""
} else {
fmt.Fprintf(out, "\t// TODO: map type %v %v for field %v\n", keyKind, valueKind, krmFieldName)
continue
}
}
if useSliceToProtoFunction != "" {
fmt.Fprintf(out, "\tout.%s = direct.Slice_ToProto(mapCtx, in.%s, %s)\n",
protoFieldName,
krmFieldName,
useSliceToProtoFunction,
)
} else if useCustomMethod != "" {
fmt.Fprintf(out, "\tout.%s = %s(mapCtx, in.%s)\n",
krmFieldName,
useCustomMethod,
krmFieldName,
)
} else {
fmt.Fprintf(out, "\tout.%s = in.%s\n",
protoFieldName,
krmFieldName,
)
}
continue
}
switch protoField.Kind() {
case protoreflect.MessageKind:
krmTypeName := krmField.Type
krmTypeName = strings.TrimPrefix(krmTypeName, "*")
functionName := krmTypeName + "_ToProto"
switch krmTypeName {
case "string":
functionName = string(msg.Name()) + "_" + krmFieldName + "_ToProto"
}
// special handling for proto messages that mapped to KRM string
if _, ok := protoMessagesNotMappedToGoStruct[string(protoField.Message().FullName())]; ok {
functionName = krmToProtoFunctionName(protoField, krmField.Name)
}
oneof := protoField.ContainingOneof()
if oneof != nil {
fmt.Fprintf(out, "\tif oneof := %s(mapCtx, in.%s); oneof != nil {\n",
functionName,
krmFieldName,
)
oneofFieldName := ToGoFieldName(oneof.Name())
oneofTypeName := protoNameForOneOf(protoField)
fmt.Fprintf(out, "\t\tout.%s = &pb.%s{%s: oneof}\n",
oneofFieldName,
oneofTypeName,
protoFieldName)
fmt.Fprintf(out, "\t}\n")
continue
}
fmt.Fprintf(out, "\tout.%s = %s(mapCtx, in.%s)\n",
protoFieldName,
functionName,
krmFieldName,
)
case protoreflect.EnumKind:
protoTypeName := "pb." + protoNameForEnum(protoField.Enum())
functionName := "direct.Enum_ToProto"
if protoIsPointerInGo(protoField) {
functionName = "EnumPtr_ToProto[" + protoTypeName + "]"
}
oneof := protoField.ContainingOneof()
if oneof != nil {
// These are very rare and irregular; just require a custom method
functionName := fmt.Sprintf("%s_%s_ToProto", goTypeName, protoFieldName)
fmt.Fprintf(out, "\tif oneof := %s(mapCtx, in.%s); oneof != nil {\n",
functionName,
krmFieldName,
)
oneofFieldName := ToGoFieldName(oneof.Name())
fmt.Fprintf(out, "\t\tout.%s = oneof\n",
oneofFieldName)
fmt.Fprintf(out, "\t}\n")
continue
}
fmt.Fprintf(out, "\tout.%s = %s[%s](mapCtx, in.%s)\n",
protoFieldName,
functionName,
protoTypeName,
krmFieldName,
)
case protoreflect.StringKind,
protoreflect.FloatKind,
protoreflect.DoubleKind,
protoreflect.BoolKind,
protoreflect.Int64Kind,
protoreflect.Int32Kind,
protoreflect.Uint32Kind,
protoreflect.Uint64Kind,
protoreflect.Fixed64Kind,
protoreflect.BytesKind:
useCustomMethod := ""
switch protoField.Kind() {
case protoreflect.StringKind:
if krmField.Type != "*string" {
useCustomMethod = fmt.Sprintf("%s_%s_ToProto", goTypeName, protoFieldName)
}
}
oneof := protoField.ContainingOneof()
if protoField.HasOptionalKeyword() {
fmt.Fprintf(out, "\tout.%s = in.%s\n",
protoFieldName,
krmFieldName,
)
} else if oneof != nil {
functionName := fmt.Sprintf("%s_%s_ToProto", goTypeName, protoFieldName)
fmt.Fprintf(out, "\tif oneof := %s(mapCtx, in.%s); oneof != nil {\n",
functionName,
krmFieldName,
)
oneofFieldName := ToGoFieldName(oneof.Name())
fmt.Fprintf(out, "\t\tout.%s = oneof\n",
oneofFieldName)
fmt.Fprintf(out, "\t}\n")
} else if useCustomMethod != "" {
fmt.Fprintf(out, "\tout.%s = %s(mapCtx, in.%s)\n",
krmFieldName,
useCustomMethod,
krmFieldName,
)
} else if protoField.Kind() == protoreflect.BytesKind {
fmt.Fprintf(out, "\tout.%s = in.%s\n",
protoFieldName,
krmFieldName,
)
} else {
fmt.Fprintf(out, "\tout.%s = direct.ValueOf(in.%s)\n",
protoFieldName,
krmFieldName,
)
}
default:
klog.Fatalf("unhandled kind %q for field %v", protoField.Kind(), protoField)
}
}
fmt.Fprintf(out, "\treturn out\n")
fmt.Fprintf(out, "}\n")
} else {
klog.Infof("found existing non-generated mapping function %q, won't generate", goTypeName+"_ToProto")
}
}