Skip to content

Commit 397a4e4

Browse files
authored
Merge pull request #257 from Kiraub/master
Add decoder for func type
2 parents f7eceb1 + 9d9e5cd commit 397a4e4

File tree

3 files changed

+163
-2
lines changed

3 files changed

+163
-2
lines changed

decode_test.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ func Test_Decoder(t *testing.T) {
152152
B string `json:"str"`
153153
C bool
154154
D *T
155+
E func()
155156
}
156157
content := []byte(`
157158
{
@@ -162,7 +163,8 @@ func Test_Decoder(t *testing.T) {
162163
"aa": 2,
163164
"bb": "world",
164165
"cc": true
165-
}
166+
},
167+
"e" : null
166168
}`)
167169
assertErr(t, json.Unmarshal(content, &v))
168170
assertEq(t, "struct.A", 123, v.A)
@@ -171,6 +173,7 @@ func Test_Decoder(t *testing.T) {
171173
assertEq(t, "struct.D.AA", 2, v.D.AA)
172174
assertEq(t, "struct.D.BB", "world", v.D.BB)
173175
assertEq(t, "struct.D.CC", true, v.D.CC)
176+
assertEq(t, "struct.E", true, v.E == nil)
174177
t.Run("struct.field null", func(t *testing.T) {
175178
var v struct {
176179
A string
@@ -179,8 +182,9 @@ func Test_Decoder(t *testing.T) {
179182
D map[string]interface{}
180183
E [2]string
181184
F interface{}
185+
G func()
182186
}
183-
assertErr(t, json.Unmarshal([]byte(`{"a":null,"b":null,"c":null,"d":null,"e":null,"f":null}`), &v))
187+
assertErr(t, json.Unmarshal([]byte(`{"a":null,"b":null,"c":null,"d":null,"e":null,"f":null,"g":null}`), &v))
184188
assertEq(t, "string", v.A, "")
185189
assertNeq(t, "[]string", v.B, nil)
186190
assertEq(t, "[]string", len(v.B), 0)
@@ -191,6 +195,7 @@ func Test_Decoder(t *testing.T) {
191195
assertNeq(t, "array", v.E, nil)
192196
assertEq(t, "array", len(v.E), 2)
193197
assertEq(t, "interface{}", v.F, nil)
198+
assertEq(t, "nilfunc", true, v.G == nil)
194199
})
195200
})
196201
t.Run("interface", func(t *testing.T) {
@@ -239,6 +244,11 @@ func Test_Decoder(t *testing.T) {
239244
assertEq(t, "interface", nil, v)
240245
})
241246
})
247+
t.Run("func", func(t *testing.T) {
248+
var v func()
249+
assertErr(t, json.Unmarshal([]byte(`null`), &v))
250+
assertEq(t, "nilfunc", true, v == nil)
251+
})
242252
}
243253

244254
func TestIssue98(t *testing.T) {

internal/decoder/compile.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,15 @@ func compile(typ *runtime.Type, structName, fieldName string, structTypeToDecode
123123
return compileFloat32(structName, fieldName)
124124
case reflect.Float64:
125125
return compileFloat64(structName, fieldName)
126+
case reflect.Func:
127+
return compileFunc(typ, structName, fieldName)
126128
}
127129
return nil, &errors.UnmarshalTypeError{
128130
Value: "object",
129131
Type: runtime.RType2Type(typ),
130132
Offset: 0,
133+
Struct: structName,
134+
Field: fieldName,
131135
}
132136
}
133137

@@ -178,6 +182,8 @@ ERROR:
178182
Value: "object",
179183
Type: runtime.RType2Type(typ),
180184
Offset: 0,
185+
Struct: structName,
186+
Field: fieldName,
181187
}
182188
}
183189

@@ -312,6 +318,10 @@ func compileInterface(typ *runtime.Type, structName, fieldName string) (Decoder,
312318
return newInterfaceDecoder(typ, structName, fieldName), nil
313319
}
314320

321+
func compileFunc(typ *runtime.Type, strutName, fieldName string) (Decoder, error) {
322+
return newFuncDecoder(typ, strutName, fieldName), nil
323+
}
324+
315325
func removeConflictFields(fieldMap map[string]*structFieldSet, conflictedMap map[string]struct{}, dec *structDecoder, field reflect.StructField) {
316326
for k, v := range dec.fieldMap {
317327
if _, exists := conflictedMap[k]; exists {

internal/decoder/func.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package decoder
2+
3+
import (
4+
"bytes"
5+
"unsafe"
6+
7+
"github.com/goccy/go-json/internal/errors"
8+
"github.com/goccy/go-json/internal/runtime"
9+
)
10+
11+
type funcDecoder struct {
12+
typ *runtime.Type
13+
structName string
14+
fieldName string
15+
}
16+
17+
func newFuncDecoder(typ *runtime.Type, structName, fieldName string) *funcDecoder {
18+
fnDecoder := &funcDecoder{typ, structName, fieldName}
19+
return fnDecoder
20+
}
21+
22+
func (d *funcDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
23+
s.skipWhiteSpace()
24+
start := s.cursor
25+
if err := s.skipValue(depth); err != nil {
26+
return err
27+
}
28+
src := s.buf[start:s.cursor]
29+
if len(src) > 0 {
30+
switch src[0] {
31+
case '"':
32+
return &errors.UnmarshalTypeError{
33+
Value: "string",
34+
Type: runtime.RType2Type(d.typ),
35+
Offset: s.totalOffset(),
36+
}
37+
case '[':
38+
return &errors.UnmarshalTypeError{
39+
Value: "array",
40+
Type: runtime.RType2Type(d.typ),
41+
Offset: s.totalOffset(),
42+
}
43+
case '{':
44+
return &errors.UnmarshalTypeError{
45+
Value: "object",
46+
Type: runtime.RType2Type(d.typ),
47+
Offset: s.totalOffset(),
48+
}
49+
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
50+
return &errors.UnmarshalTypeError{
51+
Value: "number",
52+
Type: runtime.RType2Type(d.typ),
53+
Offset: s.totalOffset(),
54+
}
55+
case 'n':
56+
if err := nullBytes(s); err != nil {
57+
return err
58+
}
59+
*(*unsafe.Pointer)(p) = nil
60+
return nil
61+
case 't':
62+
if err := trueBytes(s); err == nil {
63+
return &errors.UnmarshalTypeError{
64+
Value: "boolean",
65+
Type: runtime.RType2Type(d.typ),
66+
Offset: s.totalOffset(),
67+
}
68+
}
69+
case 'f':
70+
if err := falseBytes(s); err == nil {
71+
return &errors.UnmarshalTypeError{
72+
Value: "boolean",
73+
Type: runtime.RType2Type(d.typ),
74+
Offset: s.totalOffset(),
75+
}
76+
}
77+
}
78+
}
79+
return errors.ErrNotAtBeginningOfValue(start)
80+
}
81+
82+
func (d *funcDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
83+
buf := ctx.Buf
84+
cursor = skipWhiteSpace(buf, cursor)
85+
start := cursor
86+
end, err := skipValue(buf, cursor, depth)
87+
if err != nil {
88+
return 0, err
89+
}
90+
src := buf[start:end]
91+
if len(src) > 0 {
92+
switch src[0] {
93+
case '"':
94+
return 0, &errors.UnmarshalTypeError{
95+
Value: "string",
96+
Type: runtime.RType2Type(d.typ),
97+
Offset: start,
98+
}
99+
case '[':
100+
return 0, &errors.UnmarshalTypeError{
101+
Value: "array",
102+
Type: runtime.RType2Type(d.typ),
103+
Offset: start,
104+
}
105+
case '{':
106+
return 0, &errors.UnmarshalTypeError{
107+
Value: "object",
108+
Type: runtime.RType2Type(d.typ),
109+
Offset: start,
110+
}
111+
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
112+
return 0, &errors.UnmarshalTypeError{
113+
Value: "number",
114+
Type: runtime.RType2Type(d.typ),
115+
Offset: start,
116+
}
117+
case 'n':
118+
if bytes.Equal(src, nullbytes) {
119+
*(*unsafe.Pointer)(p) = nil
120+
return end, nil
121+
}
122+
case 't':
123+
if err := validateTrue(buf, start); err == nil {
124+
return 0, &errors.UnmarshalTypeError{
125+
Value: "boolean",
126+
Type: runtime.RType2Type(d.typ),
127+
Offset: start,
128+
}
129+
}
130+
case 'f':
131+
if err := validateFalse(buf, start); err == nil {
132+
return 0, &errors.UnmarshalTypeError{
133+
Value: "boolean",
134+
Type: runtime.RType2Type(d.typ),
135+
Offset: start,
136+
}
137+
}
138+
}
139+
}
140+
return 0, errors.ErrNotAtBeginningOfValue(start)
141+
}

0 commit comments

Comments
 (0)