Skip to content

Commit c359cc2

Browse files
authored
Merge pull request #12 from goccy/feature/fix-field-after-omitempty
Fix encoding of struct field after omitempty field
2 parents a6c3a47 + 7eafd08 commit c359cc2

File tree

4 files changed

+249
-37
lines changed

4 files changed

+249
-37
lines changed

encode_compile.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ func (e *Encoder) compileHead(typ *rtype, withIndent bool) (*opcode, error) {
1616
if typ.Kind() == reflect.Ptr {
1717
typ = typ.Elem()
1818
}
19+
if typ.Kind() == reflect.Map {
20+
return e.compileMap(typ, false, withIndent)
21+
}
1922
return e.compile(typ, withIndent)
2023
}
2124

@@ -33,7 +36,7 @@ func (e *Encoder) compile(typ *rtype, withIndent bool) (*opcode, error) {
3336
case reflect.Array:
3437
return e.compileArray(typ, withIndent)
3538
case reflect.Map:
36-
return e.compileMap(typ, withIndent)
39+
return e.compileMap(typ, true, withIndent)
3740
case reflect.Struct:
3841
return e.compileStruct(typ, withIndent)
3942
case reflect.Int:
@@ -366,7 +369,7 @@ func mapiternext(it unsafe.Pointer)
366369
//go:noescape
367370
func maplen(m unsafe.Pointer) int
368371

369-
func (e *Encoder) compileMap(typ *rtype, withIndent bool) (*opcode, error) {
372+
func (e *Encoder) compileMap(typ *rtype, withLoad, withIndent bool) (*opcode, error) {
370373
// header => code => value => code => key => code => value => code => end
371374
// ^ |
372375
// |_______________________|
@@ -387,13 +390,17 @@ func (e *Encoder) compileMap(typ *rtype, withIndent bool) (*opcode, error) {
387390

388391
e.indent--
389392

390-
header := newMapHeaderCode(typ, e.indent)
393+
header := newMapHeaderCode(typ, withLoad, e.indent)
391394
header.key = key
392395
header.value = value
393396
end := newOpCode(opMapEnd, nil, e.indent, newEndOp(e.indent))
394397

395398
if withIndent {
396-
header.op = opMapHeadIndent
399+
if header.op == opMapHead {
400+
header.op = opMapHeadIndent
401+
} else {
402+
header.op = opMapHeadLoadIndent
403+
}
397404
key.op = opMapKeyIndent
398405
value.op = opMapValueIndent
399406
end.op = opMapEndIndent

encode_opcode.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,13 @@ const (
4747
opArrayEndIndent
4848

4949
opMapHead
50+
opMapHeadLoad
5051
opMapKey
5152
opMapValue
5253
opMapEnd
5354

5455
opMapHeadIndent
56+
opMapHeadLoadIndent
5557
opMapKeyIndent
5658
opMapValueIndent
5759
opMapEndIndent
@@ -327,8 +329,9 @@ func (t opType) String() string {
327329
case opArrayEndIndent:
328330
return "ARRAY_END_INDENT"
329331
case opMapHead:
330-
331332
return "MAP_HEAD"
333+
case opMapHeadLoad:
334+
return "MAP_HEAD_LOAD"
332335
case opMapKey:
333336
return "MAP_KEY"
334337
case opMapValue:
@@ -338,6 +341,8 @@ func (t opType) String() string {
338341

339342
case opMapHeadIndent:
340343
return "MAP_HEAD_INDENT"
344+
case opMapHeadLoadIndent:
345+
return "MAP_HEAD_LOAD_INDENT"
341346
case opMapKeyIndent:
342347
return "MAP_KEY_INDENT"
343348
case opMapValueIndent:
@@ -919,10 +924,16 @@ func (c *mapValueCode) set(iter unsafe.Pointer) {
919924
c.iter = iter
920925
}
921926

922-
func newMapHeaderCode(typ *rtype, indent int) *mapHeaderCode {
927+
func newMapHeaderCode(typ *rtype, withLoad bool, indent int) *mapHeaderCode {
928+
var op opType
929+
if withLoad {
930+
op = opMapHeadLoad
931+
} else {
932+
op = opMapHead
933+
}
923934
return &mapHeaderCode{
924935
opcodeHeader: &opcodeHeader{
925-
op: opMapHead,
936+
op: op,
926937
typ: typ,
927938
indent: indent,
928939
},

encode_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,116 @@ func Test_Marshal(t *testing.T) {
129129
bytes, err := json.Marshal(&v)
130130
assertErr(t, err)
131131
assertEq(t, "struct", `{"t":1}`, string(bytes))
132+
t.Run("int", func(t *testing.T) {
133+
var v struct {
134+
A int `json:"a,omitempty"`
135+
B int `json:"b"`
136+
}
137+
v.B = 1
138+
bytes, err := json.Marshal(&v)
139+
assertErr(t, err)
140+
assertEq(t, "int", `{"b":1}`, string(bytes))
141+
})
142+
t.Run("int8", func(t *testing.T) {
143+
var v struct {
144+
A int `json:"a,omitempty"`
145+
B int8 `json:"b"`
146+
}
147+
v.B = 1
148+
bytes, err := json.Marshal(&v)
149+
assertErr(t, err)
150+
assertEq(t, "int8", `{"b":1}`, string(bytes))
151+
})
152+
t.Run("int16", func(t *testing.T) {
153+
var v struct {
154+
A int `json:"a,omitempty"`
155+
B int16 `json:"b"`
156+
}
157+
v.B = 1
158+
bytes, err := json.Marshal(&v)
159+
assertErr(t, err)
160+
assertEq(t, "int16", `{"b":1}`, string(bytes))
161+
})
162+
t.Run("int32", func(t *testing.T) {
163+
var v struct {
164+
A int `json:"a,omitempty"`
165+
B int32 `json:"b"`
166+
}
167+
v.B = 1
168+
bytes, err := json.Marshal(&v)
169+
assertErr(t, err)
170+
assertEq(t, "int32", `{"b":1}`, string(bytes))
171+
})
172+
t.Run("int64", func(t *testing.T) {
173+
var v struct {
174+
A int `json:"a,omitempty"`
175+
B int64 `json:"b"`
176+
}
177+
v.B = 1
178+
bytes, err := json.Marshal(&v)
179+
assertErr(t, err)
180+
assertEq(t, "int64", `{"b":1}`, string(bytes))
181+
})
182+
t.Run("string", func(t *testing.T) {
183+
var v struct {
184+
A int `json:"a,omitempty"`
185+
B string `json:"b"`
186+
}
187+
v.B = "b"
188+
bytes, err := json.Marshal(&v)
189+
assertErr(t, err)
190+
assertEq(t, "string", `{"b":"b"}`, string(bytes))
191+
})
192+
t.Run("float32", func(t *testing.T) {
193+
var v struct {
194+
A int `json:"a,omitempty"`
195+
B float32 `json:"b"`
196+
}
197+
v.B = 1.1
198+
bytes, err := json.Marshal(&v)
199+
assertErr(t, err)
200+
assertEq(t, "float32", `{"b":1.1}`, string(bytes))
201+
})
202+
t.Run("float64", func(t *testing.T) {
203+
var v struct {
204+
A int `json:"a,omitempty"`
205+
B float64 `json:"b"`
206+
}
207+
v.B = 3.14
208+
bytes, err := json.Marshal(&v)
209+
assertErr(t, err)
210+
assertEq(t, "float64", `{"b":3.14}`, string(bytes))
211+
})
212+
t.Run("slice", func(t *testing.T) {
213+
var v struct {
214+
A int `json:"a,omitempty"`
215+
B []int `json:"b"`
216+
}
217+
v.B = []int{1, 2, 3}
218+
bytes, err := json.Marshal(&v)
219+
assertErr(t, err)
220+
assertEq(t, "slice", `{"b":[1,2,3]}`, string(bytes))
221+
})
222+
t.Run("array", func(t *testing.T) {
223+
var v struct {
224+
A int `json:"a,omitempty"`
225+
B [2]int `json:"b"`
226+
}
227+
v.B = [2]int{1, 2}
228+
bytes, err := json.Marshal(&v)
229+
assertErr(t, err)
230+
assertEq(t, "array", `{"b":[1,2]}`, string(bytes))
231+
})
232+
t.Run("map", func(t *testing.T) {
233+
v := new(struct {
234+
A int `json:"a,omitempty"`
235+
B map[string]interface{} `json:"b"`
236+
})
237+
v.B = map[string]interface{}{"c": 1}
238+
bytes, err := json.Marshal(v)
239+
assertErr(t, err)
240+
assertEq(t, "array", `{"b":{"c":1}}`, string(bytes))
241+
})
132242
})
133243
t.Run("head_omitempty", func(t *testing.T) {
134244
type T struct {

0 commit comments

Comments
 (0)