diff --git a/encode_test.go b/encode_test.go index 5b271b0..98f71b0 100644 --- a/encode_test.go +++ b/encode_test.go @@ -191,6 +191,59 @@ func Test_Marshal(t *testing.T) { }) }) }) + + t.Run("embedded with tag", func(t *testing.T) { + type T struct { + A string `json:"a"` + } + type U struct { + *T `json:"t"` + B string `json:"b"` + } + type T2 struct { + A string `json:"a,omitempty"` + } + type U2 struct { + *T2 `json:"t,omitempty"` + B string `json:"b,omitempty"` + } + t.Run("exists field", func(t *testing.T) { + bytes, err := json.Marshal(&U{ + T: &T{ + A: "aaa", + }, + B: "bbb", + }) + assertErr(t, err) + assertEq(t, "embedded", `{"t":{"a":"aaa"},"b":"bbb"}`, string(bytes)) + t.Run("omitempty", func(t *testing.T) { + bytes, err := json.Marshal(&U2{ + T2: &T2{ + A: "aaa", + }, + B: "bbb", + }) + assertErr(t, err) + assertEq(t, "embedded", `{"t":{"a":"aaa"},"b":"bbb"}`, string(bytes)) + }) + }) + + t.Run("none field", func(t *testing.T) { + bytes, err := json.Marshal(&U{ + B: "bbb", + }) + assertErr(t, err) + assertEq(t, "embedded", `{"t":null,"b":"bbb"}`, string(bytes)) + t.Run("omitempty", func(t *testing.T) { + bytes, err := json.Marshal(&U2{ + B: "bbb", + }) + assertErr(t, err) + assertEq(t, "embedded", `{"b":"bbb"}`, string(bytes)) + }) + }) + }) + t.Run("omitempty", func(t *testing.T) { type T struct { A int `json:",omitempty"` diff --git a/internal/cmd/generator/vm.go.tmpl b/internal/cmd/generator/vm.go.tmpl index 78da5e4..f2c992a 100644 --- a/internal/cmd/generator/vm.go.tmpl +++ b/internal/cmd/generator/vm.go.tmpl @@ -578,8 +578,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b if code.Flags&encoder.AnonymousHeadFlags == 0 { b = appendStructHead(ctx, b) } - if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { - b = appendStructKey(ctx, code, b) + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } } p += uintptr(code.Offset) code = code.Next diff --git a/internal/decoder/string.go b/internal/decoder/string.go index 1e1ce15..5b1a00b 100644 --- a/internal/decoder/string.go +++ b/internal/decoder/string.go @@ -170,6 +170,7 @@ RETRY: s.buf = append(s.buf[:s.cursor-1], s.buf[s.cursor:]...) s.length-- s.cursor-- + p = s.bufptr() return p, nil } diff --git a/internal/encoder/compiler.go b/internal/encoder/compiler.go index 01a5d4b..84e4f91 100644 --- a/internal/encoder/compiler.go +++ b/internal/encoder/compiler.go @@ -1417,7 +1417,7 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) { valueCode = code } - if field.Anonymous { + if field.Anonymous && !tag.IsTaggedKey { tagKey := "" if tag.IsTaggedKey { tagKey = tag.Key @@ -1425,6 +1425,7 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) { for k, v := range anonymousStructFieldPairMap(tags, tagKey, valueCode) { anonymousFields[k] = append(anonymousFields[k], v...) } + valueCode.decIndent() // fix issue144 diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index 78da5e4..f2c992a 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -578,8 +578,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b if code.Flags&encoder.AnonymousHeadFlags == 0 { b = appendStructHead(ctx, b) } - if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { - b = appendStructKey(ctx, code, b) + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } } p += uintptr(code.Offset) code = code.Next diff --git a/internal/encoder/vm_color/vm.go b/internal/encoder/vm_color/vm.go index 0d4c472..70de3e7 100644 --- a/internal/encoder/vm_color/vm.go +++ b/internal/encoder/vm_color/vm.go @@ -578,8 +578,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b if code.Flags&encoder.AnonymousHeadFlags == 0 { b = appendStructHead(ctx, b) } - if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { - b = appendStructKey(ctx, code, b) + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } } p += uintptr(code.Offset) code = code.Next diff --git a/internal/encoder/vm_color_indent/vm.go b/internal/encoder/vm_color_indent/vm.go index de8b858..2d014e5 100644 --- a/internal/encoder/vm_color_indent/vm.go +++ b/internal/encoder/vm_color_indent/vm.go @@ -578,8 +578,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b if code.Flags&encoder.AnonymousHeadFlags == 0 { b = appendStructHead(ctx, b) } - if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { - b = appendStructKey(ctx, code, b) + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } } p += uintptr(code.Offset) code = code.Next diff --git a/internal/encoder/vm_indent/vm.go b/internal/encoder/vm_indent/vm.go index d10ce75..25d2ebc 100644 --- a/internal/encoder/vm_indent/vm.go +++ b/internal/encoder/vm_indent/vm.go @@ -578,8 +578,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b if code.Flags&encoder.AnonymousHeadFlags == 0 { b = appendStructHead(ctx, b) } - if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { - b = appendStructKey(ctx, code, b) + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } } p += uintptr(code.Offset) code = code.Next