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:
parent
0e2b54800a
commit
a7a34507ab
@ -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
|
||||||
|
@ -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))
|
||||||
|
@ -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
|
||||||
|
@ -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{}},
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user