Skip to content

Commit

Permalink
Support more complex custom encode methods
Browse files Browse the repository at this point in the history
- UpdateArrayEncoderConstructor(v *ArrayEncoderConstructor)
- UpdateStructDescriptorConstructor(v *StructDescriptorConstructor)
- UpdateMapEncoderConstructor(v *MapEncoderConstructor)
- UpdateSliceEncoderConstructor(v *SliceEncoderConstructor)
  • Loading branch information
molon committed Sep 28, 2022
1 parent e1382e8 commit 6044da9
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 19 deletions.
37 changes: 34 additions & 3 deletions reflect_array.go
Expand Up @@ -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 {
Expand All @@ -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{}
Expand Down
48 changes: 44 additions & 4 deletions reflect_extension.go
Expand Up @@ -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{}
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down
55 changes: 46 additions & 9 deletions reflect_map.go
Expand Up @@ -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 {
Expand Down
36 changes: 33 additions & 3 deletions reflect_slice.go
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down

0 comments on commit 6044da9

Please sign in to comment.