diff --git a/reflect_array.go b/reflect_array.go index 13a0b7b0..bc982ccd 100644 --- a/reflect_array.go +++ b/reflect_array.go @@ -2,9 +2,10 @@ package jsoniter import ( "fmt" - "github.com/modern-go/reflect2" "io" "unsafe" + + "github.com/modern-go/reflect2" ) func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder { @@ -13,13 +14,43 @@ func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder { return &arrayDecoder{arrayType, decoder} } +type ArrayEncoderConstructor struct { + ArrayType *reflect2.UnsafeArrayType + ElemEncoder ValEncoder + API API + DecorateFunc func(arrayEncoder ValEncoder) ValEncoder +} + +func updateArrayEncoderConstructor(v *ArrayEncoderConstructor, exts ...Extension) { + for _, ext := range exts { + if e, ok := ext.(interface { + UpdateArrayEncoderConstructor(v *ArrayEncoderConstructor) + }); ok { + e.UpdateArrayEncoderConstructor(v) + } + } +} + func encoderOfArray(ctx *ctx, typ reflect2.Type) ValEncoder { arrayType := typ.(*reflect2.UnsafeArrayType) if arrayType.Len() == 0 { return emptyArrayEncoder{} } - encoder := encoderOfType(ctx.append("[arrayElem]"), arrayType.Elem()) - return &arrayEncoder{arrayType, encoder} + elemEncoder := encoderOfType(ctx.append("[arrayElem]"), arrayType.Elem()) + + c := &ArrayEncoderConstructor{ + ArrayType: arrayType, + ElemEncoder: elemEncoder, + API: ctx, + DecorateFunc: func(arrayEncoder ValEncoder) ValEncoder { + return arrayEncoder + }, + } + updateArrayEncoderConstructor(c, extensions...) + updateArrayEncoderConstructor(c, ctx.encoderExtension) + updateArrayEncoderConstructor(c, ctx.extraExtensions...) + enc := &arrayEncoder{arrayType, c.ElemEncoder} + return c.DecorateFunc(enc) } type emptyArrayEncoder struct{} diff --git a/reflect_extension.go b/reflect_extension.go index 74a97bfe..4166ce92 100644 --- a/reflect_extension.go +++ b/reflect_extension.go @@ -2,12 +2,13 @@ package jsoniter import ( "fmt" - "github.com/modern-go/reflect2" "reflect" "sort" "strings" "unicode" "unsafe" + + "github.com/modern-go/reflect2" ) var typeDecoders = map[string]ValDecoder{} @@ -395,10 +396,49 @@ func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor { } return createStructDescriptor(ctx, typ, bindings, embeddedBindings) } + +type StructDescriptorConstructor struct { + Type reflect2.Type + Bindings []*Binding + EmbeddedBindings []*Binding + API API + DescribeStructFunc func(typ reflect2.Type) *StructDescriptor +} + +func updateStructDescriptorConstructor(v *StructDescriptorConstructor, exts ...Extension) { + for _, ext := range exts { + if e, ok := ext.(interface { + UpdateStructDescriptorConstructor(v *StructDescriptorConstructor) + }); ok { + e.UpdateStructDescriptorConstructor(v) + } + } +} + +func createStructDescriptorConstructor(ctx *ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptorConstructor { + v := &StructDescriptorConstructor{ + Type: typ, + Bindings: bindings, + EmbeddedBindings: embeddedBindings, + + API: ctx, + DescribeStructFunc: func(typ reflect2.Type) *StructDescriptor { + return describeStruct(ctx, typ) + }, + } + updateStructDescriptorConstructor(v, extensions...) + updateStructDescriptorConstructor(v, ctx.encoderExtension) + updateStructDescriptorConstructor(v, ctx.decoderExtension) + updateStructDescriptorConstructor(v, ctx.extraExtensions...) + return v +} + func createStructDescriptor(ctx *ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor { + constructor := createStructDescriptorConstructor(ctx, typ, bindings, embeddedBindings) + structDescriptor := &StructDescriptor{ - Type: typ, - Fields: bindings, + Type: constructor.Type, + Fields: constructor.Bindings, } for _, extension := range extensions { extension.UpdateStructDescriptor(structDescriptor) @@ -410,7 +450,7 @@ func createStructDescriptor(ctx *ctx, typ reflect2.Type, bindings []*Binding, em } processTags(structDescriptor, ctx.frozenConfig) // merge normal & embedded bindings & sort with original order - allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...)) + allBindings := sortableBindings(append(constructor.EmbeddedBindings, structDescriptor.Fields...)) sort.Sort(allBindings) structDescriptor.Fields = allBindings return structDescriptor diff --git a/reflect_map.go b/reflect_map.go index 4e479c8a..092fe8da 100644 --- a/reflect_map.go +++ b/reflect_map.go @@ -23,20 +23,57 @@ func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder { } } +type MapEncoderConstructor struct { + MapType *reflect2.UnsafeMapType + KeyEncoder ValEncoder + ElemEncoder ValEncoder + API API + DecorateFunc func(mapEncoder ValEncoder) ValEncoder +} + +func updateMapEncoderConstructor(v *MapEncoderConstructor, exts ...Extension) { + for _, ext := range exts { + if e, ok := ext.(interface { + UpdateMapEncoderConstructor(v *MapEncoderConstructor) + }); ok { + e.UpdateMapEncoderConstructor(v) + } + } +} + func encoderOfMap(ctx *ctx, typ reflect2.Type) ValEncoder { mapType := typ.(*reflect2.UnsafeMapType) + + keyEncoder := encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()) + elemEncoder := encoderOfType(ctx.append("[mapElem]"), mapType.Elem()) + c := &MapEncoderConstructor{ + MapType: mapType, + KeyEncoder: keyEncoder, + ElemEncoder: elemEncoder, + API: ctx, + DecorateFunc: func(mapEncoder ValEncoder) ValEncoder { + return mapEncoder + }, + } + updateMapEncoderConstructor(c, extensions...) + updateMapEncoderConstructor(c, ctx.encoderExtension) + updateMapEncoderConstructor(c, ctx.extraExtensions...) + + var enc ValEncoder if ctx.sortMapKeys { - return &sortKeysMapEncoder{ - mapType: mapType, - keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()), - elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()), + enc = &sortKeysMapEncoder{ + mapType: c.MapType, + keyEncoder: c.KeyEncoder, + elemEncoder: c.ElemEncoder, + } + } else { + enc = &mapEncoder{ + mapType: c.MapType, + keyEncoder: c.KeyEncoder, + elemEncoder: c.ElemEncoder, } } - return &mapEncoder{ - mapType: mapType, - keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()), - elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()), - } + return c.DecorateFunc(enc) } func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder { diff --git a/reflect_slice.go b/reflect_slice.go index 9441d79d..aa290bcf 100644 --- a/reflect_slice.go +++ b/reflect_slice.go @@ -2,9 +2,10 @@ package jsoniter import ( "fmt" - "github.com/modern-go/reflect2" "io" "unsafe" + + "github.com/modern-go/reflect2" ) func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder { @@ -13,10 +14,39 @@ func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder { return &sliceDecoder{sliceType, decoder} } +type SliceEncoderConstructor struct { + SliceType *reflect2.UnsafeSliceType + ElemEncoder ValEncoder + API API + DecorateFunc func(sliceEncoder ValEncoder) ValEncoder +} + +func updateSliceEncoderConstructor(v *SliceEncoderConstructor, exts ...Extension) { + for _, ext := range exts { + if e, ok := ext.(interface { + UpdateSliceEncoderConstructor(v *SliceEncoderConstructor) + }); ok { + e.UpdateSliceEncoderConstructor(v) + } + } +} + func encoderOfSlice(ctx *ctx, typ reflect2.Type) ValEncoder { sliceType := typ.(*reflect2.UnsafeSliceType) - encoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem()) - return &sliceEncoder{sliceType, encoder} + elemEncoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem()) + c := &SliceEncoderConstructor{ + SliceType: sliceType, + ElemEncoder: elemEncoder, + API: ctx, + DecorateFunc: func(sliceEncoder ValEncoder) ValEncoder { + return sliceEncoder + }, + } + updateSliceEncoderConstructor(c, extensions...) + updateSliceEncoderConstructor(c, ctx.encoderExtension) + updateSliceEncoderConstructor(c, ctx.extraExtensions...) + enc := &sliceEncoder{sliceType, c.ElemEncoder} + return c.DecorateFunc(enc) } type sliceEncoder struct {