1
0
mirror of https://github.com/json-iterator/go.git synced 2025-04-20 11:28:49 +02:00

use reflect2 for json.Marshaler

This commit is contained in:
Tao Wen 2018-02-16 15:42:37 +08:00
parent 0e2b54800a
commit a7a34507ab
5 changed files with 29 additions and 30 deletions

View File

@ -7,6 +7,7 @@ import (
"reflect" "reflect"
"time" "time"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
) )
// ValDecoder is an internal type registered to cache as needed. // ValDecoder is an internal type registered to cache as needed.
@ -331,21 +332,8 @@ func createEncoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) Val
} }
if typ.Implements(marshalerType) { if typ.Implements(marshalerType) {
checkIsEmpty := createCheckIsEmpty(cfg, typ) checkIsEmpty := createCheckIsEmpty(cfg, typ)
templateInterface := reflect.New(typ).Elem().Interface()
var encoder ValEncoder = &marshalerEncoder{ var encoder ValEncoder = &marshalerEncoder{
templateInterface: extractInterface(templateInterface), valType: reflect2.Type2(typ),
checkIsEmpty: checkIsEmpty,
}
if typ.Kind() == reflect.Ptr {
encoder = &OptionalEncoder{encoder}
}
return encoder
}
if reflect.PtrTo(typ).Implements(marshalerType) {
checkIsEmpty := createCheckIsEmpty(cfg, reflect.PtrTo(typ))
templateInterface := reflect.New(typ).Interface()
var encoder ValEncoder = &marshalerEncoder{
templateInterface: extractInterface(templateInterface),
checkIsEmpty: checkIsEmpty, checkIsEmpty: checkIsEmpty,
} }
return encoder return encoder

View File

@ -176,6 +176,10 @@ type sortKeysMapEncoder struct {
func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
ptr = *(*unsafe.Pointer)(ptr) ptr = *(*unsafe.Pointer)(ptr)
if ptr == nil {
stream.WriteNil()
return
}
mapInterface := encoder.mapInterface mapInterface := encoder.mapInterface
mapInterface.word = ptr mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface)) realInterface := (*interface{})(unsafe.Pointer(&mapInterface))

View File

@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"reflect" "reflect"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
) )
type stringCodec struct { type stringCodec struct {
@ -473,7 +474,7 @@ func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
case StringValue: case StringValue:
encoding := base64.StdEncoding encoding := base64.StdEncoding
src := iter.SkipAndReturnBytes() src := iter.SkipAndReturnBytes()
src = src[1 : len(src)-1] src = src[1: len(src)-1]
decodedLen := encoding.DecodedLen(len(src)) decodedLen := encoding.DecodedLen(len(src))
dst := make([]byte, decodedLen) dst := make([]byte, decodedLen)
len, err := encoding.Decode(dst, src) len, err := encoding.Decode(dst, src)
@ -578,20 +579,17 @@ func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
} }
type marshalerEncoder struct { type marshalerEncoder struct {
templateInterface emptyInterface checkIsEmpty checkIsEmpty
checkIsEmpty checkIsEmpty valType reflect2.Type
} }
func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
templateInterface := encoder.templateInterface obj := encoder.valType.UnsafeIndirect(ptr)
templateInterface.word = ptr if obj == nil {
realInterface := (*interface{})(unsafe.Pointer(&templateInterface)) stream.WriteNil()
marshaler, ok := (*realInterface).(json.Marshaler)
if !ok {
stream.WriteVal(nil)
return return
} }
marshaler := obj.(json.Marshaler)
bytes, err := marshaler.MarshalJSON() bytes, err := marshaler.MarshalJSON()
if err != nil { if err != nil {
stream.Error = err stream.Error = err

View File

@ -10,6 +10,7 @@ func init() {
var pString = func(val string) *string { var pString = func(val string) *string {
return &val return &val
} }
epoch := time.Unix(0, 0)
unmarshalCases = append(unmarshalCases, unmarshalCase{ unmarshalCases = append(unmarshalCases, unmarshalCase{
ptr: (*struct { ptr: (*struct {
Field interface{} Field interface{}
@ -83,13 +84,9 @@ func init() {
struct { struct {
F *float64 F *float64
}{}, }{},
// TODO: fix this
//struct {
// *time.Time
//}{},
struct { struct {
*time.Time *time.Time
}{&time.Time{}}, }{&epoch},
struct { struct {
*StructVarious *StructVarious
}{&StructVarious{}}, }{&StructVarious{}},

View File

@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"fmt"
) )
type unmarshalCase struct { type unmarshalCase struct {
@ -19,6 +20,10 @@ var marshalCases = []interface{}{
nil, nil,
} }
type selectedMarshalCase struct {
marshalCase interface{}
}
func Test_unmarshal(t *testing.T) { func Test_unmarshal(t *testing.T) {
should := require.New(t) should := require.New(t)
for _, testCase := range unmarshalCases { for _, testCase := range unmarshalCases {
@ -35,9 +40,16 @@ func Test_unmarshal(t *testing.T) {
func Test_marshal(t *testing.T) { func Test_marshal(t *testing.T) {
for _, testCase := range marshalCases { for _, testCase := range marshalCases {
selectedMarshalCase, found := testCase.(selectedMarshalCase)
if found {
marshalCases = []interface{}{selectedMarshalCase.marshalCase}
break
}
}
for i, testCase := range marshalCases {
var name string var name string
if testCase != nil { if testCase != nil {
name = reflect.TypeOf(testCase).String() name = fmt.Sprintf("[%v]%v/%s", i, testCase, reflect.TypeOf(testCase).String())
} }
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
should := require.New(t) should := require.New(t)