Explorar el Código

#81 handle field name conflict properly

Tao Wen hace 8 años
padre
commit
09cb1d9236
Se han modificado 2 ficheros con 100 adiciones y 44 borrados
  1. 6 4
      feature_reflect_extension.go
  2. 94 40
      feature_reflect_object.go

+ 6 - 4
feature_reflect_extension.go

@@ -31,6 +31,7 @@ func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding {
 }
 
 type Binding struct {
+	levels    []int
 	Field     *reflect.StructField
 	FromNames []string
 	ToNames   []string
@@ -206,6 +207,7 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
 					return nil, err
 				}
 				for _, binding := range structDescriptor.Fields {
+					binding.levels = append([]int{i}, binding.levels...)
 					binding.Encoder = &structFieldEncoder{&field, binding.Encoder, false}
 					binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
 					if field.Offset == 0 {
@@ -221,12 +223,11 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
 					return nil, err
 				}
 				for _, binding := range structDescriptor.Fields {
-					cloneField := field
-					cloneField.Name = binding.Field.Name
+					binding.levels = append([]int{i}, binding.levels...)
 					binding.Encoder = &optionalEncoder{binding.Encoder}
-					binding.Encoder = &structFieldEncoder{&cloneField, binding.Encoder, false}
+					binding.Encoder = &structFieldEncoder{&field, binding.Encoder, false}
 					binding.Decoder = &deferenceDecoder{field.Type.Elem(), binding.Decoder}
-					binding.Decoder = &structFieldDecoder{&cloneField, binding.Decoder}
+					binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
 					if field.Offset == 0 {
 						headAnonymousBindings = append(headAnonymousBindings, binding)
 					} else {
@@ -266,6 +267,7 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
 			Decoder:   decoder,
 			Encoder:   encoder,
 		}
+		binding.levels = []int{i}
 		bindings = append(bindings, binding)
 	}
 	return createStructDescriptor(cfg, typ, bindings, headAnonymousBindings, tailAnonymousBindings), nil

+ 94 - 40
feature_reflect_object.go

@@ -8,48 +8,102 @@ import (
 )
 
 func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
-	fieldsByToName := map[string]int{}
-	orderedFields := []*structFieldTo{}
+	type bindingTo struct {
+		binding *Binding
+		toName  string
+		ignored bool
+	}
+	orderedBindings := []*bindingTo{}
 	structDescriptor, err := describeStruct(cfg, typ)
 	if err != nil {
 		return nil, err
 	}
-	for index, binding := range structDescriptor.Fields {
+	for _, binding := range structDescriptor.Fields {
 		for _, toName := range binding.ToNames {
-			oldIndex, found := fieldsByToName[toName]
-			if found {
-				orderedFields[oldIndex] = nil // replaced by the later one
+			new := &bindingTo{
+				binding: binding,
+				toName:  toName,
 			}
-			fieldsByToName[toName] = index
-			orderedFields = append(orderedFields, &structFieldTo{
-				binding.Encoder.(*structFieldEncoder),
-				toName,
-			})
+			for _, old := range orderedBindings {
+				if old.toName != toName {
+					continue
+				}
+				old.ignored, new.ignored = resolveConflictBinding(old.binding, new.binding)
+			}
+			orderedBindings = append(orderedBindings, new)
 		}
 	}
-	if len(orderedFields) == 0 {
+	if len(orderedBindings) == 0 {
 		return &emptyStructEncoder{}, nil
 	}
 	finalOrderedFields := []structFieldTo{}
-	for _, structFieldTo := range orderedFields {
-		if structFieldTo != nil {
-			finalOrderedFields = append(finalOrderedFields, *structFieldTo)
+	for _, bindingTo := range orderedBindings {
+		if !bindingTo.ignored {
+			finalOrderedFields = append(finalOrderedFields, structFieldTo{
+				encoder: bindingTo.binding.Encoder.(*structFieldEncoder),
+				toName:  bindingTo.toName,
+			})
+		}
+	}
+	return &structEncoder{structDescriptor.onePtrEmbedded, structDescriptor.onePtrOptimization, finalOrderedFields}, nil
+}
+
+func resolveConflictBinding(old, new *Binding) (ignoreOld, ignoreNew bool) {
+	newTagged := new.Field.Tag.Get("json") != ""
+	oldTagged := old.Field.Tag.Get("json") != ""
+	if newTagged {
+		if oldTagged {
+			if len(old.levels) > len(new.levels) {
+				return true, false
+			} else if len(new.levels) > len(old.levels) {
+				return false, true
+			} else {
+				return true, true
+			}
+		} else {
+			return true, false
+		}
+	} else {
+		if oldTagged {
+			return true, false
+		} else {
+			if len(old.levels) > len(new.levels) {
+				return true, false
+			} else if len(new.levels) > len(old.levels) {
+				return false, true
+			} else {
+				return true, true
+			}
 		}
 	}
-	return &structEncoder{structDescriptor.onePtrEmbedded,structDescriptor.onePtrOptimization,finalOrderedFields}, nil
 }
 
 func decoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) {
-	fields := map[string]*structFieldDecoder{}
+	bindings := map[string]*Binding{}
 	structDescriptor, err := describeStruct(cfg, typ)
 	if err != nil {
 		return nil, err
 	}
 	for _, binding := range structDescriptor.Fields {
 		for _, fromName := range binding.FromNames {
-			fields[fromName] = binding.Decoder.(*structFieldDecoder)
+			old := bindings[fromName]
+			if old == nil {
+				bindings[fromName] = binding
+				continue
+			}
+			ignoreOld, ignoreNew := resolveConflictBinding(old, binding)
+			if ignoreOld {
+				delete(bindings, fromName)
+			}
+			if !ignoreNew {
+				bindings[fromName] = binding
+			}
 		}
 	}
+	fields := map[string]*structFieldDecoder{}
+	for k, binding := range bindings {
+		fields[k] = binding.Decoder.(*structFieldDecoder)
+	}
 	return createStructDecoder(typ, fields)
 }
 
@@ -120,7 +174,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
 			}
 		}
 		return &threeFieldsStructDecoder{typ,
-			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
+										 fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
 	case 4:
 		var fieldName1 int32
 		var fieldName2 int32
@@ -153,8 +207,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
 			}
 		}
 		return &fourFieldsStructDecoder{typ,
-			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
-			fieldName4, fieldDecoder4}, nil
+										fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
+										fieldName4, fieldDecoder4}, nil
 	case 5:
 		var fieldName1 int32
 		var fieldName2 int32
@@ -192,8 +246,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
 			}
 		}
 		return &fiveFieldsStructDecoder{typ,
-			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
-			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil
+										fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
+										fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil
 	case 6:
 		var fieldName1 int32
 		var fieldName2 int32
@@ -236,8 +290,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
 			}
 		}
 		return &sixFieldsStructDecoder{typ,
-			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
-			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil
+									   fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
+									   fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil
 	case 7:
 		var fieldName1 int32
 		var fieldName2 int32
@@ -285,9 +339,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
 			}
 		}
 		return &sevenFieldsStructDecoder{typ,
-			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
-			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
-			fieldName7, fieldDecoder7}, nil
+										 fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
+										 fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
+										 fieldName7, fieldDecoder7}, nil
 	case 8:
 		var fieldName1 int32
 		var fieldName2 int32
@@ -340,9 +394,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
 			}
 		}
 		return &eightFieldsStructDecoder{typ,
-			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
-			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
-			fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil
+										 fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
+										 fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
+										 fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil
 	case 9:
 		var fieldName1 int32
 		var fieldName2 int32
@@ -400,9 +454,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
 			}
 		}
 		return &nineFieldsStructDecoder{typ,
-			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
-			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
-			fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil
+										fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
+										fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
+										fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil
 	case 10:
 		var fieldName1 int32
 		var fieldName2 int32
@@ -465,10 +519,10 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
 			}
 		}
 		return &tenFieldsStructDecoder{typ,
-			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
-			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
-			fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9,
-			fieldName10, fieldDecoder10}, nil
+									   fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
+									   fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
+									   fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9,
+									   fieldName10, fieldDecoder10}, nil
 	}
 	return &generalStructDecoder{typ, fields}, nil
 }
@@ -992,9 +1046,9 @@ func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool {
 }
 
 type structEncoder struct {
-	onePtrEmbedded bool
+	onePtrEmbedded     bool
 	onePtrOptimization bool
-	fields []structFieldTo
+	fields             []structFieldTo
 }
 
 type structFieldTo struct {