Skip to content

Commit 6044da9

Browse files
committed
Support more complex custom encode methods
- UpdateArrayEncoderConstructor(v *ArrayEncoderConstructor) - UpdateStructDescriptorConstructor(v *StructDescriptorConstructor) - UpdateMapEncoderConstructor(v *MapEncoderConstructor) - UpdateSliceEncoderConstructor(v *SliceEncoderConstructor)
1 parent e1382e8 commit 6044da9

File tree

4 files changed

+157
-19
lines changed

4 files changed

+157
-19
lines changed

reflect_array.go

+34-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package jsoniter
22

33
import (
44
"fmt"
5-
"github.com/modern-go/reflect2"
65
"io"
76
"unsafe"
7+
8+
"github.com/modern-go/reflect2"
89
)
910

1011
func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder {
@@ -13,13 +14,43 @@ func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder {
1314
return &arrayDecoder{arrayType, decoder}
1415
}
1516

17+
type ArrayEncoderConstructor struct {
18+
ArrayType *reflect2.UnsafeArrayType
19+
ElemEncoder ValEncoder
20+
API API
21+
DecorateFunc func(arrayEncoder ValEncoder) ValEncoder
22+
}
23+
24+
func updateArrayEncoderConstructor(v *ArrayEncoderConstructor, exts ...Extension) {
25+
for _, ext := range exts {
26+
if e, ok := ext.(interface {
27+
UpdateArrayEncoderConstructor(v *ArrayEncoderConstructor)
28+
}); ok {
29+
e.UpdateArrayEncoderConstructor(v)
30+
}
31+
}
32+
}
33+
1634
func encoderOfArray(ctx *ctx, typ reflect2.Type) ValEncoder {
1735
arrayType := typ.(*reflect2.UnsafeArrayType)
1836
if arrayType.Len() == 0 {
1937
return emptyArrayEncoder{}
2038
}
21-
encoder := encoderOfType(ctx.append("[arrayElem]"), arrayType.Elem())
22-
return &arrayEncoder{arrayType, encoder}
39+
elemEncoder := encoderOfType(ctx.append("[arrayElem]"), arrayType.Elem())
40+
41+
c := &ArrayEncoderConstructor{
42+
ArrayType: arrayType,
43+
ElemEncoder: elemEncoder,
44+
API: ctx,
45+
DecorateFunc: func(arrayEncoder ValEncoder) ValEncoder {
46+
return arrayEncoder
47+
},
48+
}
49+
updateArrayEncoderConstructor(c, extensions...)
50+
updateArrayEncoderConstructor(c, ctx.encoderExtension)
51+
updateArrayEncoderConstructor(c, ctx.extraExtensions...)
52+
enc := &arrayEncoder{arrayType, c.ElemEncoder}
53+
return c.DecorateFunc(enc)
2354
}
2455

2556
type emptyArrayEncoder struct{}

reflect_extension.go

+44-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ package jsoniter
22

33
import (
44
"fmt"
5-
"github.com/modern-go/reflect2"
65
"reflect"
76
"sort"
87
"strings"
98
"unicode"
109
"unsafe"
10+
11+
"github.com/modern-go/reflect2"
1112
)
1213

1314
var typeDecoders = map[string]ValDecoder{}
@@ -395,10 +396,49 @@ func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor {
395396
}
396397
return createStructDescriptor(ctx, typ, bindings, embeddedBindings)
397398
}
399+
400+
type StructDescriptorConstructor struct {
401+
Type reflect2.Type
402+
Bindings []*Binding
403+
EmbeddedBindings []*Binding
404+
API API
405+
DescribeStructFunc func(typ reflect2.Type) *StructDescriptor
406+
}
407+
408+
func updateStructDescriptorConstructor(v *StructDescriptorConstructor, exts ...Extension) {
409+
for _, ext := range exts {
410+
if e, ok := ext.(interface {
411+
UpdateStructDescriptorConstructor(v *StructDescriptorConstructor)
412+
}); ok {
413+
e.UpdateStructDescriptorConstructor(v)
414+
}
415+
}
416+
}
417+
418+
func createStructDescriptorConstructor(ctx *ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptorConstructor {
419+
v := &StructDescriptorConstructor{
420+
Type: typ,
421+
Bindings: bindings,
422+
EmbeddedBindings: embeddedBindings,
423+
424+
API: ctx,
425+
DescribeStructFunc: func(typ reflect2.Type) *StructDescriptor {
426+
return describeStruct(ctx, typ)
427+
},
428+
}
429+
updateStructDescriptorConstructor(v, extensions...)
430+
updateStructDescriptorConstructor(v, ctx.encoderExtension)
431+
updateStructDescriptorConstructor(v, ctx.decoderExtension)
432+
updateStructDescriptorConstructor(v, ctx.extraExtensions...)
433+
return v
434+
}
435+
398436
func createStructDescriptor(ctx *ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor {
437+
constructor := createStructDescriptorConstructor(ctx, typ, bindings, embeddedBindings)
438+
399439
structDescriptor := &StructDescriptor{
400-
Type: typ,
401-
Fields: bindings,
440+
Type: constructor.Type,
441+
Fields: constructor.Bindings,
402442
}
403443
for _, extension := range extensions {
404444
extension.UpdateStructDescriptor(structDescriptor)
@@ -410,7 +450,7 @@ func createStructDescriptor(ctx *ctx, typ reflect2.Type, bindings []*Binding, em
410450
}
411451
processTags(structDescriptor, ctx.frozenConfig)
412452
// merge normal & embedded bindings & sort with original order
413-
allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...))
453+
allBindings := sortableBindings(append(constructor.EmbeddedBindings, structDescriptor.Fields...))
414454
sort.Sort(allBindings)
415455
structDescriptor.Fields = allBindings
416456
return structDescriptor

reflect_map.go

+46-9
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,57 @@ func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder {
2323
}
2424
}
2525

26+
type MapEncoderConstructor struct {
27+
MapType *reflect2.UnsafeMapType
28+
KeyEncoder ValEncoder
29+
ElemEncoder ValEncoder
30+
API API
31+
DecorateFunc func(mapEncoder ValEncoder) ValEncoder
32+
}
33+
34+
func updateMapEncoderConstructor(v *MapEncoderConstructor, exts ...Extension) {
35+
for _, ext := range exts {
36+
if e, ok := ext.(interface {
37+
UpdateMapEncoderConstructor(v *MapEncoderConstructor)
38+
}); ok {
39+
e.UpdateMapEncoderConstructor(v)
40+
}
41+
}
42+
}
43+
2644
func encoderOfMap(ctx *ctx, typ reflect2.Type) ValEncoder {
2745
mapType := typ.(*reflect2.UnsafeMapType)
46+
47+
keyEncoder := encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key())
48+
elemEncoder := encoderOfType(ctx.append("[mapElem]"), mapType.Elem())
49+
c := &MapEncoderConstructor{
50+
MapType: mapType,
51+
KeyEncoder: keyEncoder,
52+
ElemEncoder: elemEncoder,
53+
API: ctx,
54+
DecorateFunc: func(mapEncoder ValEncoder) ValEncoder {
55+
return mapEncoder
56+
},
57+
}
58+
updateMapEncoderConstructor(c, extensions...)
59+
updateMapEncoderConstructor(c, ctx.encoderExtension)
60+
updateMapEncoderConstructor(c, ctx.extraExtensions...)
61+
62+
var enc ValEncoder
2863
if ctx.sortMapKeys {
29-
return &sortKeysMapEncoder{
30-
mapType: mapType,
31-
keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()),
32-
elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()),
64+
enc = &sortKeysMapEncoder{
65+
mapType: c.MapType,
66+
keyEncoder: c.KeyEncoder,
67+
elemEncoder: c.ElemEncoder,
68+
}
69+
} else {
70+
enc = &mapEncoder{
71+
mapType: c.MapType,
72+
keyEncoder: c.KeyEncoder,
73+
elemEncoder: c.ElemEncoder,
3374
}
3475
}
35-
return &mapEncoder{
36-
mapType: mapType,
37-
keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()),
38-
elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()),
39-
}
76+
return c.DecorateFunc(enc)
4077
}
4178

4279
func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder {

reflect_slice.go

+33-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package jsoniter
22

33
import (
44
"fmt"
5-
"github.com/modern-go/reflect2"
65
"io"
76
"unsafe"
7+
8+
"github.com/modern-go/reflect2"
89
)
910

1011
func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder {
@@ -13,10 +14,39 @@ func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder {
1314
return &sliceDecoder{sliceType, decoder}
1415
}
1516

17+
type SliceEncoderConstructor struct {
18+
SliceType *reflect2.UnsafeSliceType
19+
ElemEncoder ValEncoder
20+
API API
21+
DecorateFunc func(sliceEncoder ValEncoder) ValEncoder
22+
}
23+
24+
func updateSliceEncoderConstructor(v *SliceEncoderConstructor, exts ...Extension) {
25+
for _, ext := range exts {
26+
if e, ok := ext.(interface {
27+
UpdateSliceEncoderConstructor(v *SliceEncoderConstructor)
28+
}); ok {
29+
e.UpdateSliceEncoderConstructor(v)
30+
}
31+
}
32+
}
33+
1634
func encoderOfSlice(ctx *ctx, typ reflect2.Type) ValEncoder {
1735
sliceType := typ.(*reflect2.UnsafeSliceType)
18-
encoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem())
19-
return &sliceEncoder{sliceType, encoder}
36+
elemEncoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem())
37+
c := &SliceEncoderConstructor{
38+
SliceType: sliceType,
39+
ElemEncoder: elemEncoder,
40+
API: ctx,
41+
DecorateFunc: func(sliceEncoder ValEncoder) ValEncoder {
42+
return sliceEncoder
43+
},
44+
}
45+
updateSliceEncoderConstructor(c, extensions...)
46+
updateSliceEncoderConstructor(c, ctx.encoderExtension)
47+
updateSliceEncoderConstructor(c, ctx.extraExtensions...)
48+
enc := &sliceEncoder{sliceType, c.ElemEncoder}
49+
return c.DecorateFunc(enc)
2050
}
2151

2252
type sliceEncoder struct {

0 commit comments

Comments
 (0)