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 {
|
func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, valueCode *structFieldCode) map[string][]structFieldPair {
|
||||||
//fmt.Println("type = ", typ, "valueCode = ", valueCode.dump())
|
|
||||||
anonymousFields := map[string][]structFieldPair{}
|
anonymousFields := map[string][]structFieldPair{}
|
||||||
f := valueCode
|
f := valueCode
|
||||||
var prevAnonymousField *structFieldCode
|
var prevAnonymousField *structFieldCode
|
||||||
|
|
|
@ -112,15 +112,24 @@ func (c *opcode) dump() string {
|
||||||
codes := []string{}
|
codes := []string{}
|
||||||
for code := c; code.op != opEnd; {
|
for code := c; code.op != opEnd; {
|
||||||
indent := strings.Repeat(" ", code.indent)
|
indent := strings.Repeat(" ", code.indent)
|
||||||
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
|
||||||
switch code.op.codeType() {
|
switch code.op.codeType() {
|
||||||
case codeArrayElem:
|
case codeArrayElem:
|
||||||
|
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||||
code = code.toArrayElemCode().end
|
code = code.toArrayElemCode().end
|
||||||
case codeSliceElem:
|
case codeSliceElem:
|
||||||
|
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||||
code = code.toSliceElemCode().end
|
code = code.toSliceElemCode().end
|
||||||
case codeMapKey:
|
case codeMapKey:
|
||||||
|
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||||
code = code.toMapKeyCode().end
|
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:
|
default:
|
||||||
|
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||||
code = code.next
|
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)
|
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()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHead {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end.next
|
code = field.end.next
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
|
@ -566,12 +570,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadInt {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeInt(e.ptrToInt(ptr))
|
e.encodeInt(e.ptrToInt(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -585,7 +593,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeInt(e.ptrToInt(ptr))
|
e.encodeInt(e.ptrToInt(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -596,12 +604,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadInt8 {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeInt8(e.ptrToInt8(ptr))
|
e.encodeInt8(e.ptrToInt8(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -615,7 +627,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeInt8(e.ptrToInt8(ptr))
|
e.encodeInt8(e.ptrToInt8(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -626,12 +638,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadInt16 {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeInt16(e.ptrToInt16(ptr))
|
e.encodeInt16(e.ptrToInt16(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -645,7 +661,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeInt16(e.ptrToInt16(ptr))
|
e.encodeInt16(e.ptrToInt16(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -656,12 +672,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadInt32 {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeInt32(e.ptrToInt32(ptr))
|
e.encodeInt32(e.ptrToInt32(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -675,7 +695,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeInt32(e.ptrToInt32(ptr))
|
e.encodeInt32(e.ptrToInt32(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -686,12 +706,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadInt64 {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeInt64(e.ptrToInt64(ptr))
|
e.encodeInt64(e.ptrToInt64(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -705,7 +729,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeInt64(e.ptrToInt64(ptr))
|
e.encodeInt64(e.ptrToInt64(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -716,12 +740,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadUint {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeUint(e.ptrToUint(ptr))
|
e.encodeUint(e.ptrToUint(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -735,7 +763,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeUint(e.ptrToUint(ptr))
|
e.encodeUint(e.ptrToUint(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -746,12 +774,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadUint8 {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeUint8(e.ptrToUint8(ptr))
|
e.encodeUint8(e.ptrToUint8(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -765,7 +797,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeUint8(e.ptrToUint8(ptr))
|
e.encodeUint8(e.ptrToUint8(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -776,12 +808,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadUint16 {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeUint16(e.ptrToUint16(ptr))
|
e.encodeUint16(e.ptrToUint16(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -795,7 +831,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeUint16(e.ptrToUint16(ptr))
|
e.encodeUint16(e.ptrToUint16(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -806,12 +842,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadUint32 {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeUint32(e.ptrToUint32(ptr))
|
e.encodeUint32(e.ptrToUint32(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -825,7 +865,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeUint32(e.ptrToUint32(ptr))
|
e.encodeUint32(e.ptrToUint32(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -836,12 +876,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadUint64 {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeUint64(e.ptrToUint64(ptr))
|
e.encodeUint64(e.ptrToUint64(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -855,7 +899,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeUint64(e.ptrToUint64(ptr))
|
e.encodeUint64(e.ptrToUint64(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -866,12 +910,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadFloat32 {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeFloat32(e.ptrToFloat32(ptr))
|
e.encodeFloat32(e.ptrToFloat32(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -885,7 +933,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeFloat32(e.ptrToFloat32(ptr))
|
e.encodeFloat32(e.ptrToFloat32(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -896,10 +944,14 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadFloat64 {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
v := e.ptrToFloat64(ptr)
|
v := e.ptrToFloat64(ptr + field.offset)
|
||||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||||
return &UnsupportedValueError{
|
return &UnsupportedValueError{
|
||||||
Value: reflect.ValueOf(v),
|
Value: reflect.ValueOf(v),
|
||||||
|
@ -921,7 +973,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
v := e.ptrToFloat64(ptr)
|
v := e.ptrToFloat64(ptr + field.offset)
|
||||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||||
return &UnsupportedValueError{
|
return &UnsupportedValueError{
|
||||||
Value: reflect.ValueOf(v),
|
Value: reflect.ValueOf(v),
|
||||||
|
@ -940,12 +992,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadString {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeString(e.ptrToString(ptr))
|
e.encodeString(e.ptrToString(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -959,7 +1015,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeString(e.ptrToString(ptr))
|
e.encodeString(e.ptrToString(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -970,12 +1026,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadBool {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeBool(e.ptrToBool(ptr))
|
e.encodeBool(e.ptrToBool(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -989,7 +1049,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
e.encodeBool(e.ptrToBool(ptr))
|
e.encodeBool(e.ptrToBool(ptr + field.offset))
|
||||||
field.nextField.ptr = ptr
|
field.nextField.ptr = ptr
|
||||||
code = field.next
|
code = field.next
|
||||||
}
|
}
|
||||||
|
@ -1000,12 +1060,16 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
field := code.toStructFieldCode()
|
field := code.toStructFieldCode()
|
||||||
ptr := field.ptr
|
ptr := field.ptr
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
e.encodeNull()
|
if code.op == opStructFieldPtrHeadBytes {
|
||||||
|
e.encodeNull()
|
||||||
|
} else {
|
||||||
|
e.encodeBytes([]byte{'{', '}'})
|
||||||
|
}
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('{')
|
e.encodeByte('{')
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
s := base64.StdEncoding.EncodeToString(e.ptrToBytes(ptr))
|
s := base64.StdEncoding.EncodeToString(e.ptrToBytes(ptr + field.offset))
|
||||||
e.encodeByte('"')
|
e.encodeByte('"')
|
||||||
e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s)))
|
e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s)))
|
||||||
e.encodeByte('"')
|
e.encodeByte('"')
|
||||||
|
@ -1022,7 +1086,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
code = field.end
|
code = field.end
|
||||||
} else {
|
} else {
|
||||||
e.encodeBytes(field.key)
|
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.encodeByte('"')
|
||||||
e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s)))
|
e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s)))
|
||||||
e.encodeByte('"')
|
e.encodeByte('"')
|
||||||
|
@ -1043,7 +1107,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
||||||
typ: code.typ,
|
typ: code.typ,
|
||||||
ptr: unsafe.Pointer(ptr),
|
ptr: unsafe.Pointer(ptr + field.offset),
|
||||||
}))
|
}))
|
||||||
rv := reflect.ValueOf(v)
|
rv := reflect.ValueOf(v)
|
||||||
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
|
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
|
||||||
|
@ -1084,7 +1148,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
||||||
typ: code.typ,
|
typ: code.typ,
|
||||||
ptr: unsafe.Pointer(ptr),
|
ptr: unsafe.Pointer(ptr + field.offset),
|
||||||
}))
|
}))
|
||||||
rv := reflect.ValueOf(v)
|
rv := reflect.ValueOf(v)
|
||||||
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
|
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
|
||||||
|
@ -1127,7 +1191,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
||||||
typ: code.typ,
|
typ: code.typ,
|
||||||
ptr: unsafe.Pointer(ptr),
|
ptr: unsafe.Pointer(ptr + field.offset),
|
||||||
}))
|
}))
|
||||||
rv := reflect.ValueOf(v)
|
rv := reflect.ValueOf(v)
|
||||||
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
|
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
|
||||||
|
@ -1158,7 +1222,7 @@ func (e *Encoder) run(code *opcode) error {
|
||||||
e.encodeBytes(field.key)
|
e.encodeBytes(field.key)
|
||||||
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
||||||
typ: code.typ,
|
typ: code.typ,
|
||||||
ptr: unsafe.Pointer(ptr),
|
ptr: unsafe.Pointer(ptr + field.offset),
|
||||||
}))
|
}))
|
||||||
rv := reflect.ValueOf(v)
|
rv := reflect.ValueOf(v)
|
||||||
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
|
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
|
||||||
|
|
|
@ -10,9 +10,15 @@ func getTag(field reflect.StructField) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func isIgnoredStructField(field reflect.StructField) bool {
|
func isIgnoredStructField(field reflect.StructField) bool {
|
||||||
if field.PkgPath != "" && !field.Anonymous {
|
if field.PkgPath != "" {
|
||||||
// private field
|
if field.Anonymous {
|
||||||
return true
|
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)
|
tag := getTag(field)
|
||||||
if tag == "-" {
|
if tag == "-" {
|
||||||
|
|
Loading…
Reference in New Issue