diff --git a/feature_reflect_extension.go b/feature_reflect_extension.go index e6e757a..098bfce 100644 --- a/feature_reflect_extension.go +++ b/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 diff --git a/feature_reflect_object.go b/feature_reflect_object.go index 9cfc225..f4634ce 100644 --- a/feature_reflect_object.go +++ b/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 {