func()

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")
	}

}