Skip to content
This repository was archived by the owner on Dec 15, 2025. It is now read-only.

Commit 2fcbb23

Browse files
committed
rewrite how eface and iface are handled
1 parent ea64033 commit 2fcbb23

File tree

13 files changed

+301
-243
lines changed

13 files changed

+301
-243
lines changed

api_tests/config_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,14 @@ func Test_customize_tag_key(t *testing.T) {
3535
str, err := json.MarshalToString(TestObject{"hello"})
3636
should.Nil(err)
3737
should.Equal(`{"field":"hello"}`, str)
38+
}
39+
40+
func Test_read_large_number_as_interface(t *testing.T) {
41+
should := require.New(t)
42+
var val interface{}
43+
err := jsoniter.Config{UseNumber: true}.Froze().UnmarshalFromString(`123456789123456789123456789`, &val)
44+
should.Nil(err)
45+
output, err := jsoniter.MarshalToString(val)
46+
should.Nil(err)
47+
should.Equal(`123456789123456789123456789`, output)
3848
}

config.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package jsoniter
22

33
import (
44
"encoding/json"
5-
"errors"
65
"io"
76
"reflect"
87
"unsafe"
@@ -267,11 +266,6 @@ func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error {
267266
data = data[:lastNotSpacePos(data)]
268267
iter := cfg.BorrowIterator(data)
269268
defer cfg.ReturnIterator(iter)
270-
typ := reflect.TypeOf(v)
271-
if typ.Kind() != reflect.Ptr {
272-
// return non-pointer error
273-
return errors.New("the second param must be ptr type")
274-
}
275269
iter.ReadVal(v)
276270
if iter.head == iter.tail {
277271
iter.loadMore()

misc_tests/jsoniter_float_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ func Test_read_float64_cursor(t *testing.T) {
4949
func Test_read_float_scientific(t *testing.T) {
5050
should := require.New(t)
5151
var obj interface{}
52-
should.Nil(jsoniter.UnmarshalFromString(`1e1`, &obj))
52+
should.NoError(jsoniter.UnmarshalFromString(`1e1`, &obj))
5353
should.Equal(float64(10), obj)
54-
should.Nil(json.Unmarshal([]byte(`1e1`), &obj))
54+
should.NoError(json.Unmarshal([]byte(`1e1`), &obj))
5555
should.Equal(float64(10), obj)
56-
should.Nil(jsoniter.UnmarshalFromString(`1.0e1`, &obj))
56+
should.NoError(jsoniter.UnmarshalFromString(`1.0e1`, &obj))
5757
should.Equal(float64(10), obj)
58-
should.Nil(json.Unmarshal([]byte(`1.0e1`), &obj))
58+
should.NoError(json.Unmarshal([]byte(`1.0e1`), &obj))
5959
should.Equal(float64(10), obj)
6060
}
6161

misc_tests/jsoniter_interface_test.go

Lines changed: 12 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,15 @@ package misc_tests
22

33
import (
44
"encoding/json"
5-
"fmt"
65
"testing"
76
"github.com/stretchr/testify/require"
87
"github.com/json-iterator/go"
8+
"io"
99
)
1010

11-
type MyInterface interface {
12-
Hello() string
13-
}
14-
15-
type MyString string
16-
17-
func (ms MyString) Hello() string {
18-
return string(ms)
19-
}
20-
21-
func Test_decode_object_contain_non_empty_interface(t *testing.T) {
22-
type TestObject struct {
23-
Field MyInterface
24-
}
25-
should := require.New(t)
26-
obj := TestObject{}
27-
obj.Field = MyString("abc")
28-
should.Nil(jsoniter.UnmarshalFromString(`{"Field": "hello"}`, &obj))
29-
should.Equal(MyString("hello"), obj.Field)
30-
}
31-
3211
func Test_nil_non_empty_interface(t *testing.T) {
3312
type TestObject struct {
34-
Field []MyInterface
13+
Field []io.Closer
3514
}
3615
should := require.New(t)
3716
obj := TestObject{}
@@ -40,31 +19,6 @@ func Test_nil_non_empty_interface(t *testing.T) {
4019
should.NotNil(jsoniter.Unmarshal(b, &obj))
4120
}
4221

43-
func Test_read_large_number_as_interface(t *testing.T) {
44-
should := require.New(t)
45-
var val interface{}
46-
err := jsoniter.Config{UseNumber: true}.Froze().UnmarshalFromString(`123456789123456789123456789`, &val)
47-
should.Nil(err)
48-
output, err := jsoniter.MarshalToString(val)
49-
should.Nil(err)
50-
should.Equal(`123456789123456789123456789`, output)
51-
}
52-
53-
func Test_unmarshal_ptr_to_interface(t *testing.T) {
54-
type TestData struct {
55-
Name string `json:"name"`
56-
}
57-
should := require.New(t)
58-
var obj interface{} = &TestData{}
59-
err := json.Unmarshal([]byte(`{"name":"value"}`), &obj)
60-
should.Nil(err)
61-
should.Equal("&{value}", fmt.Sprintf("%v", obj))
62-
obj = interface{}(&TestData{})
63-
err = jsoniter.Unmarshal([]byte(`{"name":"value"}`), &obj)
64-
should.Nil(err)
65-
should.Equal("&{value}", fmt.Sprintf("%v", obj))
66-
}
67-
6822
func Test_nil_out_null_interface(t *testing.T) {
6923
type TestData struct {
7024
Field interface{} `json:"field"`
@@ -86,7 +40,7 @@ func Test_nil_out_null_interface(t *testing.T) {
8640

8741
err = jsoniter.Unmarshal(data2, &obj)
8842
should.NoError(err)
89-
should.Equal(nil, obj.Field)
43+
should.Nil(obj.Field)
9044

9145
// Checking stdlib behavior matches.
9246
obj2 := TestData{
@@ -118,12 +72,12 @@ func Test_overwrite_interface_ptr_value_with_nil(t *testing.T) {
11872
}
11973

12074
err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
121-
should.Equal(nil, err)
75+
should.NoError(err)
12276
should.Equal(&payload, wrapper.Payload)
12377
should.Equal(42, (*(wrapper.Payload.(**Payload))).Value)
12478

12579
err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
126-
should.Equal(nil, err)
80+
should.NoError(err)
12781
should.Equal(&payload, wrapper.Payload)
12882
should.Equal((*Payload)(nil), payload)
12983

@@ -138,7 +92,7 @@ func Test_overwrite_interface_ptr_value_with_nil(t *testing.T) {
13892
should.Equal(42, (*(wrapper.Payload.(**Payload))).Value)
13993

14094
err = jsoniter.Unmarshal([]byte(`{"payload": null}`), &wrapper)
141-
should.Equal(nil, err)
95+
should.NoError(err)
14296
should.Equal(&payload, wrapper.Payload)
14397
should.Equal((*Payload)(nil), payload)
14498
}
@@ -159,11 +113,11 @@ func Test_overwrite_interface_value_with_nil(t *testing.T) {
159113
}
160114

161115
err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
162-
should.Equal(nil, err)
116+
should.NoError(err)
163117
should.Equal(42, (*(wrapper.Payload.(*Payload))).Value)
164118

165119
err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
166-
should.Equal(nil, err)
120+
should.NoError(err)
167121
should.Equal(nil, wrapper.Payload)
168122
should.Equal(42, payload.Value)
169123

@@ -198,12 +152,12 @@ func Test_unmarshal_into_nil(t *testing.T) {
198152
}
199153

200154
err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
201-
should.Nil(err)
155+
should.NoError(err)
202156
should.NotNil(wrapper.Payload)
203157
should.Nil(payload)
204158

205159
err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
206-
should.Nil(err)
160+
should.NoError(err)
207161
should.Nil(wrapper.Payload)
208162
should.Nil(payload)
209163

@@ -213,12 +167,12 @@ func Test_unmarshal_into_nil(t *testing.T) {
213167
}
214168

215169
err = jsoniter.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
216-
should.Nil(err)
170+
should.NoError(err)
217171
should.NotNil(wrapper.Payload)
218172
should.Nil(payload)
219173

220174
err = jsoniter.Unmarshal([]byte(`{"payload": null}`), &wrapper)
221-
should.Nil(err)
175+
should.NoError(err)
222176
should.Nil(wrapper.Payload)
223177
should.Nil(payload)
224178
}

reflect.go

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,17 @@ type checkIsEmpty interface {
3636
// ReadVal copy the underlying JSON into go interface, same as json.Unmarshal
3737
func (iter *Iterator) ReadVal(obj interface{}) {
3838
typ := reflect.TypeOf(obj)
39-
cacheKey := typ.Elem()
40-
decoder := decoderOfType(iter.cfg, "", cacheKey)
41-
e := (*emptyInterface)(unsafe.Pointer(&obj))
42-
if e.word == nil {
39+
if typ.Kind() != reflect.Ptr {
40+
iter.ReportError("ReadVal", "can only unmarshal into pointer")
41+
return
42+
}
43+
decoder := iter.cfg.DecoderOf(typ)
44+
ptr := reflect2.PtrOf(obj)
45+
if ptr == nil {
4346
iter.ReportError("ReadVal", "can not read into nil pointer")
4447
return
4548
}
46-
decoder.Decode(e.word, iter)
49+
decoder.Decode(ptr, iter)
4750
}
4851

4952
// WriteVal copy the go interface into underlying JSON, same as json.Marshal
@@ -63,7 +66,7 @@ func (cfg *frozenConfig) DecoderOf(typ reflect.Type) ValDecoder {
6366
if decoder != nil {
6467
return decoder
6568
}
66-
decoder = decoderOfType(cfg, "", typ)
69+
decoder = decoderOfType(cfg, "", typ.Elem())
6770
cfg.addDecoderToCache(cacheKey, decoder)
6871
return decoder
6972
}
@@ -106,10 +109,11 @@ func createDecoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) Val
106109
}
107110
switch typ.Kind() {
108111
case reflect.Interface:
109-
if typ.NumMethod() == 0 {
110-
return &emptyInterfaceCodec{}
112+
if typ.NumMethod() > 0 {
113+
ifaceType := reflect2.Type2(typ).(*reflect2.UnsafeIFaceType)
114+
return &ifaceDecoder{valType: ifaceType}
111115
}
112-
return &nonEmptyInterfaceCodec{}
116+
return &efaceDecoder{}
113117
case reflect.Struct:
114118
return decoderOfStruct(cfg, prefix, typ)
115119
case reflect.Array:
@@ -239,27 +243,3 @@ func (encoder *lazyErrorEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
239243
func (encoder *lazyErrorEncoder) IsEmpty(ptr unsafe.Pointer) bool {
240244
return false
241245
}
242-
243-
func extractInterface(val interface{}) emptyInterface {
244-
return *((*emptyInterface)(unsafe.Pointer(&val)))
245-
}
246-
247-
// emptyInterface is the header for an interface{} value.
248-
type emptyInterface struct {
249-
typ unsafe.Pointer
250-
word unsafe.Pointer
251-
}
252-
253-
// emptyInterface is the header for an interface with method (not interface{})
254-
type nonEmptyInterface struct {
255-
// see ../runtime/iface.go:/Itab
256-
itab *struct {
257-
ityp unsafe.Pointer // static interface type
258-
typ unsafe.Pointer // dynamic concrete type
259-
link unsafe.Pointer
260-
bad int32
261-
unused int32
262-
fun [100000]unsafe.Pointer // method table
263-
}
264-
word unsafe.Pointer
265-
}

reflect_dynamic.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package jsoniter
2+
3+
import (
4+
"github.com/v2pro/plz/reflect2"
5+
"unsafe"
6+
"reflect"
7+
)
8+
9+
type dynamicEncoder struct {
10+
valType reflect2.Type
11+
}
12+
13+
func (encoder *dynamicEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
14+
obj := encoder.valType.UnsafeIndirect(ptr)
15+
stream.WriteVal(obj)
16+
}
17+
18+
func (encoder *dynamicEncoder) IsEmpty(ptr unsafe.Pointer) bool {
19+
return encoder.valType.UnsafeIndirect(ptr) == nil
20+
}
21+
22+
type efaceDecoder struct {
23+
}
24+
25+
func (decoder *efaceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
26+
pObj := (*interface{})(ptr)
27+
obj := *pObj
28+
if obj == nil {
29+
*pObj = iter.Read()
30+
return
31+
}
32+
typ := reflect2.TypeOf(obj)
33+
if typ.Kind() != reflect.Ptr {
34+
*pObj = iter.Read()
35+
return
36+
}
37+
ptrType := typ.(*reflect2.UnsafePtrType)
38+
ptrElemType := ptrType.Elem()
39+
if iter.WhatIsNext() == NilValue {
40+
if ptrElemType.Kind() != reflect.Ptr {
41+
iter.skipFourBytes('n', 'u', 'l', 'l')
42+
*pObj = nil
43+
return
44+
}
45+
}
46+
if reflect2.IsNil(obj) {
47+
obj := ptrElemType.New()
48+
iter.ReadVal(obj)
49+
*pObj = obj
50+
return
51+
}
52+
iter.ReadVal(obj)
53+
}
54+
55+
type ifaceDecoder struct {
56+
valType *reflect2.UnsafeIFaceType
57+
}
58+
59+
func (decoder *ifaceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
60+
if iter.ReadNil() {
61+
decoder.valType.UnsafeSet(ptr, decoder.valType.UnsafeNew())
62+
return
63+
}
64+
obj := decoder.valType.UnsafeIndirect(ptr)
65+
if reflect2.IsNil(obj) {
66+
iter.ReportError("decode non empty interface", "can not unmarshal into nil")
67+
return
68+
}
69+
iter.ReadVal(obj)
70+
}

reflect_extension.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"strings"
88
"unicode"
99
"unsafe"
10+
"github.com/v2pro/plz/reflect2"
1011
)
1112

1213
var typeDecoders = map[string]ValDecoder{}
@@ -240,7 +241,7 @@ func _getTypeDecoderFromExtension(cfg *frozenConfig, typ reflect.Type) ValDecode
240241
if typ.Kind() == reflect.Ptr {
241242
decoder := typeDecoders[typ.Elem().String()]
242243
if decoder != nil {
243-
return &OptionalDecoder{typ.Elem(), decoder}
244+
return &OptionalDecoder{reflect2.Type2(typ.Elem()), decoder}
244245
}
245246
}
246247
return nil
@@ -317,7 +318,7 @@ func describeStruct(cfg *frozenConfig, prefix string, typ reflect.Type) *StructD
317318
omitempty := binding.Encoder.(*structFieldEncoder).omitempty
318319
binding.Encoder = &dereferenceEncoder{binding.Encoder}
319320
binding.Encoder = &structFieldEncoder{&field, binding.Encoder, omitempty}
320-
binding.Decoder = &dereferenceDecoder{field.Type.Elem(), binding.Decoder}
321+
binding.Decoder = &dereferenceDecoder{reflect2.Type2(field.Type.Elem()), binding.Decoder}
321322
binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
322323
embeddedBindings = append(embeddedBindings, binding)
323324
}

0 commit comments

Comments
 (0)