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
}