forked from mirror/go-json
Merge pull request #81 from goccy/feature/coverage
Add many test codes and distribute `case` operation ( of `switch` ) to some switch statements
This commit is contained in:
commit
af9168203a
|
@ -5,7 +5,7 @@ jobs:
|
|||
name: Test
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ "ubuntu-latest", "windows-latest", "macos-latest" ]
|
||||
os: [ "ubuntu-latest", "macos-latest", "windows-latest" ]
|
||||
go-version: [ "1.13", "1.14", "1.15" ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
|
|
@ -14,23 +14,18 @@ import (
|
|||
type opType struct {
|
||||
Op string
|
||||
Code string
|
||||
Indent func() string
|
||||
Escaped func() string
|
||||
HeadToPtrHead func() string
|
||||
HeadToNPtrHead func() string
|
||||
HeadToAnonymousHead func() string
|
||||
HeadToOmitEmptyHead func() string
|
||||
HeadToStringTagHead func() string
|
||||
HeadToOnlyHead func() string
|
||||
PtrHeadToHead func() string
|
||||
FieldToEnd func() string
|
||||
FieldToOmitEmptyField func() string
|
||||
FieldToStringTagField func() string
|
||||
}
|
||||
|
||||
func (t opType) IsEscaped() bool {
|
||||
return t.Op != t.Escaped()
|
||||
}
|
||||
|
||||
func (t opType) IsHeadToPtrHead() bool {
|
||||
return t.Op != t.HeadToPtrHead()
|
||||
}
|
||||
|
@ -55,6 +50,10 @@ func (t opType) IsPtrHeadToHead() bool {
|
|||
return t.Op != t.PtrHeadToHead()
|
||||
}
|
||||
|
||||
func (t opType) IsHeadToOnlyHead() bool {
|
||||
return t.Op != t.HeadToOnlyHead()
|
||||
}
|
||||
|
||||
func (t opType) IsFieldToEnd() bool {
|
||||
return t.Op != t.FieldToEnd()
|
||||
}
|
||||
|
@ -71,13 +70,12 @@ func createOpType(op, code string) opType {
|
|||
return opType{
|
||||
Op: op,
|
||||
Code: code,
|
||||
Indent: func() string { return fmt.Sprintf("%sIndent", op) },
|
||||
Escaped: func() string { return op },
|
||||
HeadToPtrHead: func() string { return op },
|
||||
HeadToNPtrHead: func() string { return op },
|
||||
HeadToAnonymousHead: func() string { return op },
|
||||
HeadToOmitEmptyHead: func() string { return op },
|
||||
HeadToStringTagHead: func() string { return op },
|
||||
HeadToOnlyHead: func() string { return op },
|
||||
PtrHeadToHead: func() string { return op },
|
||||
FieldToEnd: func() string { return op },
|
||||
FieldToOmitEmptyField: func() string { return op },
|
||||
|
@ -89,6 +87,10 @@ func _main() error {
|
|||
tmpl, err := template.New("").Parse(`// Code generated by cmd/generator. DO NOT EDIT!
|
||||
package json
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type codeType int
|
||||
|
||||
const (
|
||||
|
@ -106,12 +108,8 @@ const (
|
|||
)
|
||||
|
||||
func (t opType) String() string {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return t.toNotIndent().String() + "Indent"
|
||||
}
|
||||
|
||||
switch t {
|
||||
{{- range $type := .OpNotIndentTypes }}
|
||||
{{- range $type := .OpTypes }}
|
||||
case op{{ $type.Op }}:
|
||||
return "{{ $type.Op }}"
|
||||
{{- end }}
|
||||
|
@ -120,152 +118,136 @@ func (t opType) String() string {
|
|||
}
|
||||
|
||||
func (t opType) codeType() codeType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return t.toNotIndent().codeType()
|
||||
if strings.Contains(t.String(), "Struct") {
|
||||
if strings.Contains(t.String(), "End") {
|
||||
return codeStructEnd
|
||||
}
|
||||
return codeStructField
|
||||
}
|
||||
if strings.Contains(t.String(), "ArrayHead") {
|
||||
return codeArrayHead
|
||||
}
|
||||
if strings.Contains(t.String(), "ArrayElem") {
|
||||
return codeArrayElem
|
||||
}
|
||||
if strings.Contains(t.String(), "SliceHead") {
|
||||
return codeSliceHead
|
||||
}
|
||||
if strings.Contains(t.String(), "SliceElem") {
|
||||
return codeSliceElem
|
||||
}
|
||||
if strings.Contains(t.String(), "MapHead") {
|
||||
return codeMapHead
|
||||
}
|
||||
if strings.Contains(t.String(), "MapKey") {
|
||||
return codeMapKey
|
||||
}
|
||||
if strings.Contains(t.String(), "MapValue") {
|
||||
return codeMapValue
|
||||
}
|
||||
if strings.Contains(t.String(), "MapEnd") {
|
||||
return codeMapEnd
|
||||
}
|
||||
|
||||
switch t {
|
||||
{{- range $type := .OpNotIndentTypes }}
|
||||
case op{{ $type.Op }}:
|
||||
return code{{ $type.Code }}
|
||||
{{- end }}
|
||||
}
|
||||
return codeOp
|
||||
}
|
||||
|
||||
func (t opType) toNotIndent() opType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return opType(int(t) - {{ .OpLen }})
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t opType) toIndent() opType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
func (t opType) headToPtrHead() opType {
|
||||
if strings.Index(t.String(), "PtrHead") > 0 {
|
||||
return t
|
||||
}
|
||||
return opType(int(t) + {{ .OpLen }})
|
||||
}
|
||||
|
||||
func (t opType) toEscaped() opType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return opType(int(t.toNotIndent().toEscaped()) + {{ .OpLen }})
|
||||
if strings.Index(t.String(), "PtrAnonymousHead") > 0 {
|
||||
return t
|
||||
}
|
||||
|
||||
switch t {
|
||||
{{- range $type := .OpNotIndentTypes }}
|
||||
{{- if $type.IsEscaped }}
|
||||
case op{{ $type.Op }}:
|
||||
return op{{ call $type.Escaped }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
idx := strings.Index(t.String(), "Field")
|
||||
if idx == -1 {
|
||||
return t
|
||||
}
|
||||
return t
|
||||
}
|
||||
suffix := "Ptr"+t.String()[idx+len("Field"):]
|
||||
|
||||
func (t opType) headToPtrHead() opType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return opType(int(t.toNotIndent().headToPtrHead()) + {{ .OpLen }})
|
||||
}
|
||||
|
||||
switch t {
|
||||
{{- range $type := .OpNotIndentTypes }}
|
||||
{{- if $type.IsHeadToPtrHead }}
|
||||
case op{{ $type.Op }}:
|
||||
return op{{ call $type.HeadToPtrHead }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
const toPtrOffset = 12
|
||||
if strings.Contains(opType(int(t) + toPtrOffset).String(), suffix) {
|
||||
return opType(int(t) + toPtrOffset)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t opType) headToNPtrHead() opType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return opType(int(t.toNotIndent().headToNPtrHead()) + {{ .OpLen }})
|
||||
if strings.Index(t.String(), "PtrHead") > 0 {
|
||||
return t
|
||||
}
|
||||
if strings.Index(t.String(), "PtrAnonymousHead") > 0 {
|
||||
return t
|
||||
}
|
||||
|
||||
switch t {
|
||||
{{- range $type := .OpNotIndentTypes }}
|
||||
{{- if $type.IsHeadToNPtrHead }}
|
||||
case op{{ $type.Op }}:
|
||||
return op{{ call $type.HeadToNPtrHead }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
idx := strings.Index(t.String(), "Field")
|
||||
if idx == -1 {
|
||||
return t
|
||||
}
|
||||
suffix := "NPtr"+t.String()[idx+len("Field"):]
|
||||
|
||||
const toPtrOffset = 24
|
||||
if strings.Contains(opType(int(t) + toPtrOffset).String(), suffix) {
|
||||
return opType(int(t) + toPtrOffset)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t opType) headToAnonymousHead() opType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return opType(int(t.toNotIndent().headToAnonymousHead()) + {{ .OpLen }})
|
||||
}
|
||||
|
||||
switch t {
|
||||
{{- range $type := .OpNotIndentTypes }}
|
||||
{{- if $type.IsHeadToAnonymousHead }}
|
||||
case op{{ $type.Op }}:
|
||||
return op{{ call $type.HeadToAnonymousHead }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
const toAnonymousOffset = 6
|
||||
if strings.Contains(opType(int(t) + toAnonymousOffset).String(), "Anonymous") {
|
||||
return opType(int(t) + toAnonymousOffset)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t opType) headToOmitEmptyHead() opType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return opType(int(t.toNotIndent().headToOmitEmptyHead()) + {{ .OpLen }})
|
||||
const toOmitEmptyOffset = 2
|
||||
if strings.Contains(opType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") {
|
||||
return opType(int(t) + toOmitEmptyOffset)
|
||||
}
|
||||
|
||||
switch t {
|
||||
{{- range $type := .OpNotIndentTypes }}
|
||||
{{- if $type.IsHeadToOmitEmptyHead }}
|
||||
case op{{ $type.Op }}:
|
||||
return op{{ call $type.HeadToOmitEmptyHead }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t opType) headToStringTagHead() opType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return opType(int(t.toNotIndent().headToStringTagHead()) + {{ .OpLen }})
|
||||
const toStringTagOffset = 4
|
||||
if strings.Contains(opType(int(t) + toStringTagOffset).String(), "StringTag") {
|
||||
return opType(int(t) + toStringTagOffset)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t opType) headToOnlyHead() opType {
|
||||
if strings.HasSuffix(t.String(), "Head") || strings.HasSuffix(t.String(), "HeadOmitEmpty") || strings.HasSuffix(t.String(), "HeadStringTag") {
|
||||
return t
|
||||
}
|
||||
|
||||
switch t {
|
||||
{{- range $type := .OpNotIndentTypes }}
|
||||
{{- if $type.IsHeadToStringTagHead }}
|
||||
case op{{ $type.Op }}:
|
||||
return op{{ call $type.HeadToStringTagHead }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
const toOnlyOffset = 1
|
||||
if opType(int(t) + toOnlyOffset).String() == t.String() + "Only" {
|
||||
return opType(int(t) + toOnlyOffset)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t opType) ptrHeadToHead() opType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return opType(int(t.toNotIndent().ptrHeadToHead()) + {{ .OpLen }})
|
||||
idx := strings.Index(t.String(), "Ptr")
|
||||
if idx == -1 {
|
||||
return t
|
||||
}
|
||||
suffix := t.String()[idx+len("Ptr"):]
|
||||
|
||||
switch t {
|
||||
{{- range $type := .OpNotIndentTypes }}
|
||||
{{- if $type.IsPtrHeadToHead }}
|
||||
case op{{ $type.Op }}:
|
||||
return op{{ call $type.PtrHeadToHead }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
const toPtrOffset = 12
|
||||
if strings.Contains(opType(int(t) - toPtrOffset).String(), suffix) {
|
||||
return opType(int(t) - toPtrOffset)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t opType) fieldToEnd() opType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return opType(int(t.toNotIndent().fieldToEnd()) + {{ .OpLen }})
|
||||
}
|
||||
|
||||
switch t {
|
||||
{{- range $type := .OpNotIndentTypes }}
|
||||
{{- range $type := .OpTypes }}
|
||||
{{- if $type.IsFieldToEnd }}
|
||||
case op{{ $type.Op }}:
|
||||
return op{{ call $type.FieldToEnd }}
|
||||
|
@ -276,33 +258,17 @@ func (t opType) fieldToEnd() opType {
|
|||
}
|
||||
|
||||
func (t opType) fieldToOmitEmptyField() opType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return opType(int(t.toNotIndent().fieldToOmitEmptyField()) + {{ .OpLen }})
|
||||
}
|
||||
|
||||
switch t {
|
||||
{{- range $type := .OpNotIndentTypes }}
|
||||
{{- if $type.IsFieldToOmitEmptyField }}
|
||||
case op{{ $type.Op }}:
|
||||
return op{{ call $type.FieldToOmitEmptyField }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
const toOmitEmptyOffset = 1
|
||||
if strings.Contains(opType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") {
|
||||
return opType(int(t) + toOmitEmptyOffset)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t opType) fieldToStringTagField() opType {
|
||||
if int(t) >= {{ .OpLen }} {
|
||||
return opType(int(t.toNotIndent().fieldToStringTagField()) + {{ .OpLen }})
|
||||
}
|
||||
|
||||
switch t {
|
||||
{{- range $type := .OpNotIndentTypes }}
|
||||
{{- if $type.IsFieldToStringTagField }}
|
||||
case op{{ $type.Op }}:
|
||||
return op{{ call $type.FieldToStringTagField }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
const toStringTagOffset = 2
|
||||
if strings.Contains(opType(int(t) + toStringTagOffset).String(), "StringTag") {
|
||||
return opType(int(t) + toStringTagOffset)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
@ -328,16 +294,16 @@ func (t opType) fieldToStringTagField() opType {
|
|||
primitiveTypes := []string{
|
||||
"int", "int8", "int16", "int32", "int64",
|
||||
"uint", "uint8", "uint16", "uint32", "uint64",
|
||||
"float32", "float64", "bool", "string", "escapedString", "bytes",
|
||||
"float32", "float64", "bool", "string", "bytes",
|
||||
"array", "map", "mapLoad", "slice", "struct", "MarshalJSON", "MarshalText", "recursive",
|
||||
"intString", "int8String", "int16String", "int32String", "int64String",
|
||||
"uintString", "uint8String", "uint16String", "uint32String", "uint64String",
|
||||
"intPtr", "int8Ptr", "int16Ptr", "int32Ptr", "int64Ptr",
|
||||
"uintPtr", "uint8Ptr", "uint16Ptr", "uint32Ptr", "uint64Ptr",
|
||||
"float32Ptr", "float64Ptr", "boolPtr", "stringPtr", "escapedStringPtr", "bytesPtr",
|
||||
"float32Ptr", "float64Ptr", "boolPtr", "stringPtr", "bytesPtr",
|
||||
"intNPtr", "int8NPtr", "int16NPtr", "int32NPtr", "int64NPtr",
|
||||
"uintNPtr", "uint8NPtr", "uint16NPtr", "uint32NPtr", "uint64NPtr",
|
||||
"float32NPtr", "float64NPtr", "boolNPtr", "stringNPtr", "escapedStringNPtr", "bytesNPtr",
|
||||
"float32NPtr", "float64NPtr", "boolNPtr", "stringNPtr", "bytesNPtr",
|
||||
}
|
||||
primitiveTypesUpper := []string{}
|
||||
for _, typ := range primitiveTypes {
|
||||
|
@ -367,109 +333,98 @@ func (t opType) fieldToStringTagField() opType {
|
|||
}
|
||||
for _, typ := range primitiveTypesUpper {
|
||||
typ := typ
|
||||
optype := createOpType(typ, "Op")
|
||||
switch typ {
|
||||
case "String", "StringPtr", "StringNPtr":
|
||||
optype.Escaped = func() string {
|
||||
return fmt.Sprintf("Escaped%s", typ)
|
||||
}
|
||||
}
|
||||
opTypes = append(opTypes, optype)
|
||||
opTypes = append(opTypes, createOpType(typ, "Op"))
|
||||
}
|
||||
for _, escapedOrNot := range []string{"", "Escaped"} {
|
||||
for _, typ := range append(primitiveTypesUpper, "") {
|
||||
for _, ptrOrNot := range []string{"", "Ptr", "NPtr"} {
|
||||
for _, headType := range []string{"", "Anonymous"} {
|
||||
for _, opt := range []string{"", "OmitEmpty", "StringTag"} {
|
||||
for _, typ := range append(primitiveTypesUpper, "") {
|
||||
escapedOrNot := escapedOrNot
|
||||
for _, onlyOrNot := range []string{"", "Only"} {
|
||||
ptrOrNot := ptrOrNot
|
||||
headType := headType
|
||||
opt := opt
|
||||
typ := typ
|
||||
onlyOrNot := onlyOrNot
|
||||
|
||||
op := fmt.Sprintf(
|
||||
"Struct%sField%s%sHead%s%s",
|
||||
escapedOrNot,
|
||||
"StructField%s%sHead%s%s%s",
|
||||
ptrOrNot,
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
onlyOrNot,
|
||||
)
|
||||
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%s",
|
||||
ptrOrNot,
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"StructEscapedField%s%sHead%s%s",
|
||||
ptrOrNot,
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
Op: op,
|
||||
Code: "StructField",
|
||||
HeadToPtrHead: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sFieldPtr%sHead%s%s",
|
||||
escapedOrNot,
|
||||
"StructFieldPtr%sHead%s%s%s",
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
onlyOrNot,
|
||||
)
|
||||
},
|
||||
HeadToNPtrHead: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sFieldNPtr%sHead%s%s",
|
||||
escapedOrNot,
|
||||
"StructFieldNPtr%sHead%s%s%s",
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
onlyOrNot,
|
||||
)
|
||||
},
|
||||
HeadToAnonymousHead: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sField%sAnonymousHead%s%s",
|
||||
escapedOrNot,
|
||||
"StructField%sAnonymousHead%s%s%s",
|
||||
ptrOrNot,
|
||||
opt,
|
||||
typ,
|
||||
onlyOrNot,
|
||||
)
|
||||
},
|
||||
HeadToOmitEmptyHead: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sField%s%sHeadOmitEmpty%s",
|
||||
escapedOrNot,
|
||||
"StructField%s%sHeadOmitEmpty%s%s",
|
||||
ptrOrNot,
|
||||
headType,
|
||||
typ,
|
||||
onlyOrNot,
|
||||
)
|
||||
},
|
||||
HeadToStringTagHead: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sField%s%sHeadStringTag%s",
|
||||
escapedOrNot,
|
||||
"StructField%s%sHeadStringTag%s%s",
|
||||
ptrOrNot,
|
||||
headType,
|
||||
typ,
|
||||
onlyOrNot,
|
||||
)
|
||||
},
|
||||
HeadToOnlyHead: func() string {
|
||||
switch typ {
|
||||
case "", "Array", "Map", "MapLoad", "Slice",
|
||||
"Struct", "Recursive", "MarshalJSON", "MarshalText",
|
||||
"IntString", "Int8String", "Int16String", "Int32String", "Int64String",
|
||||
"UintString", "Uint8String", "Uint16String", "Uint32String", "Uint64String":
|
||||
return op
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"StructField%s%sHead%s%sOnly",
|
||||
ptrOrNot,
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
PtrHeadToHead: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sField%sHead%s%s",
|
||||
escapedOrNot,
|
||||
"StructField%sHead%s%s%s",
|
||||
headType,
|
||||
opt,
|
||||
typ,
|
||||
onlyOrNot,
|
||||
)
|
||||
},
|
||||
FieldToEnd: func() string { return op },
|
||||
|
@ -481,169 +436,87 @@ func (t opType) fieldToStringTagField() opType {
|
|||
}
|
||||
}
|
||||
}
|
||||
for _, escapedOrNot := range []string{"", "Escaped"} {
|
||||
for _, typ := range append(primitiveTypesUpper, "") {
|
||||
for _, opt := range []string{"", "OmitEmpty", "StringTag"} {
|
||||
for _, typ := range append(primitiveTypesUpper, "") {
|
||||
escapedOrNot := escapedOrNot
|
||||
opt := opt
|
||||
typ := typ
|
||||
opt := opt
|
||||
typ := typ
|
||||
|
||||
op := fmt.Sprintf(
|
||||
"Struct%sField%s%s",
|
||||
escapedOrNot,
|
||||
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%sEscaped%s",
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"StructEscapedField%s%s",
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
HeadToPtrHead: func() string { return op },
|
||||
HeadToNPtrHead: func() string { return op },
|
||||
HeadToAnonymousHead: func() string { return op },
|
||||
HeadToOmitEmptyHead: func() string { return op },
|
||||
HeadToStringTagHead: func() string { return op },
|
||||
PtrHeadToHead: func() string { return op },
|
||||
FieldToEnd: func() string {
|
||||
switch typ {
|
||||
case "", "Array", "Map", "MapLoad", "Slice", "Struct", "Recursive":
|
||||
return op
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"Struct%sEnd%s%s",
|
||||
escapedOrNot,
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
FieldToOmitEmptyField: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sFieldOmitEmpty%s",
|
||||
escapedOrNot,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
FieldToStringTagField: func() string {
|
||||
return fmt.Sprintf(
|
||||
"Struct%sFieldStringTag%s",
|
||||
escapedOrNot,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
op := fmt.Sprintf(
|
||||
"StructField%s%s",
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
opTypes = append(opTypes, opType{
|
||||
Op: op,
|
||||
Code: "StructField",
|
||||
HeadToPtrHead: func() string { return op },
|
||||
HeadToNPtrHead: func() string { return op },
|
||||
HeadToAnonymousHead: func() string { return op },
|
||||
HeadToOmitEmptyHead: func() string { return op },
|
||||
HeadToStringTagHead: func() string { return op },
|
||||
HeadToOnlyHead: func() string { return op },
|
||||
PtrHeadToHead: func() string { return op },
|
||||
FieldToEnd: func() string {
|
||||
switch typ {
|
||||
case "", "Array", "Map", "MapLoad", "Slice", "Struct", "Recursive":
|
||||
return op
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"StructEnd%s%s",
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
FieldToOmitEmptyField: func() string {
|
||||
return fmt.Sprintf(
|
||||
"StructFieldOmitEmpty%s",
|
||||
typ,
|
||||
)
|
||||
},
|
||||
FieldToStringTagField: func() string {
|
||||
return fmt.Sprintf(
|
||||
"StructFieldStringTag%s",
|
||||
typ,
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, escapedOrNot := range []string{"", "Escaped"} {
|
||||
for _, typ := range append(primitiveTypesUpper, "") {
|
||||
for _, opt := range []string{"", "OmitEmpty", "StringTag"} {
|
||||
for _, typ := range append(primitiveTypesUpper, "") {
|
||||
escapedOrNot := escapedOrNot
|
||||
opt := opt
|
||||
typ := typ
|
||||
opt := opt
|
||||
typ := typ
|
||||
|
||||
op := fmt.Sprintf(
|
||||
"Struct%sEnd%s%s",
|
||||
escapedOrNot,
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
opTypes = append(opTypes, opType{
|
||||
Op: op,
|
||||
Code: "StructEnd",
|
||||
Indent: func() string { return fmt.Sprintf("%sIndent", op) },
|
||||
Escaped: func() string {
|
||||
switch typ {
|
||||
case "String", "StringPtr", "StringNPtr":
|
||||
return fmt.Sprintf(
|
||||
"StructEscapedEnd%sEscaped%s",
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"StructEscapedEnd%s%s",
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
},
|
||||
HeadToPtrHead: func() string { return op },
|
||||
HeadToNPtrHead: func() string { return op },
|
||||
HeadToAnonymousHead: func() string { return op },
|
||||
HeadToOmitEmptyHead: func() string { return op },
|
||||
HeadToStringTagHead: func() string { return op },
|
||||
PtrHeadToHead: func() string { return op },
|
||||
FieldToEnd: func() string { return op },
|
||||
FieldToOmitEmptyField: func() string { return op },
|
||||
FieldToStringTagField: func() string { return op },
|
||||
})
|
||||
}
|
||||
op := fmt.Sprintf(
|
||||
"StructEnd%s%s",
|
||||
opt,
|
||||
typ,
|
||||
)
|
||||
opTypes = append(opTypes, opType{
|
||||
Op: op,
|
||||
Code: "StructEnd",
|
||||
HeadToPtrHead: func() string { return op },
|
||||
HeadToNPtrHead: func() string { return op },
|
||||
HeadToAnonymousHead: func() string { return op },
|
||||
HeadToOmitEmptyHead: func() string { return op },
|
||||
HeadToStringTagHead: func() string { return op },
|
||||
HeadToOnlyHead: func() string { return op },
|
||||
PtrHeadToHead: func() string { return op },
|
||||
FieldToEnd: func() string { return op },
|
||||
FieldToOmitEmptyField: func() string { return op },
|
||||
FieldToStringTagField: func() string { return op },
|
||||
})
|
||||
}
|
||||
}
|
||||
indentOpTypes := []opType{}
|
||||
for _, typ := range opTypes {
|
||||
typ := typ
|
||||
indentOpTypes = append(indentOpTypes, opType{
|
||||
Op: fmt.Sprintf("%sIndent", typ.Op),
|
||||
Code: typ.Code,
|
||||
Indent: func() string { return fmt.Sprintf("%sIndent", typ.Op) },
|
||||
Escaped: func() string { return fmt.Sprintf("%sIndent", typ.Escaped()) },
|
||||
HeadToPtrHead: func() string {
|
||||
return fmt.Sprintf("%sIndent", typ.HeadToPtrHead())
|
||||
},
|
||||
HeadToNPtrHead: func() string {
|
||||
return fmt.Sprintf("%sIndent", typ.HeadToNPtrHead())
|
||||
},
|
||||
HeadToAnonymousHead: func() string {
|
||||
return fmt.Sprintf("%sIndent", typ.HeadToAnonymousHead())
|
||||
},
|
||||
HeadToOmitEmptyHead: func() string {
|
||||
return fmt.Sprintf("%sIndent", typ.HeadToOmitEmptyHead())
|
||||
},
|
||||
HeadToStringTagHead: func() string {
|
||||
return fmt.Sprintf("%sIndent", typ.HeadToStringTagHead())
|
||||
},
|
||||
PtrHeadToHead: func() string {
|
||||
return fmt.Sprintf("%sIndent", typ.PtrHeadToHead())
|
||||
},
|
||||
FieldToOmitEmptyField: func() string {
|
||||
return fmt.Sprintf("%sIndent", typ.FieldToOmitEmptyField())
|
||||
},
|
||||
FieldToStringTagField: func() string {
|
||||
return fmt.Sprintf("%sIndent", typ.FieldToStringTagField())
|
||||
},
|
||||
FieldToEnd: func() string {
|
||||
return fmt.Sprintf("%sIndent", typ.FieldToEnd())
|
||||
},
|
||||
})
|
||||
}
|
||||
var b bytes.Buffer
|
||||
if err := tmpl.Execute(&b, struct {
|
||||
CodeTypes []string
|
||||
OpTypes []opType
|
||||
OpNotIndentTypes []opType
|
||||
OpLen int
|
||||
OpIndentLen int
|
||||
CodeTypes []string
|
||||
OpTypes []opType
|
||||
OpLen int
|
||||
}{
|
||||
CodeTypes: codeTypes,
|
||||
OpTypes: append(opTypes, indentOpTypes...),
|
||||
OpNotIndentTypes: opTypes,
|
||||
OpLen: len(opTypes),
|
||||
OpIndentLen: len(indentOpTypes),
|
||||
CodeTypes: codeTypes,
|
||||
OpTypes: opTypes,
|
||||
OpLen: len(opTypes),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
61
encode.go
61
encode.go
|
@ -42,11 +42,8 @@ const (
|
|||
)
|
||||
|
||||
type opcodeSet struct {
|
||||
escapedCode *opcode
|
||||
escapedCodeIndent *opcode
|
||||
code *opcode
|
||||
codeIndent *opcode
|
||||
codeLength int
|
||||
code *opcode
|
||||
codeLength int
|
||||
}
|
||||
|
||||
func loadOpcodeMap() map[uintptr]*opcodeSet {
|
||||
|
@ -194,24 +191,21 @@ func (e *Encoder) encode(header *interfaceHeader, isNil bool) ([]byte, error) {
|
|||
typeptr := uintptr(unsafe.Pointer(typ))
|
||||
opcodeMap := loadOpcodeMap()
|
||||
if codeSet, exists := opcodeMap[typeptr]; exists {
|
||||
var code *opcode
|
||||
if e.enabledIndent {
|
||||
if e.enabledHTMLEscape {
|
||||
code = codeSet.escapedCodeIndent
|
||||
} else {
|
||||
code = codeSet.codeIndent
|
||||
}
|
||||
} else {
|
||||
if e.enabledHTMLEscape {
|
||||
code = codeSet.escapedCode
|
||||
} else {
|
||||
code = codeSet.code
|
||||
}
|
||||
}
|
||||
ctx := e.ctx
|
||||
p := uintptr(header.ptr)
|
||||
ctx.init(p, codeSet.codeLength)
|
||||
return e.run(ctx, b, code)
|
||||
|
||||
if e.enabledIndent {
|
||||
if e.enabledHTMLEscape {
|
||||
return e.runEscapedIndent(ctx, b, codeSet.code)
|
||||
} else {
|
||||
return e.runIndent(ctx, b, codeSet.code)
|
||||
}
|
||||
}
|
||||
if e.enabledHTMLEscape {
|
||||
return e.runEscaped(ctx, b, codeSet.code)
|
||||
}
|
||||
return e.run(ctx, b, codeSet.code)
|
||||
}
|
||||
|
||||
// noescape trick for header.typ ( reflect.*rtype )
|
||||
|
@ -226,14 +220,10 @@ func (e *Encoder) encode(header *interfaceHeader, isNil bool) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
code = copyOpcode(code)
|
||||
codeIndent := toIndent(code)
|
||||
codeLength := code.totalLength()
|
||||
codeSet := &opcodeSet{
|
||||
escapedCode: toEscaped(code),
|
||||
escapedCodeIndent: toEscaped(codeIndent),
|
||||
code: code,
|
||||
codeIndent: codeIndent,
|
||||
codeLength: codeLength,
|
||||
code: code,
|
||||
codeLength: codeLength,
|
||||
}
|
||||
|
||||
storeOpcodeSet(typeptr, codeSet, opcodeMap)
|
||||
|
@ -241,26 +231,17 @@ func (e *Encoder) encode(header *interfaceHeader, isNil bool) ([]byte, error) {
|
|||
ctx := e.ctx
|
||||
ctx.init(p, codeLength)
|
||||
|
||||
var c *opcode
|
||||
if e.enabledIndent {
|
||||
if e.enabledHTMLEscape {
|
||||
c = codeSet.escapedCodeIndent
|
||||
return e.runEscapedIndent(ctx, b, codeSet.code)
|
||||
} else {
|
||||
c = codeSet.codeIndent
|
||||
}
|
||||
} else {
|
||||
if e.enabledHTMLEscape {
|
||||
c = codeSet.escapedCode
|
||||
} else {
|
||||
c = codeSet.code
|
||||
return e.runIndent(ctx, b, codeSet.code)
|
||||
}
|
||||
}
|
||||
|
||||
b, err = e.run(ctx, b, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if e.enabledHTMLEscape {
|
||||
return e.runEscaped(ctx, b, codeSet.code)
|
||||
}
|
||||
return b, nil
|
||||
return e.run(ctx, b, codeSet.code)
|
||||
}
|
||||
|
||||
func encodeFloat32(b []byte, v float32) []byte {
|
||||
|
|
|
@ -32,6 +32,7 @@ func (e *Encoder) compileHead(ctx *encodeCompileContext) (*opcode, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.convertHeadOnlyCode(code, isPtr)
|
||||
e.optimizeStructEnd(code)
|
||||
return code, nil
|
||||
} else if isPtr && typ.Implements(marshalTextType) {
|
||||
|
@ -43,6 +44,7 @@ func (e *Encoder) compileHead(ctx *encodeCompileContext) (*opcode, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.convertHeadOnlyCode(code, isPtr)
|
||||
e.optimizeStructEnd(code)
|
||||
return code, nil
|
||||
}
|
||||
|
@ -88,6 +90,45 @@ func (e *Encoder) optimizeStructEnd(c *opcode) {
|
|||
}
|
||||
}
|
||||
|
||||
func (e *Encoder) convertHeadOnlyCode(c *opcode, isPtrHead bool) {
|
||||
if c.nextField == nil {
|
||||
return
|
||||
}
|
||||
if c.nextField.op.codeType() != codeStructEnd {
|
||||
return
|
||||
}
|
||||
switch c.op {
|
||||
case opStructFieldHead:
|
||||
e.convertHeadOnlyCode(c.next, false)
|
||||
if !strings.Contains(c.next.op.String(), "Only") {
|
||||
return
|
||||
}
|
||||
c.op = opStructFieldHeadOnly
|
||||
case opStructFieldHeadOmitEmpty:
|
||||
return
|
||||
case opStructFieldPtrHead:
|
||||
}
|
||||
|
||||
if strings.Contains(c.op.String(), "Marshal") {
|
||||
return
|
||||
}
|
||||
if strings.Contains(c.op.String(), "Slice") {
|
||||
return
|
||||
}
|
||||
if strings.Contains(c.op.String(), "Map") {
|
||||
return
|
||||
}
|
||||
|
||||
isPtrOp := strings.Contains(c.op.String(), "Ptr")
|
||||
if isPtrOp && !isPtrHead {
|
||||
c.op = c.op.headToOnlyHead()
|
||||
} else if !isPtrOp && isPtrHead {
|
||||
c.op = c.op.headToPtrHead().headToOnlyHead()
|
||||
} else if isPtrOp && isPtrHead {
|
||||
c.op = c.op.headToPtrHead().headToOnlyHead()
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Encoder) implementsMarshaler(typ *rtype) bool {
|
||||
switch {
|
||||
case typ.Implements(marshalJSONType):
|
||||
|
@ -1102,17 +1143,6 @@ 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()
|
||||
}
|
||||
}
|
||||
key := fmt.Sprintf(`"%s":`, tag.key)
|
||||
escapedKey := fmt.Sprintf(`%s:`, string(encodeEscapedString([]byte{}, tag.key)))
|
||||
fieldCode := &opcode{
|
||||
|
|
|
@ -53,34 +53,6 @@ func copyOpcode(code *opcode) *opcode {
|
|||
return code.copy(codeMap)
|
||||
}
|
||||
|
||||
func toIndent(c *opcode) *opcode {
|
||||
c = copyOpcode(c)
|
||||
for code := c; code.op != opEnd; {
|
||||
code.op = code.op.toIndent()
|
||||
switch code.op.codeType() {
|
||||
case codeArrayElem, codeSliceElem, codeMapKey:
|
||||
code = code.end
|
||||
default:
|
||||
code = code.next
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func toEscaped(c *opcode) *opcode {
|
||||
c = copyOpcode(c)
|
||||
for code := c; code.op != opEnd; {
|
||||
code.op = code.op.toEscaped()
|
||||
switch code.op.codeType() {
|
||||
case codeArrayElem, codeSliceElem, codeMapKey:
|
||||
code = code.end
|
||||
default:
|
||||
code = code.next
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func newOpCodeWithNext(ctx *encodeCompileContext, op opType, next *opcode) *opcode {
|
||||
return &opcode{
|
||||
op: op,
|
||||
|
|
50851
encode_optype.go
50851
encode_optype.go
File diff suppressed because it is too large
Load Diff
9911
encode_vm.go
9911
encode_vm.go
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue