Compare commits

...

3 Commits

Author SHA1 Message Date
Masaaki Goshima 8411c9142c Add only type 2021-01-01 17:20:39 +09:00
Masaaki Goshima 058b3ae1ea Add Only type 2021-01-01 17:20:00 +09:00
Masaaki Goshima ddcf571e68 Add test case 2020-12-31 19:17:37 +09:00
5 changed files with 33196 additions and 6805 deletions

View File

@ -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, "") {

417
coverage_test.go Normal file
View File

@ -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())
}
}
}
}

View File

@ -536,126 +536,251 @@ func (e *Encoder) compileMap(ctx *encodeCompileContext, withLoad bool) (*opcode,
return (*opcode)(unsafe.Pointer(header)), nil
}
func (e *Encoder) typeToHeaderType(ctx *encodeCompileContext, code *opcode) opType {
switch code.op {
case opPtr:
ptrNum := 1
c := code
ctx.decIndex()
for {
if code.next.op == opPtr {
ptrNum++
code = code.next
ctx.decIndex()
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
}
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
}
c.ptrNum = ptrNum
if ptrNum > 1 {
switch code.next.op {
case opInt:
return opStructFieldHeadIntNPtr
case opInt8:
return opStructFieldHeadInt8NPtr
case opInt16:
return opStructFieldHeadInt16NPtr
case opInt32:
return opStructFieldHeadInt32NPtr
case opInt64:
return opStructFieldHeadInt64NPtr
case opUint:
return opStructFieldHeadUintNPtr
case opUint8:
return opStructFieldHeadUint8NPtr
case opUint16:
return opStructFieldHeadUint16NPtr
case opUint32:
return opStructFieldHeadUint32NPtr
case opUint64:
return opStructFieldHeadUint64NPtr
case opFloat32:
return opStructFieldHeadFloat32NPtr
case opFloat64:
return opStructFieldHeadFloat64NPtr
case opString:
return opStructFieldHeadStringNPtr
case opBool:
return opStructFieldHeadBoolNPtr
} else {
switch code.op {
case opPtr:
ptrNum := 1
c := code
ctx.decIndex()
for {
if code.next.op == opPtr {
ptrNum++
code = code.next
ctx.decIndex()
}
break
}
} else {
switch code.next.op {
case opInt:
return opStructFieldHeadIntPtr
case opInt8:
return opStructFieldHeadInt8Ptr
case opInt16:
return opStructFieldHeadInt16Ptr
case opInt32:
return opStructFieldHeadInt32Ptr
case opInt64:
return opStructFieldHeadInt64Ptr
case opUint:
return opStructFieldHeadUintPtr
case opUint8:
return opStructFieldHeadUint8Ptr
case opUint16:
return opStructFieldHeadUint16Ptr
case opUint32:
return opStructFieldHeadUint32Ptr
case opUint64:
return opStructFieldHeadUint64Ptr
case opFloat32:
return opStructFieldHeadFloat32Ptr
case opFloat64:
return opStructFieldHeadFloat64Ptr
case opString:
return opStructFieldHeadStringPtr
case opBool:
return opStructFieldHeadBoolPtr
c.ptrNum = ptrNum
if ptrNum > 1 {
switch code.next.op {
case opInt:
return opStructFieldHeadIntNPtr
case opInt8:
return opStructFieldHeadInt8NPtr
case opInt16:
return opStructFieldHeadInt16NPtr
case opInt32:
return opStructFieldHeadInt32NPtr
case opInt64:
return opStructFieldHeadInt64NPtr
case opUint:
return opStructFieldHeadUintNPtr
case opUint8:
return opStructFieldHeadUint8NPtr
case opUint16:
return opStructFieldHeadUint16NPtr
case opUint32:
return opStructFieldHeadUint32NPtr
case opUint64:
return opStructFieldHeadUint64NPtr
case opFloat32:
return opStructFieldHeadFloat32NPtr
case opFloat64:
return opStructFieldHeadFloat64NPtr
case opString:
return opStructFieldHeadStringNPtr
case opBool:
return opStructFieldHeadBoolNPtr
}
} else {
switch code.next.op {
case opInt:
return opStructFieldHeadIntPtr
case opInt8:
return opStructFieldHeadInt8Ptr
case opInt16:
return opStructFieldHeadInt16Ptr
case opInt32:
return opStructFieldHeadInt32Ptr
case opInt64:
return opStructFieldHeadInt64Ptr
case opUint:
return opStructFieldHeadUintPtr
case opUint8:
return opStructFieldHeadUint8Ptr
case opUint16:
return opStructFieldHeadUint16Ptr
case opUint32:
return opStructFieldHeadUint32Ptr
case opUint64:
return opStructFieldHeadUint64Ptr
case opFloat32:
return opStructFieldHeadFloat32Ptr
case opFloat64:
return opStructFieldHeadFloat64Ptr
case opString:
return opStructFieldHeadStringPtr
case opBool:
return opStructFieldHeadBoolPtr
}
}
case opInt:
return opStructFieldHeadInt
case opInt8:
return opStructFieldHeadInt8
case opInt16:
return opStructFieldHeadInt16
case opInt32:
return opStructFieldHeadInt32
case opInt64:
return opStructFieldHeadInt64
case opUint:
return opStructFieldHeadUint
case opUint8:
return opStructFieldHeadUint8
case opUint16:
return opStructFieldHeadUint16
case opUint32:
return opStructFieldHeadUint32
case opUint64:
return opStructFieldHeadUint64
case opFloat32:
return opStructFieldHeadFloat32
case opFloat64:
return opStructFieldHeadFloat64
case opString:
return opStructFieldHeadString
case opBool:
return opStructFieldHeadBool
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
}
case opInt:
return opStructFieldHeadInt
case opInt8:
return opStructFieldHeadInt8
case opInt16:
return opStructFieldHeadInt16
case opInt32:
return opStructFieldHeadInt32
case opInt64:
return opStructFieldHeadInt64
case opUint:
return opStructFieldHeadUint
case opUint8:
return opStructFieldHeadUint8
case opUint16:
return opStructFieldHeadUint16
case opUint32:
return opStructFieldHeadUint32
case opUint64:
return opStructFieldHeadUint64
case opFloat32:
return opStructFieldHeadFloat32
case opFloat64:
return opStructFieldHeadFloat64
case opString:
return opStructFieldHeadString
case opBool:
return opStructFieldHeadBool
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
}
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()
}
}
// if field number is one and primitive pointer type,
// 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 {

File diff suppressed because it is too large Load Diff

View File

@ -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 {
b = append(b, '{')
b = append(b, code.key...)
b = appendInt(b, int64(e.ptrToInt(ptr+code.offset)))
p := load(ctxptr, code.idx)
b = append(b, '{')
b = append(b, code.key...)
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.next
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,51 +1296,107 @@ 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 {
b = append(b, '{')
b = append(b, code.escapedKey...)
b = appendInt(b, int64(e.ptrToInt(ptr+code.offset)))
p := load(ctxptr, code.idx)
b = append(b, '{')
b = append(b, code.escapedKey...)
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.next
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)
b = encodeComma(b)
code = code.end.next
break
}
b = append(b, '{')
b = append(b, code.key...)
p = e.ptrToPtr(p)
if p == 0 {
b = encodeNull(b)
} 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.ptrToInt(p+code.offset)))
}
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)
b = encodeComma(b)
code = code.end.next
break
}
b = append(b, '{')
b = append(b, code.escapedKey...)
p = e.ptrToPtr(p)
if p == 0 {
b = encodeNull(b)
} 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.ptrToInt(p+code.offset)))
}
b = appendInt(b, int64(e.ptrToInt(p+code.offset)))
}
b = encodeComma(b)
code = code.next
@ -1326,6 +1404,7 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
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 {