func()

in codegen/type_converter.go [651:930]


func (c *TypeConverter) genStructConverter(
	keyPrefix string,
	fromPrefix string,
	indent string,
	fromFields []*compile.FieldSpec,
	toFields []*compile.FieldSpec,
	fieldMap map[string]FieldMapperEntry,
	prevKeyPrefixes []string,
) error {

	for i := 0; i < len(toFields); i++ {
		toField := toFields[i]

		// Check for same named field
		var fromField *compile.FieldSpec
		for j := 0; j < len(fromFields); j++ {
			if fromFields[j].Name == toField.Name {
				fromField = fromFields[j]
				break
			}
		}

		toSubIdentifier := keyPrefix + PascalCase(toField.Name)
		toIdentifier := "out." + toSubIdentifier
		overriddenIdentifier := ""
		fromIdentifier := ""

		// Check for mapped field
		var overriddenField *compile.FieldSpec

		// check if this toField satisfies a fieldMap transform
		transformFrom, ok := fieldMap[toSubIdentifier]
		if ok {
			// no existing direct fromField,  just assign the transform
			if fromField == nil {
				fromField = transformFrom.Field
				if c.useRecurGen {
					fromIdentifier = "inOriginal." + transformFrom.QualifiedName
				} else {
					fromIdentifier = "in." + transformFrom.QualifiedName
				}
				// else there is a conflicting direct fromField
			} else {
				//  depending on Override flag either the direct fromField or transformFrom is the OverrideField
				if transformFrom.Override {
					// check for required/optional setting
					if !transformFrom.Field.Required {
						overriddenField = fromField
						overriddenIdentifier = "in." + fromPrefix +
							PascalCase(overriddenField.Name)
					}
					// If override is true and the new field is required,
					// there's a default instantiation value and will always
					// overwrite.
					fromField = transformFrom.Field
					if c.useRecurGen {
						fromIdentifier = "inOriginal." + transformFrom.QualifiedName
					} else {
						fromIdentifier = "in." + transformFrom.QualifiedName
					}
				} else {
					// If override is false and the from field is required,
					// From is always populated and will never be overwritten.
					if !fromField.Required {
						overriddenField = transformFrom.Field
						if c.useRecurGen {
							fromIdentifier = "inOriginal." + transformFrom.QualifiedName
						} else {
							overriddenIdentifier = "in." + transformFrom.QualifiedName
						}
					}
				}
			}
		}

		// neither direct or transform fromField was found
		if fromField == nil {
			// search the fieldMap toField identifiers for matching identifier prefix
			// e.g.  the current toField is a struct and something within it has a transform
			//   a full match identifiers for transform non-struct types would have been caught above
			hasStructFieldMapping := false
			for toID := range fieldMap {
				if strings.HasPrefix(toID, toSubIdentifier) {
					hasStructFieldMapping = true
				}
			}

			//  if there's no fromField and no fieldMap transform that could be applied
			if !hasStructFieldMapping {
				var bypass bool
				// check if required field is filled from other resources
				// it can be used to set system default (customized tracing /auth required for clients),
				// or header propagating
				if c.optionalEntries != nil {
					for toID := range c.optionalEntries {
						if strings.HasPrefix(toID, toSubIdentifier) {
							bypass = true
							break
						}
					}
				}

				// the toField is either covered by optionalEntries, or optional and
				// there's nothing that maps to it or its sub-fields so we should skip it
				if bypass || !toField.Required {
					continue
				}

				// unrecoverable error
				return errors.Errorf(
					"required toField %s does not have a valid fromField mapping",
					toField.Name,
				)
			}
		}

		if fromIdentifier == "" && fromField != nil {
			// should we set this if no fromField ??
			fromIdentifier = "in." + fromPrefix + PascalCase(fromField.Name)
		}

		if prevKeyPrefixes == nil {
			prevKeyPrefixes = []string{}
		}

		var overriddenFieldName string
		var overriddenFieldType compile.TypeSpec
		if overriddenField != nil {
			overriddenFieldName = overriddenField.Name
			overriddenFieldType = overriddenField.Type
		}

		// Override thrift type names to avoid naming collisions between endpoint
		// and client types.
		switch toFieldType := compile.RootTypeSpec(toField.Type).(type) {
		case
			*compile.BoolSpec,
			*compile.I8Spec,
			*compile.I16Spec,
			*compile.I32Spec,
			*compile.EnumSpec,
			*compile.I64Spec,
			*compile.DoubleSpec,
			*compile.StringSpec:

			err := c.genConverterForPrimitive(
				toField,
				toIdentifier,
				fromField,
				fromIdentifier,
				overriddenField,
				overriddenIdentifier,
				indent,
				prevKeyPrefixes,
			)
			if err != nil {
				return err
			}
		case *compile.BinarySpec:
			for _, line := range checkOptionalNil(indent, c.uninitialized, toIdentifier, prevKeyPrefixes, c.useRecurGen) {
				c.append(line)
			}
			c.append(toIdentifier, " = []byte(", fromIdentifier, ")")
		case *compile.StructSpec:
			var (
				stFromPrefix = fromPrefix
				stFromType   compile.TypeSpec
				fromTypeName string
			)
			if fromField != nil {
				stFromType = fromField.Type
				stFromPrefix = fromPrefix + PascalCase(fromField.Name)

				fromTypeName, _ = c.getIdentifierName(stFromType)
			}

			toTypeName, err := c.getIdentifierName(toFieldType)
			if err != nil {
				return err
			}

			if converterMethodName, ok := c.convStructMap[toFieldType.Name]; ok {
				// the converter for this struct has already been generated, so just use it
				c.append(indent, "out.", keyPrefix+PascalCase(toField.Name), " = ", converterMethodName, "(", fromIdentifier, ")")
			} else if c.useRecurGen && fromTypeName != "" {
				// generate a callable converter inside function literal
				err = c.genConverterForStructWrapped(
					toField,
					toFieldType,
					toTypeName,
					toSubIdentifier,
					fromTypeName,
					fromIdentifier,
					stFromType,
					fieldMap,
					prevKeyPrefixes,
					indent,
				)
			} else {
				err = c.genConverterForStruct(
					toField.Name,
					toFieldType,
					toField.Required,
					stFromType,
					fromIdentifier,
					keyPrefix+PascalCase(toField.Name),
					stFromPrefix,
					indent,
					fieldMap,
					prevKeyPrefixes,
				)
			}
			if err != nil {
				return err
			}
		case *compile.ListSpec:
			err := c.genConverterForList(
				toFieldParam{
					toFieldType,
					toField.Name,
					toField.Required,
					toIdentifier,
				},
				fromFieldParam{
					fromField.Type,
					fromField.Name,
					fromIdentifier,
					fromIdentifier,
				},
				overriddenFieldParam{
					overriddenFieldType,
					overriddenFieldName,
					overriddenIdentifier,
				},
				indent,
			)
			if err != nil {
				return err
			}
		case *compile.MapSpec:
			err := c.genConverterForMap(
				toFieldParam{
					toFieldType,
					toField.Name,
					toField.Required,
					toIdentifier,
				},
				fromFieldParam{
					fromField.Type,
					fromField.Name,
					fromIdentifier,
					fromIdentifier,
				},
				overriddenFieldParam{
					overriddenFieldType,
					overriddenFieldName,
					overriddenIdentifier,
				},
				indent,
			)
			if err != nil {
				return err
			}
		default:
			// fmt.Printf("Unknown type %s for field %s \n",
			// 	toField.Type.TypeCode().String(), toField.Name,
			// )

			// pkgName, err := h.TypePackageName(toField.Type.IDLFile())
			// if err != nil {
			// 	return nil, err
			// }
			// typeName := pkgName + "." + toField.Type.ThriftName()
			// line := toIdentifier + "(*" + typeName + ")" + postfix
			// c.Lines = append(c.Lines, line)
		}
	}

	return nil
}