forked from mirror/go-json
Merge pull request #40 from goccy/feature/fix-anonymous-struct
Fix anonymous struct fields
This commit is contained in:
commit
76cbb4ce68
|
@ -622,7 +622,6 @@ type structFieldPair struct {
|
|||
}
|
||||
|
||||
func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, valueCode *structFieldCode) map[string][]structFieldPair {
|
||||
//fmt.Println("type = ", typ, "valueCode = ", valueCode.dump())
|
||||
anonymousFields := map[string][]structFieldPair{}
|
||||
f := valueCode
|
||||
var prevAnonymousField *structFieldCode
|
||||
|
|
|
@ -112,15 +112,24 @@ func (c *opcode) dump() string {
|
|||
codes := []string{}
|
||||
for code := c; code.op != opEnd; {
|
||||
indent := strings.Repeat(" ", code.indent)
|
||||
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||
switch code.op.codeType() {
|
||||
case codeArrayElem:
|
||||
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||
code = code.toArrayElemCode().end
|
||||
case codeSliceElem:
|
||||
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||
code = code.toSliceElemCode().end
|
||||
case codeMapKey:
|
||||
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||
code = code.toMapKeyCode().end
|
||||
case codeStructField:
|
||||
sf := code.toStructFieldCode()
|
||||
key := sf.displayKey
|
||||
offset := sf.offset
|
||||
codes = append(codes, fmt.Sprintf("%s%s [%s:%d] ( %p )", indent, code.op, key, offset, unsafe.Pointer(code)))
|
||||
code = code.next
|
||||
default:
|
||||
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||
code = code.next
|
||||
}
|
||||
}
|
||||
|
|
177
encode_test.go
177
encode_test.go
|
@ -1392,3 +1392,180 @@ func TestDuplicatedFieldDisappears(t *testing.T) {
|
|||
t.Fatalf("Marshal: got %s want %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnonymousFields(t *testing.T) {
|
||||
tests := []struct {
|
||||
label string // Test name
|
||||
makeInput func() interface{} // Function to create input value
|
||||
want string // Expected JSON output
|
||||
}{{
|
||||
// Both S1 and S2 have a field named X. From the perspective of S,
|
||||
// it is ambiguous which one X refers to.
|
||||
// This should not serialize either field.
|
||||
label: "AmbiguousField",
|
||||
makeInput: func() interface{} {
|
||||
type (
|
||||
S1 struct{ x, X int }
|
||||
S2 struct{ x, X int }
|
||||
S struct {
|
||||
S1
|
||||
S2
|
||||
}
|
||||
)
|
||||
return S{S1{1, 2}, S2{3, 4}}
|
||||
},
|
||||
want: `{}`,
|
||||
}, {
|
||||
label: "DominantField",
|
||||
// Both S1 and S2 have a field named X, but since S has an X field as
|
||||
// well, it takes precedence over S1.X and S2.X.
|
||||
makeInput: func() interface{} {
|
||||
type (
|
||||
S1 struct{ x, X int }
|
||||
S2 struct{ x, X int }
|
||||
S struct {
|
||||
S1
|
||||
S2
|
||||
x, X int
|
||||
}
|
||||
)
|
||||
return S{S1{1, 2}, S2{3, 4}, 5, 6}
|
||||
},
|
||||
want: `{"X":6}`,
|
||||
}, {
|
||||
// Unexported embedded field of non-struct type should not be serialized.
|
||||
label: "UnexportedEmbeddedInt",
|
||||
makeInput: func() interface{} {
|
||||
type (
|
||||
myInt int
|
||||
S struct{ myInt }
|
||||
)
|
||||
return S{5}
|
||||
},
|
||||
want: `{}`,
|
||||
}, {
|
||||
// Exported embedded field of non-struct type should be serialized.
|
||||
label: "ExportedEmbeddedInt",
|
||||
makeInput: func() interface{} {
|
||||
type (
|
||||
MyInt int
|
||||
S struct{ MyInt }
|
||||
)
|
||||
return S{5}
|
||||
},
|
||||
want: `{"MyInt":5}`,
|
||||
}, {
|
||||
// Unexported embedded field of pointer to non-struct type
|
||||
// should not be serialized.
|
||||
label: "UnexportedEmbeddedIntPointer",
|
||||
makeInput: func() interface{} {
|
||||
type (
|
||||
myInt int
|
||||
S struct{ *myInt }
|
||||
)
|
||||
s := S{new(myInt)}
|
||||
*s.myInt = 5
|
||||
return s
|
||||
},
|
||||
want: `{}`,
|
||||
}, {
|
||||
// Exported embedded field of pointer to non-struct type
|
||||
// should be serialized.
|
||||
label: "ExportedEmbeddedIntPointer",
|
||||
makeInput: func() interface{} {
|
||||
type (
|
||||
MyInt int
|
||||
S struct{ *MyInt }
|
||||
)
|
||||
s := S{new(MyInt)}
|
||||
*s.MyInt = 5
|
||||
return s
|
||||
},
|
||||
want: `{"MyInt":5}`,
|
||||
}, {
|
||||
// Exported fields of embedded structs should have their
|
||||
// exported fields be serialized regardless of whether the struct types
|
||||
// themselves are exported.
|
||||
label: "EmbeddedStruct",
|
||||
makeInput: func() interface{} {
|
||||
type (
|
||||
s1 struct{ x, X int }
|
||||
S2 struct{ y, Y int }
|
||||
S struct {
|
||||
s1
|
||||
S2
|
||||
}
|
||||
)
|
||||
return S{s1{1, 2}, S2{3, 4}}
|
||||
},
|
||||
want: `{"X":2,"Y":4}`,
|
||||
}, {
|
||||
// Exported fields of pointers to embedded structs should have their
|
||||
// exported fields be serialized regardless of whether the struct types
|
||||
// themselves are exported.
|
||||
label: "EmbeddedStructPointer",
|
||||
makeInput: func() interface{} {
|
||||
type (
|
||||
s1 struct{ x, X int }
|
||||
S2 struct{ y, Y int }
|
||||
S struct {
|
||||
*s1
|
||||
*S2
|
||||
}
|
||||
)
|
||||
return S{&s1{1, 2}, &S2{3, 4}}
|
||||
},
|
||||
want: `{"X":2,"Y":4}`,
|
||||
}, {
|
||||
// Exported fields on embedded unexported structs at multiple levels
|
||||
// of nesting should still be serialized.
|
||||
label: "NestedStructAndInts",
|
||||
makeInput: func() interface{} {
|
||||
type (
|
||||
MyInt1 int
|
||||
MyInt2 int
|
||||
myInt int
|
||||
s2 struct {
|
||||
MyInt2
|
||||
myInt
|
||||
}
|
||||
s1 struct {
|
||||
MyInt1
|
||||
myInt
|
||||
s2
|
||||
}
|
||||
S struct {
|
||||
s1
|
||||
myInt
|
||||
}
|
||||
)
|
||||
return S{s1{1, 2, s2{3, 4}}, 6}
|
||||
},
|
||||
want: `{"MyInt1":1,"MyInt2":3}`,
|
||||
}, {
|
||||
// If an anonymous struct pointer field is nil, we should ignore
|
||||
// the embedded fields behind it. Not properly doing so may
|
||||
// result in the wrong output or reflect panics.
|
||||
label: "EmbeddedFieldBehindNilPointer",
|
||||
makeInput: func() interface{} {
|
||||
type (
|
||||
S2 struct{ Field string }
|
||||
S struct{ *S2 }
|
||||
)
|
||||
return S{}
|
||||
},
|
||||
want: `{}`,
|
||||
}}
|
||||
|
||||
for i, tt := range tests {
|
||||
t.Run(tt.label, func(t *testing.T) {
|
||||
b, err := json.Marshal(tt.makeInput())
|
||||
if err != nil {
|
||||
t.Fatalf("%d: Marshal() = %v, want nil error", i, err)
|
||||
}
|
||||
if string(b) != tt.want {
|
||||
t.Fatalf("%d: Marshal() = %q, want %q", i, b, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
164
encode_vm.go
164
encode_vm.go
|
@ -538,7 +538,11 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHead {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end.next
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
|
@ -566,12 +570,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadInt {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeInt(e.ptrToInt(ptr))
|
||||
e.encodeInt(e.ptrToInt(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -585,7 +593,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeInt(e.ptrToInt(ptr))
|
||||
e.encodeInt(e.ptrToInt(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -596,12 +604,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadInt8 {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeInt8(e.ptrToInt8(ptr))
|
||||
e.encodeInt8(e.ptrToInt8(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -615,7 +627,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeInt8(e.ptrToInt8(ptr))
|
||||
e.encodeInt8(e.ptrToInt8(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -626,12 +638,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadInt16 {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeInt16(e.ptrToInt16(ptr))
|
||||
e.encodeInt16(e.ptrToInt16(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -645,7 +661,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeInt16(e.ptrToInt16(ptr))
|
||||
e.encodeInt16(e.ptrToInt16(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -656,12 +672,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadInt32 {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeInt32(e.ptrToInt32(ptr))
|
||||
e.encodeInt32(e.ptrToInt32(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -675,7 +695,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeInt32(e.ptrToInt32(ptr))
|
||||
e.encodeInt32(e.ptrToInt32(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -686,12 +706,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadInt64 {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeInt64(e.ptrToInt64(ptr))
|
||||
e.encodeInt64(e.ptrToInt64(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -705,7 +729,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeInt64(e.ptrToInt64(ptr))
|
||||
e.encodeInt64(e.ptrToInt64(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -716,12 +740,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadUint {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeUint(e.ptrToUint(ptr))
|
||||
e.encodeUint(e.ptrToUint(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -735,7 +763,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeUint(e.ptrToUint(ptr))
|
||||
e.encodeUint(e.ptrToUint(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -746,12 +774,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadUint8 {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeUint8(e.ptrToUint8(ptr))
|
||||
e.encodeUint8(e.ptrToUint8(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -765,7 +797,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeUint8(e.ptrToUint8(ptr))
|
||||
e.encodeUint8(e.ptrToUint8(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -776,12 +808,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadUint16 {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeUint16(e.ptrToUint16(ptr))
|
||||
e.encodeUint16(e.ptrToUint16(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -795,7 +831,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeUint16(e.ptrToUint16(ptr))
|
||||
e.encodeUint16(e.ptrToUint16(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -806,12 +842,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadUint32 {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeUint32(e.ptrToUint32(ptr))
|
||||
e.encodeUint32(e.ptrToUint32(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -825,7 +865,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeUint32(e.ptrToUint32(ptr))
|
||||
e.encodeUint32(e.ptrToUint32(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -836,12 +876,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadUint64 {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeUint64(e.ptrToUint64(ptr))
|
||||
e.encodeUint64(e.ptrToUint64(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -855,7 +899,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeUint64(e.ptrToUint64(ptr))
|
||||
e.encodeUint64(e.ptrToUint64(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -866,12 +910,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadFloat32 {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeFloat32(e.ptrToFloat32(ptr))
|
||||
e.encodeFloat32(e.ptrToFloat32(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -885,7 +933,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeFloat32(e.ptrToFloat32(ptr))
|
||||
e.encodeFloat32(e.ptrToFloat32(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -896,10 +944,14 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadFloat64 {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
v := e.ptrToFloat64(ptr)
|
||||
v := e.ptrToFloat64(ptr + field.offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return &UnsupportedValueError{
|
||||
Value: reflect.ValueOf(v),
|
||||
|
@ -921,7 +973,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
if ptr == 0 {
|
||||
code = field.end
|
||||
} else {
|
||||
v := e.ptrToFloat64(ptr)
|
||||
v := e.ptrToFloat64(ptr + field.offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return &UnsupportedValueError{
|
||||
Value: reflect.ValueOf(v),
|
||||
|
@ -940,12 +992,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadString {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeString(e.ptrToString(ptr))
|
||||
e.encodeString(e.ptrToString(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -959,7 +1015,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeString(e.ptrToString(ptr))
|
||||
e.encodeString(e.ptrToString(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -970,12 +1026,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadBool {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeBool(e.ptrToBool(ptr))
|
||||
e.encodeBool(e.ptrToBool(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -989,7 +1049,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
e.encodeBool(e.ptrToBool(ptr))
|
||||
e.encodeBool(e.ptrToBool(ptr + field.offset))
|
||||
field.nextField.ptr = ptr
|
||||
code = field.next
|
||||
}
|
||||
|
@ -1000,12 +1060,16 @@ func (e *Encoder) run(code *opcode) error {
|
|||
field := code.toStructFieldCode()
|
||||
ptr := field.ptr
|
||||
if ptr == 0 {
|
||||
e.encodeNull()
|
||||
if code.op == opStructFieldPtrHeadBytes {
|
||||
e.encodeNull()
|
||||
} else {
|
||||
e.encodeBytes([]byte{'{', '}'})
|
||||
}
|
||||
code = field.end
|
||||
} else {
|
||||
e.encodeByte('{')
|
||||
e.encodeBytes(field.key)
|
||||
s := base64.StdEncoding.EncodeToString(e.ptrToBytes(ptr))
|
||||
s := base64.StdEncoding.EncodeToString(e.ptrToBytes(ptr + field.offset))
|
||||
e.encodeByte('"')
|
||||
e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s)))
|
||||
e.encodeByte('"')
|
||||
|
@ -1022,7 +1086,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
code = field.end
|
||||
} else {
|
||||
e.encodeBytes(field.key)
|
||||
s := base64.StdEncoding.EncodeToString(e.ptrToBytes(code.ptr))
|
||||
s := base64.StdEncoding.EncodeToString(e.ptrToBytes(code.ptr + field.offset))
|
||||
e.encodeByte('"')
|
||||
e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s)))
|
||||
e.encodeByte('"')
|
||||
|
@ -1043,7 +1107,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
e.encodeBytes(field.key)
|
||||
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
||||
typ: code.typ,
|
||||
ptr: unsafe.Pointer(ptr),
|
||||
ptr: unsafe.Pointer(ptr + field.offset),
|
||||
}))
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
|
||||
|
@ -1084,7 +1148,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
e.encodeBytes(field.key)
|
||||
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
||||
typ: code.typ,
|
||||
ptr: unsafe.Pointer(ptr),
|
||||
ptr: unsafe.Pointer(ptr + field.offset),
|
||||
}))
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
|
||||
|
@ -1127,7 +1191,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
e.encodeBytes(field.key)
|
||||
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
||||
typ: code.typ,
|
||||
ptr: unsafe.Pointer(ptr),
|
||||
ptr: unsafe.Pointer(ptr + field.offset),
|
||||
}))
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
|
||||
|
@ -1158,7 +1222,7 @@ func (e *Encoder) run(code *opcode) error {
|
|||
e.encodeBytes(field.key)
|
||||
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
||||
typ: code.typ,
|
||||
ptr: unsafe.Pointer(ptr),
|
||||
ptr: unsafe.Pointer(ptr + field.offset),
|
||||
}))
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
|
||||
|
|
|
@ -10,9 +10,15 @@ func getTag(field reflect.StructField) string {
|
|||
}
|
||||
|
||||
func isIgnoredStructField(field reflect.StructField) bool {
|
||||
if field.PkgPath != "" && !field.Anonymous {
|
||||
// private field
|
||||
return true
|
||||
if field.PkgPath != "" {
|
||||
if field.Anonymous {
|
||||
if !(field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct) && field.Type.Kind() != reflect.Struct {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
// private field
|
||||
return true
|
||||
}
|
||||
}
|
||||
tag := getTag(field)
|
||||
if tag == "-" {
|
||||
|
|
Loading…
Reference in New Issue