forked from mirror/go-json
Compare commits
3 Commits
master
...
feature/im
Author | SHA1 | Date |
---|---|---|
Masaaki Goshima | 8411c9142c | |
Masaaki Goshima | 058b3ae1ea | |
Masaaki Goshima | ddcf571e68 |
|
@ -481,6 +481,121 @@ func (t opType) fieldToStringTagField() opType {
|
|||
}
|
||||
}
|
||||
}
|
||||
for _, escapedOrNot := range []string{"", "Escaped"} {
|
||||
for _, ptrOrNot := range []string{"", "Ptr", "NPtr"} {
|
||||
for _, headType := range []string{"", "Anonymous"} {
|
||||
for _, opt := range []string{"", "OmitEmpty", "StringTag"} {
|
||||
for _, typ := range []string{
|
||||
"Int", "Int8", "Int16", "Int32", "Int64",
|
||||
"Uint", "Uint8", "Uint16", "Uint32", "Uint64",
|
||||
"Float32", "Float64", "Bool", "String", "EscapedString", "Bytes",
|
||||
"IntPtr", "Int8Ptr", "Int16Ptr", "Int32Ptr", "Int64Ptr",
|
||||
"UintPtr", "Uint8Ptr", "Uint16Ptr", "Uint32Ptr", "Uint64Ptr",
|
||||
"Float32Ptr", "Float64Ptr", "BoolPtr", "StringPtr", "EscapedStringPtr", "BytesPtr",
|
||||
"IntNPtr", "Int8NPtr", "Int16NPtr", "Int32NPtr", "Int64NPtr",
|
||||
"UintNPtr", "Uint8NPtr", "Uint16NPtr", "Uint32NPtr", "Uint64NPtr",
|
||||
"Float32NPtr", "Float64NPtr", "BoolNPtr", "StringNPtr", "EscapedStringNPtr", "BytesNPtr",
|
||||
} {
|
||||
escapedOrNot := escapedOrNot
|
||||
ptrOrNot := ptrOrNot
|
||||
headType := headType
|
||||
opt := opt
|
||||
typ := typ
|
||||
|
||||
op := fmt.Sprintf(
|
||||
"Struct%sField%s%sHead%s%sOnly",
|
||||
escapedOrNot,
|
||||
ptrOrNot,
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
opTypes = append(opTypes, opType{
|
||||
Op: op,
|
||||
Code: "StructField",
|
||||
Indent: func() string { return fmt.Sprintf("%sIndent", op) },
|
||||
Escaped: func() string {
|
||||
switch typ {
|
||||
case "String", "StringPtr", "StringNPtr":
|
||||
return fmt.Sprintf(
|
||||
"StructEscapedField%s%sHead%sEscaped%sOnly",
|
||||
ptrOrNot,
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"StructEscapedField%s%sHead%s%sOnly",
|
||||
ptrOrNot,
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
HeadToPtrHead: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sFieldPtr%sHead%s%sOnly",
|
||||
escapedOrNot,
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
HeadToNPtrHead: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sFieldNPtr%sHead%s%sOnly",
|
||||
escapedOrNot,
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
HeadToAnonymousHead: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sField%sAnonymousHead%s%sOnly",
|
||||
escapedOrNot,
|
||||
ptrOrNot,
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
HeadToOmitEmptyHead: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sField%s%sHeadOmitEmpty%sOnly",
|
||||
escapedOrNot,
|
||||
ptrOrNot,
|
||||
headType,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
HeadToStringTagHead: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sField%s%sHeadStringTag%sOnly",
|
||||
escapedOrNot,
|
||||
ptrOrNot,
|
||||
headType,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
PtrHeadToHead: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sField%sHead%s%sOnly",
|
||||
escapedOrNot,
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
FieldToEnd: func() string { return op },
|
||||
FieldToOmitEmptyField: func() string { return op },
|
||||
FieldToStringTagField: func() string { return op },
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, escapedOrNot := range []string{"", "Escaped"} {
|
||||
for _, opt := range []string{"", "OmitEmpty", "StringTag"} {
|
||||
for _, typ := range append(primitiveTypesUpper, "") {
|
||||
|
|
|
@ -0,0 +1,417 @@
|
|||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func intptr(v int) *int {
|
||||
return &v
|
||||
}
|
||||
|
||||
func int8ptr(v int8) *int8 {
|
||||
return &v
|
||||
}
|
||||
|
||||
func headIntPtrNilNotRoot() interface{} {
|
||||
v := struct {
|
||||
A struct {
|
||||
A *int `json:"a"`
|
||||
}
|
||||
}{}
|
||||
return v
|
||||
}
|
||||
|
||||
func ptrHeadIntNotRoot() interface{} {
|
||||
v := struct {
|
||||
A *struct {
|
||||
A int `json:"a"`
|
||||
}
|
||||
}{A: new(struct {
|
||||
A int `json:"a"`
|
||||
})}
|
||||
v.A.A = 1
|
||||
return v
|
||||
}
|
||||
|
||||
func TestCoverage(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
expected string
|
||||
data interface{}
|
||||
}{
|
||||
{
|
||||
name: "HeadIntZero",
|
||||
expected: `{"a":0}`,
|
||||
data: struct {
|
||||
A int `json:"a"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "HeadInt",
|
||||
expected: `{"a":1}`,
|
||||
data: struct {
|
||||
A int `json:"a"`
|
||||
}{A: 1},
|
||||
},
|
||||
{
|
||||
name: "HeadIntPtr",
|
||||
expected: `{"a":1}`,
|
||||
data: struct {
|
||||
A *int `json:"a"`
|
||||
}{A: intptr(1)},
|
||||
},
|
||||
{
|
||||
name: "HeadIntPtrNil",
|
||||
expected: `{"a":null}`,
|
||||
data: struct {
|
||||
A *int `json:"a"`
|
||||
}{A: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntZero",
|
||||
expected: `{"a":0}`,
|
||||
data: &struct {
|
||||
A int `json:"a"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadInt",
|
||||
expected: `{"a":1}`,
|
||||
data: &struct {
|
||||
A int `json:"a"`
|
||||
}{A: 1},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntPtr",
|
||||
expected: `{"a":1}`,
|
||||
data: &struct {
|
||||
A *int `json:"a"`
|
||||
}{A: intptr(1)},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntPtrNil",
|
||||
expected: `{"a":null}`,
|
||||
data: &struct {
|
||||
A *int `json:"a"`
|
||||
}{A: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntNil",
|
||||
expected: `null`,
|
||||
data: (*struct {
|
||||
A *int `json:"a"`
|
||||
})(nil),
|
||||
},
|
||||
{
|
||||
name: "HeadIntZeroMultiFields",
|
||||
expected: `{"a":0,"b":0}`,
|
||||
data: struct {
|
||||
A int `json:"a"`
|
||||
B int `json:"b"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "HeadIntMultiFields",
|
||||
expected: `{"a":1,"b":2}`,
|
||||
data: struct {
|
||||
A int `json:"a"`
|
||||
B int `json:"b"`
|
||||
}{A: 1, B: 2},
|
||||
},
|
||||
{
|
||||
name: "HeadIntPtrMultiFields",
|
||||
expected: `{"a":1,"b":2}`,
|
||||
data: struct {
|
||||
A *int `json:"a"`
|
||||
B *int `json:"b"`
|
||||
}{A: intptr(1), B: intptr(2)},
|
||||
},
|
||||
{
|
||||
name: "HeadIntPtrNilMultiFieldsd",
|
||||
expected: `{"a":null,"b":null}`,
|
||||
data: struct {
|
||||
A *int `json:"a"`
|
||||
B *int `json:"b"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntZeroMultiFields",
|
||||
expected: `{"a":0,"b":0}`,
|
||||
data: &struct {
|
||||
A int `json:"a"`
|
||||
B int `json:"b"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntMultiFields",
|
||||
expected: `{"a":1,"b":2}`,
|
||||
data: &struct {
|
||||
A int `json:"a"`
|
||||
B int `json:"b"`
|
||||
}{A: 1, B: 2},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntPtrMultiFields",
|
||||
expected: `{"a":1,"b":2}`,
|
||||
data: &struct {
|
||||
A *int `json:"a"`
|
||||
B *int `json:"b"`
|
||||
}{A: intptr(1), B: intptr(2)},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntPtrNilMultiFields",
|
||||
expected: `{"a":null,"b":null}`,
|
||||
data: &struct {
|
||||
A *int `json:"a"`
|
||||
B *int `json:"b"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntNilMultiFields",
|
||||
expected: `null`,
|
||||
data: (*struct {
|
||||
A *int `json:"a"`
|
||||
B *int `json:"b"`
|
||||
})(nil),
|
||||
},
|
||||
|
||||
{
|
||||
name: "HeadIntZeroNotRoot",
|
||||
expected: `{"A":{"a":0}}`,
|
||||
data: struct {
|
||||
A struct {
|
||||
A int `json:"a"`
|
||||
}
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "HeadIntNotRoot",
|
||||
expected: `{"A":{"a":1}}`,
|
||||
data: struct {
|
||||
A struct {
|
||||
A int `json:"a"`
|
||||
}
|
||||
}{A: struct {
|
||||
A int `json:"a"`
|
||||
}{A: 1}},
|
||||
},
|
||||
{
|
||||
name: "HeadIntPtrNotRoot",
|
||||
expected: `{"A":{"a":1}}`,
|
||||
data: struct {
|
||||
A struct {
|
||||
A *int `json:"a"`
|
||||
}
|
||||
}{A: struct {
|
||||
A *int `json:"a"`
|
||||
}{intptr(1)}},
|
||||
},
|
||||
/*
|
||||
{
|
||||
name: "HeadIntPtrNilNotRoot",
|
||||
expected: `{"A":{"a":null}}`,
|
||||
data: struct {
|
||||
A struct {
|
||||
A *int `json:"a"`
|
||||
}
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntZeroNotRoot",
|
||||
expected: `{"A":{"a":0}}`,
|
||||
data: struct {
|
||||
A *struct {
|
||||
A int `json:"a"`
|
||||
}
|
||||
}{A: new(struct {
|
||||
A int `json:"a"`
|
||||
})},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntNotRoot",
|
||||
expected: `{"A":{"a":1}}`,
|
||||
data: struct {
|
||||
A *struct {
|
||||
A int `json:"a"`
|
||||
}
|
||||
}{A: &(struct {
|
||||
A int `json:"a"`
|
||||
}{A: 1})},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntPtrNotRoot",
|
||||
expected: `{"A":{"a":1}}`,
|
||||
data: struct {
|
||||
A *struct {
|
||||
A *int `json:"a"`
|
||||
}
|
||||
}{A: &(struct {
|
||||
A *int `json:"a"`
|
||||
}{A: intptr(1)})},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntPtrNilNotRoot",
|
||||
expected: `{"A":{"a":null}}`,
|
||||
data: struct {
|
||||
A *struct {
|
||||
A *int `json:"a"`
|
||||
}
|
||||
}{A: &(struct {
|
||||
A *int `json:"a"`
|
||||
}{A: nil})},
|
||||
},
|
||||
*/
|
||||
/*
|
||||
{
|
||||
name: "PtrHeadIntNilNotRoot",
|
||||
expected: `{"A":null}`,
|
||||
data: struct {
|
||||
A *struct {
|
||||
A *int `json:"a"`
|
||||
}
|
||||
}{A: nil},
|
||||
},
|
||||
*/
|
||||
{
|
||||
name: "HeadIntZeroMultiFields",
|
||||
expected: `{"a":0,"b":0}`,
|
||||
data: struct {
|
||||
A int `json:"a"`
|
||||
B int `json:"b"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "HeadIntMultiFields",
|
||||
expected: `{"a":1,"b":2}`,
|
||||
data: struct {
|
||||
A int `json:"a"`
|
||||
B int `json:"b"`
|
||||
}{A: 1, B: 2},
|
||||
},
|
||||
{
|
||||
name: "HeadIntPtrMultiFields",
|
||||
expected: `{"a":1,"b":2}`,
|
||||
data: struct {
|
||||
A *int `json:"a"`
|
||||
B *int `json:"b"`
|
||||
}{A: intptr(1), B: intptr(2)},
|
||||
},
|
||||
{
|
||||
name: "HeadIntPtrNilMultiFieldsd",
|
||||
expected: `{"a":null,"b":null}`,
|
||||
data: struct {
|
||||
A *int `json:"a"`
|
||||
B *int `json:"b"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntZeroMultiFields",
|
||||
expected: `{"a":0,"b":0}`,
|
||||
data: &struct {
|
||||
A int `json:"a"`
|
||||
B int `json:"b"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntMultiFields",
|
||||
expected: `{"a":1,"b":2}`,
|
||||
data: &struct {
|
||||
A int `json:"a"`
|
||||
B int `json:"b"`
|
||||
}{A: 1, B: 2},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntPtrMultiFields",
|
||||
expected: `{"a":1,"b":2}`,
|
||||
data: &struct {
|
||||
A *int `json:"a"`
|
||||
B *int `json:"b"`
|
||||
}{A: intptr(1), B: intptr(2)},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntPtrNilMultiFields",
|
||||
expected: `{"a":null,"b":null}`,
|
||||
data: &struct {
|
||||
A *int `json:"a"`
|
||||
B *int `json:"b"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadIntNilMultiFields",
|
||||
expected: `null`,
|
||||
data: (*struct {
|
||||
A *int `json:"a"`
|
||||
B *int `json:"b"`
|
||||
})(nil),
|
||||
},
|
||||
|
||||
{
|
||||
name: "Int8Head",
|
||||
expected: `{"a":1}`,
|
||||
data: struct {
|
||||
A int8 `json:"a"`
|
||||
}{A: 1},
|
||||
},
|
||||
{
|
||||
name: "Int8PtrHead",
|
||||
expected: `{"a":1}`,
|
||||
data: struct {
|
||||
A *int8 `json:"a"`
|
||||
}{A: int8ptr(1)},
|
||||
},
|
||||
/*
|
||||
{
|
||||
name: "Int8PtrNilHead",
|
||||
expected: `{"a":null}`,
|
||||
data: struct {
|
||||
A *int8 `json:"a"`
|
||||
}{A: nil},
|
||||
},
|
||||
*/
|
||||
{
|
||||
name: "PtrInt8Head",
|
||||
expected: `{"a":1}`,
|
||||
data: &struct {
|
||||
A int8 `json:"a"`
|
||||
}{A: 1},
|
||||
},
|
||||
{
|
||||
name: "PtrInt8PtrHead",
|
||||
expected: `{"a":1}`,
|
||||
data: &struct {
|
||||
A *int8 `json:"a"`
|
||||
}{A: int8ptr(1)},
|
||||
},
|
||||
{
|
||||
name: "Int8Field",
|
||||
expected: `{"a":1,"b":2}`,
|
||||
data: struct {
|
||||
A int8 `json:"a"`
|
||||
B int8 `json:"b"`
|
||||
}{A: 1, B: 2},
|
||||
},
|
||||
{
|
||||
name: "Int8PtrField",
|
||||
expected: `{"a":1,"b":2}`,
|
||||
data: struct {
|
||||
A *int8 `json:"a"`
|
||||
B *int8 `json:"b"`
|
||||
}{A: int8ptr(1), B: int8ptr(2)},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
for _, htmlEscape := range []bool{true, false} {
|
||||
var buf bytes.Buffer
|
||||
enc := NewEncoder(&buf)
|
||||
enc.SetEscapeHTML(htmlEscape)
|
||||
if err := enc.Encode(test.data); err != nil {
|
||||
t.Errorf("%s(htmlEscape:%T): %s: %s", test.name, htmlEscape, test.expected, err)
|
||||
}
|
||||
if strings.TrimRight(buf.String(), "\n") != test.expected {
|
||||
t.Errorf("%s(htmlEscape:%T): expected %q but got %q", test.name, htmlEscape, test.expected, buf.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -536,7 +536,131 @@ func (e *Encoder) compileMap(ctx *encodeCompileContext, withLoad bool) (*opcode,
|
|||
return (*opcode)(unsafe.Pointer(header)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) typeToHeaderType(ctx *encodeCompileContext, code *opcode) opType {
|
||||
func (e *Encoder) typeToHeaderType(ctx *encodeCompileContext, code *opcode, isOnlyPtrField bool) opType {
|
||||
if isOnlyPtrField {
|
||||
// 1. pointer struct + primitive type field
|
||||
// 2. struct + primitive pointer type field
|
||||
switch code.op {
|
||||
case opPtr:
|
||||
ptrNum := 1
|
||||
c := code
|
||||
ctx.decIndex()
|
||||
for {
|
||||
if code.next.op == opPtr {
|
||||
ptrNum++
|
||||
code = code.next
|
||||
ctx.decIndex()
|
||||
}
|
||||
break
|
||||
}
|
||||
c.ptrNum = ptrNum
|
||||
if ptrNum > 1 {
|
||||
switch code.next.op {
|
||||
case opInt:
|
||||
return opStructFieldHeadIntNPtrOnly
|
||||
case opInt8:
|
||||
return opStructFieldHeadInt8NPtrOnly
|
||||
case opInt16:
|
||||
return opStructFieldHeadInt16NPtrOnly
|
||||
case opInt32:
|
||||
return opStructFieldHeadInt32NPtrOnly
|
||||
case opInt64:
|
||||
return opStructFieldHeadInt64NPtrOnly
|
||||
case opUint:
|
||||
return opStructFieldHeadUintNPtrOnly
|
||||
case opUint8:
|
||||
return opStructFieldHeadUint8NPtrOnly
|
||||
case opUint16:
|
||||
return opStructFieldHeadUint16NPtrOnly
|
||||
case opUint32:
|
||||
return opStructFieldHeadUint32NPtrOnly
|
||||
case opUint64:
|
||||
return opStructFieldHeadUint64NPtrOnly
|
||||
case opFloat32:
|
||||
return opStructFieldHeadFloat32NPtrOnly
|
||||
case opFloat64:
|
||||
return opStructFieldHeadFloat64NPtrOnly
|
||||
case opString:
|
||||
return opStructFieldHeadStringNPtrOnly
|
||||
case opBool:
|
||||
return opStructFieldHeadBoolNPtrOnly
|
||||
}
|
||||
} else {
|
||||
switch code.next.op {
|
||||
case opInt:
|
||||
return opStructFieldHeadIntPtrOnly
|
||||
case opInt8:
|
||||
return opStructFieldHeadInt8PtrOnly
|
||||
case opInt16:
|
||||
return opStructFieldHeadInt16PtrOnly
|
||||
case opInt32:
|
||||
return opStructFieldHeadInt32PtrOnly
|
||||
case opInt64:
|
||||
return opStructFieldHeadInt64PtrOnly
|
||||
case opUint:
|
||||
return opStructFieldHeadUintPtrOnly
|
||||
case opUint8:
|
||||
return opStructFieldHeadUint8PtrOnly
|
||||
case opUint16:
|
||||
return opStructFieldHeadUint16PtrOnly
|
||||
case opUint32:
|
||||
return opStructFieldHeadUint32PtrOnly
|
||||
case opUint64:
|
||||
return opStructFieldHeadUint64PtrOnly
|
||||
case opFloat32:
|
||||
return opStructFieldHeadFloat32PtrOnly
|
||||
case opFloat64:
|
||||
return opStructFieldHeadFloat64PtrOnly
|
||||
case opString:
|
||||
return opStructFieldHeadStringPtrOnly
|
||||
case opBool:
|
||||
return opStructFieldHeadBoolPtrOnly
|
||||
}
|
||||
}
|
||||
case opInt:
|
||||
return opStructFieldHeadIntOnly
|
||||
case opInt8:
|
||||
return opStructFieldHeadInt8Only
|
||||
case opInt16:
|
||||
return opStructFieldHeadInt16Only
|
||||
case opInt32:
|
||||
return opStructFieldHeadInt32Only
|
||||
case opInt64:
|
||||
return opStructFieldHeadInt64Only
|
||||
case opUint:
|
||||
return opStructFieldHeadUintOnly
|
||||
case opUint8:
|
||||
return opStructFieldHeadUint8Only
|
||||
case opUint16:
|
||||
return opStructFieldHeadUint16Only
|
||||
case opUint32:
|
||||
return opStructFieldHeadUint32Only
|
||||
case opUint64:
|
||||
return opStructFieldHeadUint64Only
|
||||
case opFloat32:
|
||||
return opStructFieldHeadFloat32Only
|
||||
case opFloat64:
|
||||
return opStructFieldHeadFloat64Only
|
||||
case opString:
|
||||
return opStructFieldHeadStringOnly
|
||||
case opBool:
|
||||
return opStructFieldHeadBoolOnly
|
||||
case opMapHead:
|
||||
return opStructFieldHeadMap
|
||||
case opMapHeadLoad:
|
||||
return opStructFieldHeadMapLoad
|
||||
case opArrayHead:
|
||||
return opStructFieldHeadArray
|
||||
case opSliceHead:
|
||||
return opStructFieldHeadSlice
|
||||
case opStructFieldHead:
|
||||
return opStructFieldHeadStruct
|
||||
case opMarshalJSON:
|
||||
return opStructFieldHeadMarshalJSON
|
||||
case opMarshalText:
|
||||
return opStructFieldHeadMarshalText
|
||||
}
|
||||
} else {
|
||||
switch code.op {
|
||||
case opPtr:
|
||||
ptrNum := 1
|
||||
|
@ -657,6 +781,7 @@ func (e *Encoder) typeToHeaderType(ctx *encodeCompileContext, code *opcode) opTy
|
|||
case opMarshalText:
|
||||
return opStructFieldHeadMarshalText
|
||||
}
|
||||
}
|
||||
return opStructFieldHead
|
||||
}
|
||||
|
||||
|
@ -784,8 +909,8 @@ func (e *Encoder) typeToFieldType(ctx *encodeCompileContext, code *opcode) opTyp
|
|||
return opStructField
|
||||
}
|
||||
|
||||
func (e *Encoder) optimizeStructHeader(ctx *encodeCompileContext, code *opcode, tag *structTag) opType {
|
||||
headType := e.typeToHeaderType(ctx, code)
|
||||
func (e *Encoder) optimizeStructHeader(ctx *encodeCompileContext, code *opcode, tag *structTag, isOnlyPtrField bool) opType {
|
||||
headType := e.typeToHeaderType(ctx, code, isOnlyPtrField)
|
||||
switch {
|
||||
case tag.isOmitEmpty:
|
||||
headType = headType.headToOmitEmptyHead()
|
||||
|
@ -821,9 +946,9 @@ func (e *Encoder) compiledCode(ctx *encodeCompileContext) *opcode {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) structHeader(ctx *encodeCompileContext, fieldCode *opcode, valueCode *opcode, tag *structTag) *opcode {
|
||||
func (e *Encoder) structHeader(ctx *encodeCompileContext, fieldCode *opcode, valueCode *opcode, tag *structTag, isOnlyPtrField bool) *opcode {
|
||||
fieldCode.indent--
|
||||
op := e.optimizeStructHeader(ctx, valueCode, tag)
|
||||
op := e.optimizeStructHeader(ctx, valueCode, tag, isOnlyPtrField)
|
||||
fieldCode.op = op
|
||||
fieldCode.ptrNum = valueCode.ptrNum
|
||||
switch op {
|
||||
|
@ -1102,17 +1227,11 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
|
|||
anonymousFields[k] = append(anonymousFields[k], v...)
|
||||
}
|
||||
}
|
||||
if fieldNum == 1 && valueCode.op == opPtr {
|
||||
|
||||
// if field number is one and primitive pointer type,
|
||||
// it should encode as **not** pointer .
|
||||
switch valueCode.next.op {
|
||||
case opInt, opInt8, opInt16, opInt32, opInt64,
|
||||
opUint, opUint8, opUint16, opUint32, opUint64,
|
||||
opFloat32, opFloat64, opBool, opString, opBytes:
|
||||
valueCode = valueCode.next
|
||||
ctx.decOpcodeIndex()
|
||||
}
|
||||
}
|
||||
// it should encode as special opcode.
|
||||
isOnlyPtrField := fieldNum == 1 && (valueCode.op == opPtr && !isPtr || valueCode.op != opPtr && isPtr)
|
||||
|
||||
key := fmt.Sprintf(`"%s":`, tag.key)
|
||||
escapedKey := fmt.Sprintf(`%s:`, string(encodeEscapedString([]byte{}, tag.key)))
|
||||
fieldCode := &opcode{
|
||||
|
@ -1130,7 +1249,7 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
|
|||
}
|
||||
if fieldIdx == 0 {
|
||||
fieldCode.headIdx = fieldCode.idx
|
||||
code = e.structHeader(ctx, fieldCode, valueCode, tag)
|
||||
code = e.structHeader(ctx, fieldCode, valueCode, tag, isOnlyPtrField)
|
||||
head = fieldCode
|
||||
prevField = fieldCode
|
||||
} else {
|
||||
|
|
33716
encode_optype.go
33716
encode_optype.go
File diff suppressed because it is too large
Load Diff
338
encode_vm.go
338
encode_vm.go
|
@ -1236,6 +1236,22 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
code = code.next
|
||||
store(ctxptr, code.idx, ptr)
|
||||
}
|
||||
case opStructFieldPtrHeadIntOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
case opStructFieldHeadIntOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.key...)
|
||||
b = appendInt(b, int64(e.ptrToInt(p)))
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructFieldPtrHeadInt:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
|
@ -1247,22 +1263,28 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
store(ctxptr, code.idx, e.ptrToPtr(p))
|
||||
fallthrough
|
||||
case opStructFieldHeadInt:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr == 0 {
|
||||
if code.op == opStructFieldPtrHeadInt {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
} else {
|
||||
b = append(b, '{', '}', ',')
|
||||
}
|
||||
code = code.end.next
|
||||
} else {
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.key...)
|
||||
b = appendInt(b, int64(e.ptrToInt(ptr+code.offset)))
|
||||
b = appendInt(b, int64(e.ptrToInt(p+code.offset)))
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructEscapedFieldPtrHeadIntOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
case opStructEscapedFieldHeadIntOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.escapedKey...)
|
||||
b = appendInt(b, int64(e.ptrToInt(p)))
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructEscapedFieldPtrHeadInt:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
|
@ -1274,27 +1296,51 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
store(ctxptr, code.idx, e.ptrToPtr(p))
|
||||
fallthrough
|
||||
case opStructEscapedFieldHeadInt:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr == 0 {
|
||||
if code.op == opStructEscapedFieldPtrHeadInt {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
} else {
|
||||
b = append(b, '{', '}', ',')
|
||||
}
|
||||
code = code.end.next
|
||||
} else {
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.escapedKey...)
|
||||
b = appendInt(b, int64(e.ptrToInt(ptr+code.offset)))
|
||||
b = appendInt(b, int64(e.ptrToInt(p+code.offset)))
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructFieldPtrHeadIntPtrOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
store(ctxptr, code.idx, e.ptrToPtr(p))
|
||||
fallthrough
|
||||
case opStructFieldHeadIntPtrOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.key...)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
} else {
|
||||
b = appendInt(b, int64(e.ptrToInt(p+code.offset)))
|
||||
}
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructFieldPtrHeadIntPtr:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
store(ctxptr, code.idx, e.ptrToPtr(p))
|
||||
fallthrough
|
||||
case opStructFieldHeadIntPtr:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
} else {
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
b = append(b, '{')
|
||||
b = append(b, code.key...)
|
||||
p = e.ptrToPtr(p)
|
||||
|
@ -1303,14 +1349,47 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
} else {
|
||||
b = appendInt(b, int64(e.ptrToInt(p+code.offset)))
|
||||
}
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructEscapedFieldPtrHeadIntPtrOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
store(ctxptr, code.idx, e.ptrToPtr(p))
|
||||
fallthrough
|
||||
case opStructEscapedFieldHeadIntPtrOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.escapedKey...)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
} else {
|
||||
b = appendInt(b, int64(e.ptrToInt(p+code.offset)))
|
||||
}
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructEscapedFieldPtrHeadIntPtr:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
store(ctxptr, code.idx, e.ptrToPtr(p))
|
||||
fallthrough
|
||||
case opStructEscapedFieldHeadIntPtr:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
} else {
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
b = append(b, '{')
|
||||
b = append(b, code.escapedKey...)
|
||||
p = e.ptrToPtr(p)
|
||||
|
@ -1319,13 +1398,13 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
} else {
|
||||
b = appendInt(b, int64(e.ptrToInt(p+code.offset)))
|
||||
}
|
||||
}
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructFieldHeadIntNPtr:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
code = code.end.next
|
||||
} else {
|
||||
b = append(b, '{')
|
||||
b = append(b, code.key...)
|
||||
|
@ -1390,6 +1469,22 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
b = encodeComma(b)
|
||||
code = code.next
|
||||
}
|
||||
case opStructFieldPtrHeadInt8Only:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
case opStructFieldHeadInt8Only:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.key...)
|
||||
b = appendInt(b, int64(e.ptrToInt8(p)))
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructFieldPtrHeadInt8:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
|
@ -1417,6 +1512,22 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
b = encodeComma(b)
|
||||
code = code.next
|
||||
}
|
||||
case opStructEscapedFieldPtrHeadInt8Only:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
case opStructEscapedFieldHeadInt8Only:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.escapedKey...)
|
||||
b = appendInt(b, int64(e.ptrToInt8(p)))
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructEscapedFieldPtrHeadInt8:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
|
@ -1444,6 +1555,102 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
b = encodeComma(b)
|
||||
code = code.next
|
||||
}
|
||||
case opStructFieldPtrHeadInt8PtrOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
store(ctxptr, code.idx, e.ptrToPtr(p))
|
||||
fallthrough
|
||||
case opStructFieldHeadInt8PtrOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.key...)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
} else {
|
||||
b = appendInt(b, int64(e.ptrToInt8(p)))
|
||||
}
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructFieldPtrHeadInt8Ptr:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
store(ctxptr, code.idx, e.ptrToPtr(p))
|
||||
fallthrough
|
||||
case opStructFieldHeadInt8Ptr:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
code = code.end.next
|
||||
} else {
|
||||
b = append(b, '{')
|
||||
b = append(b, code.key...)
|
||||
p = e.ptrToPtr(p)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
} else {
|
||||
b = appendInt(b, int64(e.ptrToInt8(p+code.offset)))
|
||||
}
|
||||
code = code.next
|
||||
}
|
||||
b = encodeComma(b)
|
||||
case opStructEscapedFieldPtrHeadInt8PtrOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
store(ctxptr, code.idx, e.ptrToPtr(p))
|
||||
fallthrough
|
||||
case opStructEscapedFieldHeadInt8PtrOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.escapedKey...)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
} else {
|
||||
b = appendInt(b, int64(e.ptrToInt8(p)))
|
||||
}
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructEscapedFieldPtrHeadInt8Ptr:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
store(ctxptr, code.idx, e.ptrToPtr(p))
|
||||
fallthrough
|
||||
case opStructEscapedFieldHeadInt8Ptr:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
code = code.end.next
|
||||
} else {
|
||||
b = append(b, '{')
|
||||
b = append(b, code.escapedKey...)
|
||||
p = e.ptrToPtr(p)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
} else {
|
||||
b = appendInt(b, int64(e.ptrToInt8(p+code.offset)))
|
||||
}
|
||||
code = code.next
|
||||
}
|
||||
b = encodeComma(b)
|
||||
case opStructFieldPtrAnonymousHeadInt8:
|
||||
store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx)))
|
||||
fallthrough
|
||||
|
@ -2313,6 +2520,22 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
b = encodeComma(b)
|
||||
code = code.next
|
||||
}
|
||||
case opStructEscapedFieldPtrHeadEscapedStringOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
case opStructEscapedFieldHeadEscapedStringOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.escapedKey...)
|
||||
b = encodeEscapedString(b, e.ptrToString(p))
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructEscapedFieldPtrHeadEscapedString:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
|
@ -2393,6 +2616,22 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
b = encodeComma(b)
|
||||
code = code.next
|
||||
}
|
||||
case opStructEscapedFieldPtrHeadBoolOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
case opStructEscapedFieldHeadBoolOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.escapedKey...)
|
||||
b = encodeBool(b, e.ptrToBool(p))
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructEscapedFieldPtrHeadBool:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
|
@ -3750,6 +3989,24 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
code = code.next
|
||||
}
|
||||
}
|
||||
case opStructEscapedFieldPtrHeadOmitEmptyIntOnly:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr != 0 {
|
||||
store(ctxptr, code.idx, e.ptrToPtr(ptr))
|
||||
}
|
||||
fallthrough
|
||||
case opStructEscapedFieldHeadOmitEmptyIntOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
v := e.ptrToInt(p)
|
||||
if v == 0 {
|
||||
code = code.nextField
|
||||
} else {
|
||||
b = append(b, code.escapedKey...)
|
||||
b = appendInt(b, int64(v))
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
}
|
||||
case opStructEscapedFieldPtrHeadOmitEmptyInt:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr != 0 {
|
||||
|
@ -6705,6 +6962,22 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
b = encodeComma(b)
|
||||
code = code.next
|
||||
}
|
||||
|
||||
case opStructEscapedFieldPtrHeadStringTagInt64PtrOnly:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr != 0 {
|
||||
store(ctxptr, code.idx, e.ptrToPtr(ptr))
|
||||
}
|
||||
fallthrough
|
||||
case opStructEscapedFieldHeadStringTagInt64PtrOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.escapedKey...)
|
||||
b = append(b, '"')
|
||||
b = appendInt(b, e.ptrToInt64(p))
|
||||
b = append(b, '"')
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructEscapedFieldPtrHeadStringTagInt64:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr != 0 {
|
||||
|
@ -7419,6 +7692,21 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
|
|||
b = encodeComma(b)
|
||||
code = code.next
|
||||
}
|
||||
case opStructEscapedFieldPtrHeadStringTagBoolOnly:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr != 0 {
|
||||
store(ctxptr, code.idx, e.ptrToPtr(ptr))
|
||||
}
|
||||
fallthrough
|
||||
case opStructEscapedFieldHeadStringTagBoolOnly:
|
||||
p := load(ctxptr, code.idx)
|
||||
b = append(b, '{')
|
||||
b = append(b, code.escapedKey...)
|
||||
b = append(b, '"')
|
||||
b = encodeBool(b, e.ptrToBool(p))
|
||||
b = append(b, '"')
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
case opStructEscapedFieldPtrHeadStringTagBool:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr != 0 {
|
||||
|
|
Loading…
Reference in New Issue