Skip to content

Commit 2941dde

Browse files
author
Tao Wen
committed
support embed struct
1 parent 27f0c11 commit 2941dde

18 files changed

+329
-90
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.vscode

gen/main.go

+66-23
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ var anonymousCounter = 1
2222
var anonymousDecoders = []byte{}
2323
var referencedImports = map[string]string{}
2424
var allImports = map[string]string{}
25+
var prefix string
2526

2627
func init() {
2728
var err error
@@ -35,11 +36,12 @@ func init() {
3536
func main() {
3637
typeSpec := locateTypeSpec()
3738
typeName := typeSpec.Name.Name
39+
prefix = typeName
3840
switch x := typeSpec.Type.(type) {
3941
case *ast.ArrayType:
4042
genArray(typeName, x)
4143
case *ast.StructType:
42-
genStruct(x)
44+
genStruct(typeName, x)
4345
case *ast.MapType:
4446
genMap(x)
4547
default:
@@ -48,25 +50,35 @@ func main() {
4850
}
4951
mainDecoder := lines
5052
lines = []byte{}
53+
switch x := typeSpec.Type.(type) {
54+
case *ast.StructType:
55+
genStructFields(x)
56+
}
57+
fieldsDecoder := lines
58+
lines = []byte{}
5159
_l(fmt.Sprintf("package %s", os.Getenv("GOPACKAGE")))
5260
_n()
5361
_l(`import jsoniter "github.com/json-iterator/tinygo"`)
5462
for alias, path := range referencedImports {
5563
_f(`import %s "%s"`, alias, path)
5664
}
5765
_n()
58-
_f("func %s_json_unmarshal(iter *jsoniter.Iterator, out *%s) {", escapeTypeName(typeName), typeName)
59-
lines = append(lines, anonymousDecoders...)
66+
_f("func %s_json_unmarshal(iter *jsoniter.Iterator, out *%s) {", prefix, typeName)
6067
lines = append(lines, mainDecoder...)
6168
_l("}")
69+
_f("func %s_json_unmarshal_field(iter *jsoniter.Iterator, field string, out *%s) bool {", prefix, typeName)
70+
lines = append(lines, fieldsDecoder...)
71+
_l(" return false")
72+
_l("}")
73+
lines = append(lines, anonymousDecoders...)
6274
_f("type %s_json struct {", typeName)
6375
_l("}")
6476
_f("func (json %s_json) Type() interface{} {", typeName)
6577
_f(" var val %s", typeName)
6678
_l(" return &val")
6779
_l("}")
6880
_f("func (json %s_json) Unmarshal(iter *jsoniter.Iterator, val interface{}) {", typeName)
69-
_f(" %s_json_unmarshal(iter, val.(*%s))", typeName, typeName)
81+
_f(" %s_json_unmarshal(iter, val.(*%s))", prefix, typeName)
7082
_l("}")
7183
outputPath := filepath.Join(cwd, fmt.Sprintf("%s_json.go", typeSpec.Name.Name))
7284
os.WriteFile(outputPath, lines, 0644)
@@ -103,17 +115,13 @@ func nodeToString(node ast.Node) string {
103115
return buf.String()
104116
}
105117

106-
func escapeTypeName(typeName string) string {
107-
return strings.ReplaceAll(typeName, "[]", "array_")
108-
}
109-
110118
func genAnonymousArray(arrayType *ast.ArrayType) string {
111-
decoderName := fmt.Sprintf(`array%d`, anonymousCounter)
119+
decoderName := fmt.Sprintf(`%s_array%d`, prefix, anonymousCounter)
112120
typeName := nodeToString(arrayType)
113121
anonymousCounter++
114122
oldLines := lines
115123
lines = []byte{}
116-
_f("%s_json_unmarshal := func (iter *jsoniter.Iterator, out *%s) {", decoderName, typeName)
124+
_f("func %s_json_unmarshal (iter *jsoniter.Iterator, out *%s) {", decoderName, typeName)
117125
genArray(typeName, arrayType)
118126
_l("}")
119127
anonymousDecoders = append(anonymousDecoders, lines...)
@@ -122,26 +130,29 @@ func genAnonymousArray(arrayType *ast.ArrayType) string {
122130
}
123131

124132
func genAnonymousStruct(structType *ast.StructType) string {
125-
decoderName := fmt.Sprintf(`struct%d`, anonymousCounter)
126-
typeName := nodeToString(structType)
133+
decoderName := fmt.Sprintf(`%s_struct%d`, prefix, anonymousCounter)
127134
anonymousCounter++
128135
oldLines := lines
129136
lines = []byte{}
130-
_f("%s_json_unmarshal := func (iter *jsoniter.Iterator, out *%s) {", decoderName, typeName)
131-
genStruct(structType)
137+
_f("func %s_json_unmarshal_field (iter *jsoniter.Iterator, field string, out *%s) bool {", decoderName, nodeToString(structType))
138+
genStructFields(structType)
139+
_l(" return false")
140+
_l("}")
141+
_f("func %s_json_unmarshal (iter *jsoniter.Iterator, out *%s) {", decoderName, nodeToString(structType))
142+
genStruct(decoderName, structType)
132143
_l("}")
133144
anonymousDecoders = append(anonymousDecoders, lines...)
134145
lines = oldLines
135146
return decoderName + "_json_unmarshal(iter, %s)"
136147
}
137148

138149
func genAnonymousMap(mapType *ast.MapType) string {
139-
decoderName := fmt.Sprintf(`map%d`, anonymousCounter)
150+
decoderName := fmt.Sprintf(`%s_map%d`, prefix, anonymousCounter)
140151
typeName := nodeToString(mapType)
141152
anonymousCounter++
142153
oldLines := lines
143154
lines = []byte{}
144-
_f("%s_json_unmarshal := func (iter *jsoniter.Iterator, out *%s) {", decoderName, typeName)
155+
_f("func %s_json_unmarshal (iter *jsoniter.Iterator, out *%s) {", decoderName, typeName)
145156
genMap(mapType)
146157
_l("}")
147158
anonymousDecoders = append(anonymousDecoders, lines...)
@@ -203,14 +214,38 @@ func genMap(mapType *ast.MapType) {
203214
_l(" }")
204215
}
205216

206-
func genStruct(structType *ast.StructType) {
217+
func genStructFields(structType *ast.StructType) {
207218
oldLines := lines
208-
_l(" more := iter.ReadObjectHead()")
209-
_l(" for more {")
210-
_l(" field := iter.ReadObjectField()")
211-
_l(" switch {")
212219
isEmptyStruct := true
220+
for i, field := range structType.Fields.List {
221+
if len(field.Names) != 0 {
222+
continue
223+
}
224+
switch x := field.Type.(type) {
225+
case *ast.StarExpr:
226+
if ident, ok := x.X.(*ast.Ident); ok {
227+
_f(" var val%d %s", i, ident.Name)
228+
_f(" if %s_json_unmarshal_field(iter, field, &val%d) {", ident.Name, i)
229+
_f(" out.%s = new(%s)", ident.Name, ident.Name)
230+
_f(" *out.%s = val%d", ident.Name, i)
231+
_l(" return true")
232+
_l(" }")
233+
} else {
234+
reportError(fmt.Errorf("unknown embed field type: %s", field.Type))
235+
return
236+
}
237+
case *ast.Ident:
238+
_f(" if %s_json_unmarshal_field(iter, field, &out.%s) { return true }", x.Name, x.Name)
239+
default:
240+
reportError(fmt.Errorf("unknown embed field type: %s", field.Type))
241+
return
242+
}
243+
}
244+
_l(" switch {")
213245
for _, field := range structType.Fields.List {
246+
if len(field.Names) == 0 {
247+
continue
248+
}
214249
fieldName := field.Names[0].Name
215250
encodedFieldName := fieldName
216251
if field.Tag != nil {
@@ -234,14 +269,22 @@ func genStruct(structType *ast.StructType) {
234269
}
235270
isEmptyStruct = false
236271
ptr := fmt.Sprintf("&(*out).%s", fieldName)
237-
_f(" case field == `%s`:", encodedFieldName)
272+
_f(" case field == `%s`:", encodedFieldName)
238273
genDecodeStmt(field.Type, ptr)
274+
_l(" return true")
239275
}
276+
_l(" }")
240277
if isEmptyStruct {
241278
lines = oldLines
242279
return
243280
}
244-
_l(" default:")
281+
}
282+
283+
func genStruct(typeName string, structType *ast.StructType) {
284+
_l(" more := iter.ReadObjectHead()")
285+
_l(" for more {")
286+
_l(" field := iter.ReadObjectField()")
287+
_f(" if !%s_json_unmarshal_field(iter, field, out) {", typeName)
245288
_l(" iter.Skip()")
246289
_l(" }")
247290
_l(" more = iter.ReadObjectMore()")

value_tests/AnonymousArray_json.go

+18-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,24 @@ package value_tests
33
import jsoniter "github.com/json-iterator/tinygo"
44

55
func AnonymousArray_json_unmarshal(iter *jsoniter.Iterator, out *AnonymousArray) {
6-
array1_json_unmarshal := func (iter *jsoniter.Iterator, out *[]string) {
6+
more := iter.ReadObjectHead()
7+
for more {
8+
field := iter.ReadObjectField()
9+
if !AnonymousArray_json_unmarshal_field(iter, field, out) {
10+
iter.Skip()
11+
}
12+
more = iter.ReadObjectMore()
13+
}
14+
}
15+
func AnonymousArray_json_unmarshal_field(iter *jsoniter.Iterator, field string, out *AnonymousArray) bool {
16+
switch {
17+
case field == `Value`:
18+
AnonymousArray_array1_json_unmarshal(iter, &(*out).Value)
19+
return true
20+
}
21+
return false
22+
}
23+
func AnonymousArray_array1_json_unmarshal (iter *jsoniter.Iterator, out *[]string) {
724
i := 0
825
val := *out
926
more := iter.ReadArrayHead()
@@ -20,18 +37,6 @@ array1_json_unmarshal := func (iter *jsoniter.Iterator, out *[]string) {
2037
} else {
2138
*out = val[:i]
2239
}
23-
}
24-
more := iter.ReadObjectHead()
25-
for more {
26-
field := iter.ReadObjectField()
27-
switch {
28-
case field == `Value`:
29-
array1_json_unmarshal(iter, &(*out).Value)
30-
default:
31-
iter.Skip()
32-
}
33-
more = iter.ReadObjectMore()
34-
}
3540
}
3641
type AnonymousArray_json struct {
3742
}

value_tests/AnonymousMap_json.go

+18-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,24 @@ package value_tests
33
import jsoniter "github.com/json-iterator/tinygo"
44

55
func AnonymousMap_json_unmarshal(iter *jsoniter.Iterator, out *AnonymousMap) {
6-
map1_json_unmarshal := func (iter *jsoniter.Iterator, out *map[string]string) {
6+
more := iter.ReadObjectHead()
7+
for more {
8+
field := iter.ReadObjectField()
9+
if !AnonymousMap_json_unmarshal_field(iter, field, out) {
10+
iter.Skip()
11+
}
12+
more = iter.ReadObjectMore()
13+
}
14+
}
15+
func AnonymousMap_json_unmarshal_field(iter *jsoniter.Iterator, field string, out *AnonymousMap) bool {
16+
switch {
17+
case field == `Value`:
18+
AnonymousMap_map1_json_unmarshal(iter, &(*out).Value)
19+
return true
20+
}
21+
return false
22+
}
23+
func AnonymousMap_map1_json_unmarshal (iter *jsoniter.Iterator, out *map[string]string) {
724
more := iter.ReadObjectHead()
825
if *out == nil && iter.Error == nil {
926
*out = make(map[string]string)
@@ -22,18 +39,6 @@ map1_json_unmarshal := func (iter *jsoniter.Iterator, out *map[string]string) {
2239
}
2340
more = iter.ReadObjectMore()
2441
}
25-
}
26-
more := iter.ReadObjectHead()
27-
for more {
28-
field := iter.ReadObjectField()
29-
switch {
30-
case field == `Value`:
31-
map1_json_unmarshal(iter, &(*out).Value)
32-
default:
33-
iter.Skip()
34-
}
35-
more = iter.ReadObjectMore()
36-
}
3742
}
3843
type AnonymousMap_json struct {
3944
}

value_tests/AnonymousStruct_json.go

+28-14
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,45 @@ package value_tests
33
import jsoniter "github.com/json-iterator/tinygo"
44

55
func AnonymousStruct_json_unmarshal(iter *jsoniter.Iterator, out *AnonymousStruct) {
6-
struct1_json_unmarshal := func (iter *jsoniter.Iterator, out *struct {
7-
Name string
8-
Price int
9-
}) {
106
more := iter.ReadObjectHead()
117
for more {
128
field := iter.ReadObjectField()
13-
switch {
14-
case field == `Name`:
15-
iter.ReadString(&(*out).Name)
16-
case field == `Price`:
17-
iter.ReadInt(&(*out).Price)
18-
default:
9+
if !AnonymousStruct_json_unmarshal_field(iter, field, out) {
1910
iter.Skip()
2011
}
2112
more = iter.ReadObjectMore()
2213
}
2314
}
15+
func AnonymousStruct_json_unmarshal_field(iter *jsoniter.Iterator, field string, out *AnonymousStruct) bool {
16+
switch {
17+
case field == `Value`:
18+
AnonymousStruct_struct1_json_unmarshal(iter, &(*out).Value)
19+
return true
20+
}
21+
return false
22+
}
23+
func AnonymousStruct_struct1_json_unmarshal_field (iter *jsoniter.Iterator, field string, out *struct {
24+
Name string
25+
Price int
26+
}) bool {
27+
switch {
28+
case field == `Name`:
29+
iter.ReadString(&(*out).Name)
30+
return true
31+
case field == `Price`:
32+
iter.ReadInt(&(*out).Price)
33+
return true
34+
}
35+
return false
36+
}
37+
func AnonymousStruct_struct1_json_unmarshal (iter *jsoniter.Iterator, out *struct {
38+
Name string
39+
Price int
40+
}) {
2441
more := iter.ReadObjectHead()
2542
for more {
2643
field := iter.ReadObjectField()
27-
switch {
28-
case field == `Value`:
29-
struct1_json_unmarshal(iter, &(*out).Value)
30-
default:
44+
if !AnonymousStruct_struct1_json_unmarshal_field(iter, field, out) {
3145
iter.Skip()
3246
}
3347
more = iter.ReadObjectMore()

value_tests/EmptyStruct_json.go

+11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ package value_tests
33
import jsoniter "github.com/json-iterator/tinygo"
44

55
func EmptyStruct_json_unmarshal(iter *jsoniter.Iterator, out *EmptyStruct) {
6+
more := iter.ReadObjectHead()
7+
for more {
8+
field := iter.ReadObjectField()
9+
if !EmptyStruct_json_unmarshal_field(iter, field, out) {
10+
iter.Skip()
11+
}
12+
more = iter.ReadObjectMore()
13+
}
14+
}
15+
func EmptyStruct_json_unmarshal_field(iter *jsoniter.Iterator, field string, out *EmptyStruct) bool {
16+
return false
617
}
718
type EmptyStruct_json struct {
819
}

value_tests/IntKeyMap_json.go

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ func IntKeyMap_json_unmarshal(iter *jsoniter.Iterator, out *IntKeyMap) {
2222
more = iter.ReadObjectMore()
2323
}
2424
}
25+
func IntKeyMap_json_unmarshal_field(iter *jsoniter.Iterator, field string, out *IntKeyMap) bool {
26+
return false
27+
}
2528
type IntKeyMap_json struct {
2629
}
2730
func (json IntKeyMap_json) Type() interface{} {

value_tests/NamedArray_json.go

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ func NamedArray_json_unmarshal(iter *jsoniter.Iterator, out *NamedArray) {
2020
*out = val[:i]
2121
}
2222
}
23+
func NamedArray_json_unmarshal_field(iter *jsoniter.Iterator, field string, out *NamedArray) bool {
24+
return false
25+
}
2326
type NamedArray_json struct {
2427
}
2528
func (json NamedArray_json) Type() interface{} {

value_tests/NamedMap_json.go

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ func NamedMap_json_unmarshal(iter *jsoniter.Iterator, out *NamedMap) {
2222
more = iter.ReadObjectMore()
2323
}
2424
}
25+
func NamedMap_json_unmarshal_field(iter *jsoniter.Iterator, field string, out *NamedMap) bool {
26+
return false
27+
}
2528
type NamedMap_json struct {
2629
}
2730
func (json NamedMap_json) Type() interface{} {

0 commit comments

Comments
 (0)