Skip to content

Commit

Permalink
Merge pull request #264 from goccy/feature/fix-indirect
Browse files Browse the repository at this point in the history
Fix encoding of indirect layout structure
  • Loading branch information
goccy committed Jul 5, 2021
2 parents 36a91cc + 9028569 commit 0a7e5d9
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 3 deletions.
29 changes: 29 additions & 0 deletions encode_test.go
Expand Up @@ -2004,3 +2004,32 @@ func TestInterfaceWithPointer(t *testing.T) {
}
assertEq(t, "interface{}", string(expected), string(actual))
}

func TestIssue263(t *testing.T) {
type Foo struct {
A []string `json:"a"`
B int `json:"b"`
}

type MyStruct struct {
Foo *Foo `json:"foo,omitempty"`
}

s := MyStruct{
Foo: &Foo{
A: []string{"ls -lah"},
B: 0,
},
}
expected, err := stdjson.Marshal(s)
if err != nil {
t.Fatal(err)
}
actual, err := json.Marshal(s)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(expected, actual) {
t.Fatalf("expected:[%s] but got:[%s]", string(expected), string(actual))
}
}
12 changes: 9 additions & 3 deletions internal/encoder/compiler.go
Expand Up @@ -1440,8 +1440,10 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
// if parent is indirect type, set child indirect property to true
valueCode.Flags |= IndirectFlags
} else {
// if parent is not indirect type and child have only one field, set child indirect property to false
if i == 0 && valueCode.NextField != nil && valueCode.NextField.Op == OpStructEnd {
// if parent is not indirect type, set child indirect property to false.
// but if parent's indirect is false and isPtr is true, then indirect must be true.
// Do this only if indirectConversion is enabled at the end of compileStruct.
if i == 0 {
valueCode.Flags &= ^IndirectFlags
}
}
Expand Down Expand Up @@ -1544,7 +1546,11 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
delete(ctx.structTypeToCompiledCode, typeptr)

if !disableIndirectConversion && (head.Flags&IndirectFlags == 0) && isPtr {
head.Flags |= IndirectFlags
headCode := head
for strings.Contains(headCode.Op.String(), "Head") {
headCode.Flags |= IndirectFlags
headCode = headCode.Next
}
}

return ret, nil
Expand Down
100 changes: 100 additions & 0 deletions test/cover/cover_int_test.go
Expand Up @@ -631,6 +631,56 @@ func TestCoverInt(t *testing.T) {
}{A: -1}},
},

// HeadIntNotRootMultiFields
{
name: "HeadIntNotRootMultiFields",
data: struct {
A struct {
A int `json:"a"`
B int `json:"b"`
}
}{A: struct {
A int `json:"a"`
B int `json:"b"`
}{A: -1, B: 1}},
},
{
name: "HeadIntNotRootOmitEmptyMultiFields",
data: struct {
A struct {
A int `json:"a,omitempty"`
B int `json:"b,omitempty"`
}
}{A: struct {
A int `json:"a,omitempty"`
B int `json:"b,omitempty"`
}{A: -1, B: 1}},
},
{
name: "HeadIntNotRootStringMultiFields",
data: struct {
A struct {
A int `json:"a,string"`
B int `json:"b,string"`
}
}{A: struct {
A int `json:"a,string"`
B int `json:"b,string"`
}{A: -1, B: 1}},
},
{
name: "HeadIntNotRootStringOmitEmptyMultiFields",
data: struct {
A struct {
A int `json:"a,string,omitempty"`
B int `json:"b,string,omitempty"`
}
}{A: struct {
A int `json:"a,string,omitempty"`
B int `json:"b,string,omitempty"`
}{A: -1, B: 1}},
},

// HeadIntPtrNotRoot
{
name: "HeadIntPtrNotRoot",
Expand Down Expand Up @@ -791,6 +841,56 @@ func TestCoverInt(t *testing.T) {
}{A: -1})},
},

// PtrHeadIntNotRootMultiFields
{
name: "PtrHeadIntNotRootMultiFields",
data: struct {
A *struct {
A int `json:"a"`
B int `json:"b"`
}
}{A: &(struct {
A int `json:"a"`
B int `json:"b"`
}{A: -1, B: 1})},
},
{
name: "PtrHeadIntNotRootOmitEmptyMultiFields",
data: struct {
A *struct {
A int `json:"a,omitempty"`
B int `json:"b,omitempty"`
}
}{A: &(struct {
A int `json:"a,omitempty"`
B int `json:"b,omitempty"`
}{A: -1, B: 1})},
},
{
name: "PtrHeadIntNotRootStringMultiFields",
data: struct {
A *struct {
A int `json:"a,string"`
B int `json:"b,string"`
}
}{A: &(struct {
A int `json:"a,string"`
B int `json:"b,string"`
}{A: -1, B: 1})},
},
{
name: "PtrHeadIntNotRootStringOmitEmptyMultiFields",
data: struct {
A *struct {
A int `json:"a,string,omitempty"`
B int `json:"b,string,omitempty"`
}
}{A: &(struct {
A int `json:"a,string,omitempty"`
B int `json:"b,string,omitempty"`
}{A: -1, B: 1})},
},

// PtrHeadIntPtrNotRoot
{
name: "PtrHeadIntPtrNotRoot",
Expand Down

0 comments on commit 0a7e5d9

Please sign in to comment.