mirror of https://github.com/goccy/go-json.git
Add MarshalIndent
This commit is contained in:
parent
03a21193fc
commit
3d7267abc8
122
encode.go
122
encode.go
|
@ -1,6 +1,7 @@
|
|||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
@ -10,9 +11,13 @@ import (
|
|||
|
||||
// An Encoder writes JSON values to an output stream.
|
||||
type Encoder struct {
|
||||
w io.Writer
|
||||
buf []byte
|
||||
pool sync.Pool
|
||||
w io.Writer
|
||||
buf []byte
|
||||
pool sync.Pool
|
||||
enabledIndent bool
|
||||
prefix []byte
|
||||
indentStr []byte
|
||||
indent int
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -23,14 +28,19 @@ type opcodeMap struct {
|
|||
sync.Map
|
||||
}
|
||||
|
||||
func (m *opcodeMap) Get(k *rtype) *opcode {
|
||||
type opcodeSet struct {
|
||||
codeIndent *opcode
|
||||
code *opcode
|
||||
}
|
||||
|
||||
func (m *opcodeMap) get(k *rtype) *opcodeSet {
|
||||
if v, ok := m.Load(k); ok {
|
||||
return v.(*opcode)
|
||||
return v.(*opcodeSet)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *opcodeMap) Set(k *rtype, op *opcode) {
|
||||
func (m *opcodeMap) set(k *rtype, op *opcodeSet) {
|
||||
m.Store(k, op)
|
||||
}
|
||||
|
||||
|
@ -55,6 +65,7 @@ func init() {
|
|||
func NewEncoder(w io.Writer) *Encoder {
|
||||
enc := encPool.Get().(*Encoder)
|
||||
enc.w = w
|
||||
enc.indent = 0
|
||||
enc.reset()
|
||||
return enc
|
||||
}
|
||||
|
@ -72,15 +83,6 @@ func (e *Encoder) Encode(v interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeForMarshal(v interface{}) ([]byte, error) {
|
||||
if err := e.encode(v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copied := make([]byte, len(e.buf))
|
||||
copy(copied, e.buf)
|
||||
return copied, nil
|
||||
}
|
||||
|
||||
// SetEscapeHTML specifies whether problematic HTML characters should be escaped inside JSON quoted strings.
|
||||
// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e to avoid certain safety problems that can arise when embedding JSON in HTML.
|
||||
//
|
||||
|
@ -92,7 +94,13 @@ func (e *Encoder) SetEscapeHTML(on bool) {
|
|||
// SetIndent instructs the encoder to format each subsequent encoded value as if indented by the package-level function Indent(dst, src, prefix, indent).
|
||||
// Calling SetIndent("", "") disables indentation.
|
||||
func (e *Encoder) SetIndent(prefix, indent string) {
|
||||
|
||||
if prefix == "" && indent == "" {
|
||||
e.enabledIndent = false
|
||||
return
|
||||
}
|
||||
e.prefix = []byte(prefix)
|
||||
e.indentStr = []byte(indent)
|
||||
e.enabledIndent = true
|
||||
}
|
||||
|
||||
func (e *Encoder) release() {
|
||||
|
@ -104,6 +112,63 @@ func (e *Encoder) reset() {
|
|||
e.buf = e.buf[:0]
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeForMarshal(v interface{}) ([]byte, error) {
|
||||
if err := e.encode(v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if e.enabledIndent {
|
||||
last := len(e.buf) - 1
|
||||
if e.buf[last] == '\n' {
|
||||
last--
|
||||
}
|
||||
length := last + 1
|
||||
copied := make([]byte, length)
|
||||
copy(copied, e.buf[0:length])
|
||||
return copied, nil
|
||||
}
|
||||
copied := make([]byte, len(e.buf))
|
||||
copy(copied, e.buf)
|
||||
return copied, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encode(v interface{}) error {
|
||||
header := (*interfaceHeader)(unsafe.Pointer(&v))
|
||||
typ := header.typ
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
}
|
||||
if codeSet := cachedOpcode.get(typ); codeSet != nil {
|
||||
var code *opcode
|
||||
if e.enabledIndent {
|
||||
code = codeSet.codeIndent
|
||||
} else {
|
||||
code = codeSet.code
|
||||
}
|
||||
p := uintptr(header.ptr)
|
||||
code.ptr = p
|
||||
if err := e.run(code); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
codeIndent, err := e.compile(typ, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
code, err := e.compile(typ, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
codeSet := &opcodeSet{codeIndent: codeIndent, code: code}
|
||||
cachedOpcode.set(typ, codeSet)
|
||||
p := uintptr(header.ptr)
|
||||
code.ptr = p
|
||||
if e.enabledIndent {
|
||||
return e.run(codeIndent)
|
||||
}
|
||||
return e.run(code)
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeInt(v int) {
|
||||
e.encodeInt64(int64(v))
|
||||
}
|
||||
|
@ -169,26 +234,7 @@ func (e *Encoder) encodeByte(b byte) {
|
|||
e.buf = append(e.buf, b)
|
||||
}
|
||||
|
||||
func (e *Encoder) encode(v interface{}) error {
|
||||
header := (*interfaceHeader)(unsafe.Pointer(&v))
|
||||
typ := header.typ
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
}
|
||||
if code := cachedOpcode.Get(typ); code != nil {
|
||||
p := uintptr(header.ptr)
|
||||
code.ptr = p
|
||||
if err := e.run(code); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
code, err := e.compile(typ)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cachedOpcode.Set(typ, code)
|
||||
p := uintptr(header.ptr)
|
||||
code.ptr = p
|
||||
return e.run(code)
|
||||
func (e *Encoder) encodeIndent(indent int) {
|
||||
e.buf = append(e.buf, e.prefix...)
|
||||
e.buf = append(e.buf, bytes.Repeat(e.indentStr, indent)...)
|
||||
}
|
||||
|
|
|
@ -9,18 +9,18 @@ import (
|
|||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func (e *Encoder) compile(typ *rtype) (*opcode, error) {
|
||||
func (e *Encoder) compile(typ *rtype, withIndent bool) (*opcode, error) {
|
||||
switch typ.Kind() {
|
||||
case reflect.Ptr:
|
||||
return e.compilePtr(typ)
|
||||
return e.compilePtr(typ, withIndent)
|
||||
case reflect.Slice:
|
||||
return e.compileSlice(typ)
|
||||
return e.compileSlice(typ, withIndent)
|
||||
case reflect.Array:
|
||||
return e.compileArray(typ)
|
||||
return e.compileArray(typ, withIndent)
|
||||
case reflect.Map:
|
||||
return e.compileMap(typ)
|
||||
return e.compileMap(typ, withIndent)
|
||||
case reflect.Struct:
|
||||
return e.compileStruct(typ)
|
||||
return e.compileStruct(typ, withIndent)
|
||||
case reflect.Int:
|
||||
return e.compileInt(typ)
|
||||
case reflect.Int8:
|
||||
|
@ -119,14 +119,75 @@ func (e *Encoder) optimizeStructFieldPtrHead(typ *rtype, code *opcode) *opcode {
|
|||
code.op = opStructFieldPtrHeadStringOmitEmpty
|
||||
case opStructFieldHeadBoolOmitEmpty:
|
||||
code.op = opStructFieldPtrHeadBoolOmitEmpty
|
||||
|
||||
case opStructFieldHeadIndent:
|
||||
code.op = opStructFieldPtrHeadIndent
|
||||
case opStructFieldHeadIntIndent:
|
||||
code.op = opStructFieldPtrHeadIntIndent
|
||||
case opStructFieldHeadInt8Indent:
|
||||
code.op = opStructFieldPtrHeadInt8Indent
|
||||
case opStructFieldHeadInt16Indent:
|
||||
code.op = opStructFieldPtrHeadInt16Indent
|
||||
case opStructFieldHeadInt32Indent:
|
||||
code.op = opStructFieldPtrHeadInt32Indent
|
||||
case opStructFieldHeadInt64Indent:
|
||||
code.op = opStructFieldPtrHeadInt64Indent
|
||||
case opStructFieldHeadUintIndent:
|
||||
code.op = opStructFieldPtrHeadUintIndent
|
||||
case opStructFieldHeadUint8Indent:
|
||||
code.op = opStructFieldPtrHeadUint8Indent
|
||||
case opStructFieldHeadUint16Indent:
|
||||
code.op = opStructFieldPtrHeadUint16Indent
|
||||
case opStructFieldHeadUint32Indent:
|
||||
code.op = opStructFieldPtrHeadUint32Indent
|
||||
case opStructFieldHeadUint64Indent:
|
||||
code.op = opStructFieldPtrHeadUint64Indent
|
||||
case opStructFieldHeadFloat32Indent:
|
||||
code.op = opStructFieldPtrHeadFloat32Indent
|
||||
case opStructFieldHeadFloat64Indent:
|
||||
code.op = opStructFieldPtrHeadFloat64Indent
|
||||
case opStructFieldHeadStringIndent:
|
||||
code.op = opStructFieldPtrHeadStringIndent
|
||||
case opStructFieldHeadBoolIndent:
|
||||
code.op = opStructFieldPtrHeadBoolIndent
|
||||
case opStructFieldHeadOmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadOmitEmptyIndent
|
||||
case opStructFieldHeadIntOmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadIntOmitEmptyIndent
|
||||
case opStructFieldHeadInt8OmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadInt8OmitEmptyIndent
|
||||
case opStructFieldHeadInt16OmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadInt16OmitEmptyIndent
|
||||
case opStructFieldHeadInt32OmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadInt32OmitEmptyIndent
|
||||
case opStructFieldHeadInt64OmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadInt64OmitEmptyIndent
|
||||
case opStructFieldHeadUintOmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadUintOmitEmptyIndent
|
||||
case opStructFieldHeadUint8OmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadUint8OmitEmptyIndent
|
||||
case opStructFieldHeadUint16OmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadUint16OmitEmptyIndent
|
||||
case opStructFieldHeadUint32OmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadUint32OmitEmptyIndent
|
||||
case opStructFieldHeadUint64OmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadUint64OmitEmptyIndent
|
||||
case opStructFieldHeadFloat32OmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadFloat32OmitEmptyIndent
|
||||
case opStructFieldHeadFloat64OmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadFloat64OmitEmptyIndent
|
||||
case opStructFieldHeadStringOmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadStringOmitEmptyIndent
|
||||
case opStructFieldHeadBoolOmitEmptyIndent:
|
||||
code.op = opStructFieldPtrHeadBoolOmitEmptyIndent
|
||||
default:
|
||||
return newOpCode(opPtr, typ, code)
|
||||
return newOpCode(opPtr, typ, e.indent, code)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func (e *Encoder) compilePtr(typ *rtype) (*opcode, error) {
|
||||
code, err := e.compile(typ.Elem())
|
||||
func (e *Encoder) compilePtr(typ *rtype, withIndent bool) (*opcode, error) {
|
||||
code, err := e.compile(typ.Elem(), withIndent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -134,69 +195,73 @@ func (e *Encoder) compilePtr(typ *rtype) (*opcode, error) {
|
|||
}
|
||||
|
||||
func (e *Encoder) compileInt(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opInt, typ, newEndOp()), nil
|
||||
return newOpCode(opInt, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileInt8(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opInt8, typ, newEndOp()), nil
|
||||
return newOpCode(opInt8, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileInt16(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opInt16, typ, newEndOp()), nil
|
||||
return newOpCode(opInt16, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileInt32(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opInt32, typ, newEndOp()), nil
|
||||
return newOpCode(opInt32, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileInt64(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opInt64, typ, newEndOp()), nil
|
||||
return newOpCode(opInt64, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileUint(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opUint, typ, newEndOp()), nil
|
||||
return newOpCode(opUint, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileUint8(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opUint8, typ, newEndOp()), nil
|
||||
return newOpCode(opUint8, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileUint16(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opUint16, typ, newEndOp()), nil
|
||||
return newOpCode(opUint16, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileUint32(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opUint32, typ, newEndOp()), nil
|
||||
return newOpCode(opUint32, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileUint64(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opUint64, typ, newEndOp()), nil
|
||||
return newOpCode(opUint64, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileFloat32(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opFloat32, typ, newEndOp()), nil
|
||||
return newOpCode(opFloat32, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileFloat64(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opFloat64, typ, newEndOp()), nil
|
||||
return newOpCode(opFloat64, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileString(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opString, typ, newEndOp()), nil
|
||||
return newOpCode(opString, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileBool(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opBool, typ, newEndOp()), nil
|
||||
return newOpCode(opBool, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileInterface(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opInterface, typ, newEndOp()), nil
|
||||
return newOpCode(opInterface, typ, e.indent, newEndOp(e.indent)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileSlice(typ *rtype) (*opcode, error) {
|
||||
func (e *Encoder) compileSlice(typ *rtype, withIndent bool) (*opcode, error) {
|
||||
elem := typ.Elem()
|
||||
size := elem.Size()
|
||||
code, err := e.compile(elem)
|
||||
|
||||
e.indent++
|
||||
code, err := e.compile(elem, withIndent)
|
||||
e.indent--
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -205,9 +270,20 @@ func (e *Encoder) compileSlice(typ *rtype) (*opcode, error) {
|
|||
// ^ |
|
||||
// |________|
|
||||
|
||||
header := newSliceHeaderCode()
|
||||
elemCode := &sliceElemCode{opcodeHeader: &opcodeHeader{op: opSliceElem}, size: size}
|
||||
end := newOpCode(opSliceEnd, nil, newEndOp())
|
||||
header := newSliceHeaderCode(e.indent)
|
||||
elemCode := &sliceElemCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opSliceElem,
|
||||
indent: e.indent,
|
||||
},
|
||||
size: size,
|
||||
}
|
||||
end := newOpCode(opSliceEnd, nil, e.indent, newEndOp(e.indent))
|
||||
if withIndent {
|
||||
header.op = opSliceHeadIndent
|
||||
elemCode.op = opSliceElemIndent
|
||||
end.op = opSliceEndIndent
|
||||
}
|
||||
|
||||
header.elem = elemCode
|
||||
header.end = end
|
||||
|
@ -218,11 +294,15 @@ func (e *Encoder) compileSlice(typ *rtype) (*opcode, error) {
|
|||
return (*opcode)(unsafe.Pointer(header)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileArray(typ *rtype) (*opcode, error) {
|
||||
func (e *Encoder) compileArray(typ *rtype, withIndent bool) (*opcode, error) {
|
||||
elem := typ.Elem()
|
||||
alen := typ.Len()
|
||||
size := elem.Size()
|
||||
code, err := e.compile(elem)
|
||||
|
||||
e.indent++
|
||||
code, err := e.compile(elem, withIndent)
|
||||
e.indent--
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -230,7 +310,7 @@ func (e *Encoder) compileArray(typ *rtype) (*opcode, error) {
|
|||
// ^ |
|
||||
// |________|
|
||||
|
||||
header := newArrayHeaderCode(alen)
|
||||
header := newArrayHeaderCode(e.indent, alen)
|
||||
elemCode := &arrayElemCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opArrayElem,
|
||||
|
@ -238,7 +318,13 @@ func (e *Encoder) compileArray(typ *rtype) (*opcode, error) {
|
|||
len: uintptr(alen),
|
||||
size: size,
|
||||
}
|
||||
end := newOpCode(opArrayEnd, nil, newEndOp())
|
||||
end := newOpCode(opArrayEnd, nil, e.indent, newEndOp(e.indent))
|
||||
|
||||
if withIndent {
|
||||
header.op = opArrayHeadIndent
|
||||
elemCode.op = opArrayElemIndent
|
||||
end.op = opArrayEndIndent
|
||||
}
|
||||
|
||||
header.elem = elemCode
|
||||
header.end = end
|
||||
|
@ -265,26 +351,38 @@ func mapiternext(it unsafe.Pointer)
|
|||
//go:noescape
|
||||
func maplen(m unsafe.Pointer) int
|
||||
|
||||
func (e *Encoder) compileMap(typ *rtype) (*opcode, error) {
|
||||
func (e *Encoder) compileMap(typ *rtype, withIndent bool) (*opcode, error) {
|
||||
// header => code => value => code => key => code => value => code => end
|
||||
// ^ |
|
||||
// |_______________________|
|
||||
e.indent++
|
||||
keyType := typ.Key()
|
||||
keyCode, err := e.compile(keyType)
|
||||
keyCode, err := e.compile(keyType, withIndent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
valueType := typ.Elem()
|
||||
valueCode, err := e.compile(valueType)
|
||||
valueCode, err := e.compile(valueType, withIndent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
header := newMapHeaderCode(typ)
|
||||
key := newMapKeyCode()
|
||||
value := newMapValueCode()
|
||||
|
||||
key := newMapKeyCode(e.indent)
|
||||
value := newMapValueCode(e.indent)
|
||||
|
||||
e.indent--
|
||||
|
||||
header := newMapHeaderCode(typ, e.indent)
|
||||
header.key = key
|
||||
header.value = value
|
||||
end := newOpCode(opMapEnd, nil, newEndOp())
|
||||
end := newOpCode(opMapEnd, nil, e.indent, newEndOp(e.indent))
|
||||
|
||||
if withIndent {
|
||||
header.op = opMapHeadIndent
|
||||
key.op = opMapKeyIndent
|
||||
value.op = opMapValueIndent
|
||||
end.op = opMapEndIndent
|
||||
}
|
||||
|
||||
header.next = keyCode
|
||||
keyCode.beforeLastCode().next = (*opcode)(unsafe.Pointer(value))
|
||||
|
@ -314,7 +412,297 @@ func (e *Encoder) isIgnoredStructField(field reflect.StructField) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (e *Encoder) compileStruct(typ *rtype) (*opcode, error) {
|
||||
func (e *Encoder) optimizeStructHeaderOmitEmptyIndent(op opType) opType {
|
||||
switch op {
|
||||
case opInt:
|
||||
return opStructFieldHeadIntOmitEmptyIndent
|
||||
case opInt8:
|
||||
return opStructFieldHeadInt8OmitEmptyIndent
|
||||
case opInt16:
|
||||
return opStructFieldHeadInt16OmitEmptyIndent
|
||||
case opInt32:
|
||||
return opStructFieldHeadInt32OmitEmptyIndent
|
||||
case opInt64:
|
||||
return opStructFieldHeadInt64OmitEmptyIndent
|
||||
case opUint:
|
||||
return opStructFieldHeadUintOmitEmptyIndent
|
||||
case opUint8:
|
||||
return opStructFieldHeadUint8OmitEmptyIndent
|
||||
case opUint16:
|
||||
return opStructFieldHeadUint16OmitEmptyIndent
|
||||
case opUint32:
|
||||
return opStructFieldHeadUint32OmitEmptyIndent
|
||||
case opUint64:
|
||||
return opStructFieldHeadUint64OmitEmptyIndent
|
||||
case opFloat32:
|
||||
return opStructFieldHeadFloat32OmitEmptyIndent
|
||||
case opFloat64:
|
||||
return opStructFieldHeadFloat64OmitEmptyIndent
|
||||
case opString:
|
||||
return opStructFieldHeadStringOmitEmptyIndent
|
||||
case opBool:
|
||||
return opStructFieldHeadBoolOmitEmptyIndent
|
||||
}
|
||||
return opStructFieldHeadOmitEmptyIndent
|
||||
}
|
||||
|
||||
func (e *Encoder) optimizeStructHeaderIndent(op opType, isOmitEmpty bool) opType {
|
||||
if isOmitEmpty {
|
||||
return e.optimizeStructHeaderOmitEmptyIndent(op)
|
||||
}
|
||||
switch op {
|
||||
case opInt:
|
||||
return opStructFieldHeadIntIndent
|
||||
case opInt8:
|
||||
return opStructFieldHeadInt8Indent
|
||||
case opInt16:
|
||||
return opStructFieldHeadInt16Indent
|
||||
case opInt32:
|
||||
return opStructFieldHeadInt32Indent
|
||||
case opInt64:
|
||||
return opStructFieldHeadInt64Indent
|
||||
case opUint:
|
||||
return opStructFieldHeadUintIndent
|
||||
case opUint8:
|
||||
return opStructFieldHeadUint8Indent
|
||||
case opUint16:
|
||||
return opStructFieldHeadUint16Indent
|
||||
case opUint32:
|
||||
return opStructFieldHeadUint32Indent
|
||||
case opUint64:
|
||||
return opStructFieldHeadUint64Indent
|
||||
case opFloat32:
|
||||
return opStructFieldHeadFloat32Indent
|
||||
case opFloat64:
|
||||
return opStructFieldHeadFloat64Indent
|
||||
case opString:
|
||||
return opStructFieldHeadStringIndent
|
||||
case opBool:
|
||||
return opStructFieldHeadBoolIndent
|
||||
}
|
||||
return opStructFieldHeadIndent
|
||||
}
|
||||
|
||||
func (e *Encoder) optimizeStructHeaderOmitEmpty(op opType) opType {
|
||||
switch op {
|
||||
case opInt:
|
||||
return opStructFieldHeadIntOmitEmpty
|
||||
case opInt8:
|
||||
return opStructFieldHeadInt8OmitEmpty
|
||||
case opInt16:
|
||||
return opStructFieldHeadInt16OmitEmpty
|
||||
case opInt32:
|
||||
return opStructFieldHeadInt32OmitEmpty
|
||||
case opInt64:
|
||||
return opStructFieldHeadInt64OmitEmpty
|
||||
case opUint:
|
||||
return opStructFieldHeadUintOmitEmpty
|
||||
case opUint8:
|
||||
return opStructFieldHeadUint8OmitEmpty
|
||||
case opUint16:
|
||||
return opStructFieldHeadUint16OmitEmpty
|
||||
case opUint32:
|
||||
return opStructFieldHeadUint32OmitEmpty
|
||||
case opUint64:
|
||||
return opStructFieldHeadUint64OmitEmpty
|
||||
case opFloat32:
|
||||
return opStructFieldHeadFloat32OmitEmpty
|
||||
case opFloat64:
|
||||
return opStructFieldHeadFloat64OmitEmpty
|
||||
case opString:
|
||||
return opStructFieldHeadStringOmitEmpty
|
||||
case opBool:
|
||||
return opStructFieldHeadBoolOmitEmpty
|
||||
}
|
||||
return opStructFieldHeadOmitEmpty
|
||||
}
|
||||
|
||||
func (e *Encoder) optimizeStructHeader(op opType, isOmitEmpty, withIndent bool) opType {
|
||||
if withIndent {
|
||||
return e.optimizeStructHeaderIndent(op, isOmitEmpty)
|
||||
}
|
||||
if isOmitEmpty {
|
||||
return e.optimizeStructHeaderOmitEmpty(op)
|
||||
}
|
||||
switch op {
|
||||
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
|
||||
}
|
||||
return opStructFieldHead
|
||||
}
|
||||
|
||||
func (e *Encoder) optimizeStructFieldOmitEmptyIndent(op opType) opType {
|
||||
switch op {
|
||||
case opInt:
|
||||
return opStructFieldIntOmitEmptyIndent
|
||||
case opInt8:
|
||||
return opStructFieldInt8OmitEmptyIndent
|
||||
case opInt16:
|
||||
return opStructFieldInt16OmitEmptyIndent
|
||||
case opInt32:
|
||||
return opStructFieldInt32OmitEmptyIndent
|
||||
case opInt64:
|
||||
return opStructFieldInt64OmitEmptyIndent
|
||||
case opUint:
|
||||
return opStructFieldUintOmitEmptyIndent
|
||||
case opUint8:
|
||||
return opStructFieldUint8OmitEmptyIndent
|
||||
case opUint16:
|
||||
return opStructFieldUint16OmitEmptyIndent
|
||||
case opUint32:
|
||||
return opStructFieldUint32OmitEmptyIndent
|
||||
case opUint64:
|
||||
return opStructFieldUint64OmitEmptyIndent
|
||||
case opFloat32:
|
||||
return opStructFieldFloat32OmitEmptyIndent
|
||||
case opFloat64:
|
||||
return opStructFieldFloat64OmitEmptyIndent
|
||||
case opString:
|
||||
return opStructFieldStringOmitEmptyIndent
|
||||
case opBool:
|
||||
return opStructFieldBoolOmitEmptyIndent
|
||||
}
|
||||
return opStructFieldOmitEmptyIndent
|
||||
}
|
||||
|
||||
func (e *Encoder) optimizeStructFieldIndent(op opType, isOmitEmpty bool) opType {
|
||||
if isOmitEmpty {
|
||||
return e.optimizeStructFieldOmitEmptyIndent(op)
|
||||
}
|
||||
switch op {
|
||||
case opInt:
|
||||
return opStructFieldIntIndent
|
||||
case opInt8:
|
||||
return opStructFieldInt8Indent
|
||||
case opInt16:
|
||||
return opStructFieldInt16Indent
|
||||
case opInt32:
|
||||
return opStructFieldInt32Indent
|
||||
case opInt64:
|
||||
return opStructFieldInt64Indent
|
||||
case opUint:
|
||||
return opStructFieldUintIndent
|
||||
case opUint8:
|
||||
return opStructFieldUint8Indent
|
||||
case opUint16:
|
||||
return opStructFieldUint16Indent
|
||||
case opUint32:
|
||||
return opStructFieldUint32Indent
|
||||
case opUint64:
|
||||
return opStructFieldUint64Indent
|
||||
case opFloat32:
|
||||
return opStructFieldFloat32Indent
|
||||
case opFloat64:
|
||||
return opStructFieldFloat64Indent
|
||||
case opString:
|
||||
return opStructFieldStringIndent
|
||||
case opBool:
|
||||
return opStructFieldBoolIndent
|
||||
}
|
||||
return opStructFieldIndent
|
||||
}
|
||||
|
||||
func (e *Encoder) optimizeStructFieldOmitEmpty(op opType) opType {
|
||||
switch op {
|
||||
case opInt:
|
||||
return opStructFieldIntOmitEmpty
|
||||
case opInt8:
|
||||
return opStructFieldInt8OmitEmpty
|
||||
case opInt16:
|
||||
return opStructFieldInt16OmitEmpty
|
||||
case opInt32:
|
||||
return opStructFieldInt32OmitEmpty
|
||||
case opInt64:
|
||||
return opStructFieldInt64OmitEmpty
|
||||
case opUint:
|
||||
return opStructFieldUintOmitEmpty
|
||||
case opUint8:
|
||||
return opStructFieldUint8OmitEmpty
|
||||
case opUint16:
|
||||
return opStructFieldUint16OmitEmpty
|
||||
case opUint32:
|
||||
return opStructFieldUint32OmitEmpty
|
||||
case opUint64:
|
||||
return opStructFieldUint64OmitEmpty
|
||||
case opFloat32:
|
||||
return opStructFieldFloat32OmitEmpty
|
||||
case opFloat64:
|
||||
return opStructFieldFloat64OmitEmpty
|
||||
case opString:
|
||||
return opStructFieldStringOmitEmpty
|
||||
case opBool:
|
||||
return opStructFieldBoolOmitEmpty
|
||||
}
|
||||
return opStructFieldOmitEmpty
|
||||
}
|
||||
|
||||
func (e *Encoder) optimizeStructField(op opType, isOmitEmpty, withIndent bool) opType {
|
||||
if withIndent {
|
||||
return e.optimizeStructFieldIndent(op, isOmitEmpty)
|
||||
}
|
||||
if isOmitEmpty {
|
||||
return e.optimizeStructFieldOmitEmpty(op)
|
||||
}
|
||||
switch op {
|
||||
case opInt:
|
||||
return opStructFieldInt
|
||||
case opInt8:
|
||||
return opStructFieldInt8
|
||||
case opInt16:
|
||||
return opStructFieldInt16
|
||||
case opInt32:
|
||||
return opStructFieldInt32
|
||||
case opInt64:
|
||||
return opStructFieldInt64
|
||||
case opUint:
|
||||
return opStructFieldUint
|
||||
case opUint8:
|
||||
return opStructFieldUint8
|
||||
case opUint16:
|
||||
return opStructFieldUint16
|
||||
case opUint32:
|
||||
return opStructFieldUint32
|
||||
case opUint64:
|
||||
return opStructFieldUint64
|
||||
case opFloat32:
|
||||
return opStructFieldFloat32
|
||||
case opFloat64:
|
||||
return opStructFieldFloat64
|
||||
case opString:
|
||||
return opStructFieldString
|
||||
case opBool:
|
||||
return opStructFieldBool
|
||||
}
|
||||
return opStructField
|
||||
}
|
||||
|
||||
func (e *Encoder) compileStruct(typ *rtype, withIndent bool) (*opcode, error) {
|
||||
// header => code => structField => code => end
|
||||
// ^ |
|
||||
// |__________|
|
||||
|
@ -325,6 +713,7 @@ func (e *Encoder) compileStruct(typ *rtype) (*opcode, error) {
|
|||
code *opcode
|
||||
prevField *structFieldCode
|
||||
)
|
||||
e.indent++
|
||||
for i := 0; i < fieldNum; i++ {
|
||||
field := typ.Field(i)
|
||||
if e.isIgnoredStructField(field) {
|
||||
|
@ -343,171 +732,58 @@ func (e *Encoder) compileStruct(typ *rtype) (*opcode, error) {
|
|||
isOmitEmpty = opts[1] == "omitempty"
|
||||
}
|
||||
fieldType := type2rtype(field.Type)
|
||||
valueCode, err := e.compile(fieldType)
|
||||
valueCode, err := e.compile(fieldType, withIndent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := fmt.Sprintf(`"%s":`, keyName)
|
||||
fieldCode := &structFieldCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
typ: fieldType,
|
||||
next: valueCode,
|
||||
typ: fieldType,
|
||||
next: valueCode,
|
||||
indent: e.indent,
|
||||
},
|
||||
key: []byte(key),
|
||||
offset: field.Offset,
|
||||
}
|
||||
if fieldIdx == 0 {
|
||||
fieldCode.indent--
|
||||
head = fieldCode
|
||||
code = (*opcode)(unsafe.Pointer(fieldCode))
|
||||
prevField = fieldCode
|
||||
if isOmitEmpty {
|
||||
fieldCode.op = opStructFieldHeadOmitEmpty
|
||||
switch valueCode.op {
|
||||
case opInt:
|
||||
fieldCode.op = opStructFieldHeadIntOmitEmpty
|
||||
case opInt8:
|
||||
fieldCode.op = opStructFieldHeadInt8OmitEmpty
|
||||
case opInt16:
|
||||
fieldCode.op = opStructFieldHeadInt16OmitEmpty
|
||||
case opInt32:
|
||||
fieldCode.op = opStructFieldHeadInt32OmitEmpty
|
||||
case opInt64:
|
||||
fieldCode.op = opStructFieldHeadInt64OmitEmpty
|
||||
case opUint:
|
||||
fieldCode.op = opStructFieldHeadUintOmitEmpty
|
||||
case opUint8:
|
||||
fieldCode.op = opStructFieldHeadUint8OmitEmpty
|
||||
case opUint16:
|
||||
fieldCode.op = opStructFieldHeadUint16OmitEmpty
|
||||
case opUint32:
|
||||
fieldCode.op = opStructFieldHeadUint32OmitEmpty
|
||||
case opUint64:
|
||||
fieldCode.op = opStructFieldHeadUint64OmitEmpty
|
||||
case opFloat32:
|
||||
fieldCode.op = opStructFieldHeadFloat32OmitEmpty
|
||||
case opFloat64:
|
||||
fieldCode.op = opStructFieldHeadFloat64OmitEmpty
|
||||
case opString:
|
||||
fieldCode.op = opStructFieldHeadStringOmitEmpty
|
||||
case opBool:
|
||||
fieldCode.op = opStructFieldHeadBoolOmitEmpty
|
||||
default:
|
||||
code = valueCode.beforeLastCode()
|
||||
}
|
||||
} else {
|
||||
fieldCode.op = opStructFieldHead
|
||||
switch valueCode.op {
|
||||
case opInt:
|
||||
fieldCode.op = opStructFieldHeadInt
|
||||
case opInt8:
|
||||
fieldCode.op = opStructFieldHeadInt8
|
||||
case opInt16:
|
||||
fieldCode.op = opStructFieldHeadInt16
|
||||
case opInt32:
|
||||
fieldCode.op = opStructFieldHeadInt32
|
||||
case opInt64:
|
||||
fieldCode.op = opStructFieldHeadInt64
|
||||
case opUint:
|
||||
fieldCode.op = opStructFieldHeadUint
|
||||
case opUint8:
|
||||
fieldCode.op = opStructFieldHeadUint8
|
||||
case opUint16:
|
||||
fieldCode.op = opStructFieldHeadUint16
|
||||
case opUint32:
|
||||
fieldCode.op = opStructFieldHeadUint32
|
||||
case opUint64:
|
||||
fieldCode.op = opStructFieldHeadUint64
|
||||
case opFloat32:
|
||||
fieldCode.op = opStructFieldHeadFloat32
|
||||
case opFloat64:
|
||||
fieldCode.op = opStructFieldHeadFloat64
|
||||
case opString:
|
||||
fieldCode.op = opStructFieldHeadString
|
||||
case opBool:
|
||||
fieldCode.op = opStructFieldHeadBool
|
||||
default:
|
||||
code = valueCode.beforeLastCode()
|
||||
}
|
||||
op := e.optimizeStructHeader(valueCode.op, isOmitEmpty, withIndent)
|
||||
fieldCode.op = op
|
||||
switch op {
|
||||
case opStructFieldHead,
|
||||
opStructFieldHeadOmitEmpty,
|
||||
opStructFieldHeadIndent,
|
||||
opStructFieldHeadOmitEmptyIndent:
|
||||
code = valueCode.beforeLastCode()
|
||||
}
|
||||
} else {
|
||||
fieldCode.op = opStructField
|
||||
code.next = (*opcode)(unsafe.Pointer(fieldCode))
|
||||
prevField.nextField = (*opcode)(unsafe.Pointer(fieldCode))
|
||||
prevField = fieldCode
|
||||
code = (*opcode)(unsafe.Pointer(fieldCode))
|
||||
if isOmitEmpty {
|
||||
fieldCode.op = opStructFieldOmitEmpty
|
||||
switch valueCode.op {
|
||||
case opInt:
|
||||
fieldCode.op = opStructFieldIntOmitEmpty
|
||||
case opInt8:
|
||||
fieldCode.op = opStructFieldInt8OmitEmpty
|
||||
case opInt16:
|
||||
fieldCode.op = opStructFieldInt16OmitEmpty
|
||||
case opInt32:
|
||||
fieldCode.op = opStructFieldInt32OmitEmpty
|
||||
case opInt64:
|
||||
fieldCode.op = opStructFieldInt64OmitEmpty
|
||||
case opUint:
|
||||
fieldCode.op = opStructFieldUintOmitEmpty
|
||||
case opUint8:
|
||||
fieldCode.op = opStructFieldUint8OmitEmpty
|
||||
case opUint16:
|
||||
fieldCode.op = opStructFieldUint16OmitEmpty
|
||||
case opUint32:
|
||||
fieldCode.op = opStructFieldUint32OmitEmpty
|
||||
case opUint64:
|
||||
fieldCode.op = opStructFieldUint64OmitEmpty
|
||||
case opFloat32:
|
||||
fieldCode.op = opStructFieldFloat32OmitEmpty
|
||||
case opFloat64:
|
||||
fieldCode.op = opStructFieldFloat64OmitEmpty
|
||||
case opString:
|
||||
fieldCode.op = opStructFieldStringOmitEmpty
|
||||
case opBool:
|
||||
fieldCode.op = opStructFieldBoolOmitEmpty
|
||||
default:
|
||||
code = valueCode.beforeLastCode()
|
||||
}
|
||||
} else {
|
||||
switch valueCode.op {
|
||||
case opInt:
|
||||
fieldCode.op = opStructFieldInt
|
||||
case opInt8:
|
||||
fieldCode.op = opStructFieldInt8
|
||||
case opInt16:
|
||||
fieldCode.op = opStructFieldInt16
|
||||
case opInt32:
|
||||
fieldCode.op = opStructFieldInt32
|
||||
case opInt64:
|
||||
fieldCode.op = opStructFieldInt64
|
||||
case opUint:
|
||||
fieldCode.op = opStructFieldUint
|
||||
case opUint8:
|
||||
fieldCode.op = opStructFieldUint8
|
||||
case opUint16:
|
||||
fieldCode.op = opStructFieldUint16
|
||||
case opUint32:
|
||||
fieldCode.op = opStructFieldUint32
|
||||
case opUint64:
|
||||
fieldCode.op = opStructFieldUint64
|
||||
case opFloat32:
|
||||
fieldCode.op = opStructFieldFloat32
|
||||
case opFloat64:
|
||||
fieldCode.op = opStructFieldFloat64
|
||||
case opString:
|
||||
fieldCode.op = opStructFieldString
|
||||
case opBool:
|
||||
fieldCode.op = opStructFieldBool
|
||||
default:
|
||||
code = valueCode.beforeLastCode()
|
||||
}
|
||||
op := e.optimizeStructField(valueCode.op, isOmitEmpty, withIndent)
|
||||
fieldCode.op = op
|
||||
switch op {
|
||||
case opStructField,
|
||||
opStructFieldOmitEmpty,
|
||||
opStructFieldIndent,
|
||||
opStructFieldOmitEmptyIndent:
|
||||
code = valueCode.beforeLastCode()
|
||||
}
|
||||
}
|
||||
fieldIdx++
|
||||
}
|
||||
e.indent--
|
||||
|
||||
structEndCode := newOpCode(opStructEnd, nil, nil)
|
||||
structEndCode := newOpCode(opStructEnd, nil, e.indent, nil)
|
||||
|
||||
if withIndent {
|
||||
structEndCode.op = opStructEndIndent
|
||||
}
|
||||
|
||||
if prevField != nil && prevField.nextField == nil {
|
||||
prevField.nextField = structEndCode
|
||||
|
@ -517,15 +793,19 @@ func (e *Encoder) compileStruct(typ *rtype) (*opcode, error) {
|
|||
if head == nil {
|
||||
head = &structFieldCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opStructFieldHead,
|
||||
typ: typ,
|
||||
op: opStructFieldHead,
|
||||
typ: typ,
|
||||
indent: e.indent,
|
||||
},
|
||||
nextField: structEndCode,
|
||||
}
|
||||
if withIndent {
|
||||
head.op = opStructFieldHeadIndent
|
||||
}
|
||||
code = (*opcode)(unsafe.Pointer(head))
|
||||
}
|
||||
head.end = structEndCode
|
||||
code.next = structEndCode
|
||||
structEndCode.next = newEndOp()
|
||||
structEndCode.next = newEndOp(e.indent)
|
||||
return (*opcode)(unsafe.Pointer(head)), nil
|
||||
}
|
||||
|
|
392
encode_opcode.go
392
encode_opcode.go
|
@ -27,17 +27,33 @@ const (
|
|||
opBool
|
||||
opInterface
|
||||
opPtr
|
||||
|
||||
opSliceHead
|
||||
opSliceElem
|
||||
opSliceEnd
|
||||
|
||||
opSliceHeadIndent
|
||||
opSliceElemIndent
|
||||
opSliceEndIndent
|
||||
|
||||
opArrayHead
|
||||
opArrayElem
|
||||
opArrayEnd
|
||||
|
||||
opArrayHeadIndent
|
||||
opArrayElemIndent
|
||||
opArrayEndIndent
|
||||
|
||||
opMapHead
|
||||
opMapKey
|
||||
opMapValue
|
||||
opMapEnd
|
||||
|
||||
opMapHeadIndent
|
||||
opMapKeyIndent
|
||||
opMapValueIndent
|
||||
opMapEndIndent
|
||||
|
||||
// StructFieldHead
|
||||
opStructFieldHead
|
||||
opStructFieldHeadInt
|
||||
|
@ -55,6 +71,22 @@ const (
|
|||
opStructFieldHeadString
|
||||
opStructFieldHeadBool
|
||||
|
||||
opStructFieldHeadIndent
|
||||
opStructFieldHeadIntIndent
|
||||
opStructFieldHeadInt8Indent
|
||||
opStructFieldHeadInt16Indent
|
||||
opStructFieldHeadInt32Indent
|
||||
opStructFieldHeadInt64Indent
|
||||
opStructFieldHeadUintIndent
|
||||
opStructFieldHeadUint8Indent
|
||||
opStructFieldHeadUint16Indent
|
||||
opStructFieldHeadUint32Indent
|
||||
opStructFieldHeadUint64Indent
|
||||
opStructFieldHeadFloat32Indent
|
||||
opStructFieldHeadFloat64Indent
|
||||
opStructFieldHeadStringIndent
|
||||
opStructFieldHeadBoolIndent
|
||||
|
||||
// StructFieldHead with omitempty
|
||||
opStructFieldHeadOmitEmpty
|
||||
opStructFieldHeadIntOmitEmpty
|
||||
|
@ -72,6 +104,22 @@ const (
|
|||
opStructFieldHeadStringOmitEmpty
|
||||
opStructFieldHeadBoolOmitEmpty
|
||||
|
||||
opStructFieldHeadOmitEmptyIndent
|
||||
opStructFieldHeadIntOmitEmptyIndent
|
||||
opStructFieldHeadInt8OmitEmptyIndent
|
||||
opStructFieldHeadInt16OmitEmptyIndent
|
||||
opStructFieldHeadInt32OmitEmptyIndent
|
||||
opStructFieldHeadInt64OmitEmptyIndent
|
||||
opStructFieldHeadUintOmitEmptyIndent
|
||||
opStructFieldHeadUint8OmitEmptyIndent
|
||||
opStructFieldHeadUint16OmitEmptyIndent
|
||||
opStructFieldHeadUint32OmitEmptyIndent
|
||||
opStructFieldHeadUint64OmitEmptyIndent
|
||||
opStructFieldHeadFloat32OmitEmptyIndent
|
||||
opStructFieldHeadFloat64OmitEmptyIndent
|
||||
opStructFieldHeadStringOmitEmptyIndent
|
||||
opStructFieldHeadBoolOmitEmptyIndent
|
||||
|
||||
// StructFieldHead for pointer structure
|
||||
opStructFieldPtrHead
|
||||
opStructFieldPtrHeadInt
|
||||
|
@ -89,6 +137,22 @@ const (
|
|||
opStructFieldPtrHeadString
|
||||
opStructFieldPtrHeadBool
|
||||
|
||||
opStructFieldPtrHeadIndent
|
||||
opStructFieldPtrHeadIntIndent
|
||||
opStructFieldPtrHeadInt8Indent
|
||||
opStructFieldPtrHeadInt16Indent
|
||||
opStructFieldPtrHeadInt32Indent
|
||||
opStructFieldPtrHeadInt64Indent
|
||||
opStructFieldPtrHeadUintIndent
|
||||
opStructFieldPtrHeadUint8Indent
|
||||
opStructFieldPtrHeadUint16Indent
|
||||
opStructFieldPtrHeadUint32Indent
|
||||
opStructFieldPtrHeadUint64Indent
|
||||
opStructFieldPtrHeadFloat32Indent
|
||||
opStructFieldPtrHeadFloat64Indent
|
||||
opStructFieldPtrHeadStringIndent
|
||||
opStructFieldPtrHeadBoolIndent
|
||||
|
||||
// StructFieldPtrHead with omitempty
|
||||
opStructFieldPtrHeadOmitEmpty
|
||||
opStructFieldPtrHeadIntOmitEmpty
|
||||
|
@ -106,6 +170,22 @@ const (
|
|||
opStructFieldPtrHeadStringOmitEmpty
|
||||
opStructFieldPtrHeadBoolOmitEmpty
|
||||
|
||||
opStructFieldPtrHeadOmitEmptyIndent
|
||||
opStructFieldPtrHeadIntOmitEmptyIndent
|
||||
opStructFieldPtrHeadInt8OmitEmptyIndent
|
||||
opStructFieldPtrHeadInt16OmitEmptyIndent
|
||||
opStructFieldPtrHeadInt32OmitEmptyIndent
|
||||
opStructFieldPtrHeadInt64OmitEmptyIndent
|
||||
opStructFieldPtrHeadUintOmitEmptyIndent
|
||||
opStructFieldPtrHeadUint8OmitEmptyIndent
|
||||
opStructFieldPtrHeadUint16OmitEmptyIndent
|
||||
opStructFieldPtrHeadUint32OmitEmptyIndent
|
||||
opStructFieldPtrHeadUint64OmitEmptyIndent
|
||||
opStructFieldPtrHeadFloat32OmitEmptyIndent
|
||||
opStructFieldPtrHeadFloat64OmitEmptyIndent
|
||||
opStructFieldPtrHeadStringOmitEmptyIndent
|
||||
opStructFieldPtrHeadBoolOmitEmptyIndent
|
||||
|
||||
// StructField
|
||||
opStructField
|
||||
opStructFieldInt
|
||||
|
@ -123,6 +203,22 @@ const (
|
|||
opStructFieldString
|
||||
opStructFieldBool
|
||||
|
||||
opStructFieldIndent
|
||||
opStructFieldIntIndent
|
||||
opStructFieldInt8Indent
|
||||
opStructFieldInt16Indent
|
||||
opStructFieldInt32Indent
|
||||
opStructFieldInt64Indent
|
||||
opStructFieldUintIndent
|
||||
opStructFieldUint8Indent
|
||||
opStructFieldUint16Indent
|
||||
opStructFieldUint32Indent
|
||||
opStructFieldUint64Indent
|
||||
opStructFieldFloat32Indent
|
||||
opStructFieldFloat64Indent
|
||||
opStructFieldStringIndent
|
||||
opStructFieldBoolIndent
|
||||
|
||||
// StructField with omitempty
|
||||
opStructFieldOmitEmpty
|
||||
opStructFieldIntOmitEmpty
|
||||
|
@ -140,7 +236,24 @@ const (
|
|||
opStructFieldStringOmitEmpty
|
||||
opStructFieldBoolOmitEmpty
|
||||
|
||||
opStructFieldOmitEmptyIndent
|
||||
opStructFieldIntOmitEmptyIndent
|
||||
opStructFieldInt8OmitEmptyIndent
|
||||
opStructFieldInt16OmitEmptyIndent
|
||||
opStructFieldInt32OmitEmptyIndent
|
||||
opStructFieldInt64OmitEmptyIndent
|
||||
opStructFieldUintOmitEmptyIndent
|
||||
opStructFieldUint8OmitEmptyIndent
|
||||
opStructFieldUint16OmitEmptyIndent
|
||||
opStructFieldUint32OmitEmptyIndent
|
||||
opStructFieldUint64OmitEmptyIndent
|
||||
opStructFieldFloat32OmitEmptyIndent
|
||||
opStructFieldFloat64OmitEmptyIndent
|
||||
opStructFieldStringOmitEmptyIndent
|
||||
opStructFieldBoolOmitEmptyIndent
|
||||
|
||||
opStructEnd
|
||||
opStructEndIndent
|
||||
)
|
||||
|
||||
func (t opType) String() string {
|
||||
|
@ -179,19 +292,36 @@ func (t opType) String() string {
|
|||
return "INTERFACE"
|
||||
case opPtr:
|
||||
return "PTR"
|
||||
|
||||
case opSliceHead:
|
||||
return "SLICE_HEAD"
|
||||
case opSliceElem:
|
||||
return "SLICE_ELEM"
|
||||
case opSliceEnd:
|
||||
return "SLICE_END"
|
||||
|
||||
case opSliceHeadIndent:
|
||||
return "SLICE_HEAD_INDENT"
|
||||
case opSliceElemIndent:
|
||||
return "SLICE_ELEM_INDENT"
|
||||
case opSliceEndIndent:
|
||||
return "SLICE_END_INDENT"
|
||||
|
||||
case opArrayHead:
|
||||
return "ARRAY_HEAD"
|
||||
case opArrayElem:
|
||||
return "ARRAY_ELEM"
|
||||
case opArrayEnd:
|
||||
return "ARRAY_END"
|
||||
|
||||
case opArrayHeadIndent:
|
||||
return "ARRAY_HEAD_INDENT"
|
||||
case opArrayElemIndent:
|
||||
return "ARRAY_ELEM_INDENT"
|
||||
case opArrayEndIndent:
|
||||
return "ARRAY_END_INDENT"
|
||||
case opMapHead:
|
||||
|
||||
return "MAP_HEAD"
|
||||
case opMapKey:
|
||||
return "MAP_KEY"
|
||||
|
@ -200,6 +330,15 @@ func (t opType) String() string {
|
|||
case opMapEnd:
|
||||
return "MAP_END"
|
||||
|
||||
case opMapHeadIndent:
|
||||
return "MAP_HEAD_INDENT"
|
||||
case opMapKeyIndent:
|
||||
return "MAP_KEY_INDENT"
|
||||
case opMapValueIndent:
|
||||
return "MAP_VALUE_INDENT"
|
||||
case opMapEndIndent:
|
||||
return "MAP_END_INDENT"
|
||||
|
||||
case opStructFieldHead:
|
||||
return "STRUCT_FIELD_HEAD"
|
||||
case opStructFieldHeadInt:
|
||||
|
@ -231,6 +370,37 @@ func (t opType) String() string {
|
|||
case opStructFieldHeadBool:
|
||||
return "STRUCT_FIELD_HEAD_BOOL"
|
||||
|
||||
case opStructFieldHeadIndent:
|
||||
return "STRUCT_FIELD_HEAD_INDENT"
|
||||
case opStructFieldHeadIntIndent:
|
||||
return "STRUCT_FIELD_HEAD_INT_INDENT"
|
||||
case opStructFieldHeadInt8Indent:
|
||||
return "STRUCT_FIELD_HEAD_INT8_INDENT"
|
||||
case opStructFieldHeadInt16Indent:
|
||||
return "STRUCT_FIELD_HEAD_INT16_INDENT"
|
||||
case opStructFieldHeadInt32Indent:
|
||||
return "STRUCT_FIELD_HEAD_INT32_INDENT"
|
||||
case opStructFieldHeadInt64Indent:
|
||||
return "STRUCT_FIELD_HEAD_INT64_INDENT"
|
||||
case opStructFieldHeadUintIndent:
|
||||
return "STRUCT_FIELD_HEAD_UINT_INDENT"
|
||||
case opStructFieldHeadUint8Indent:
|
||||
return "STRUCT_FIELD_HEAD_UINT8_INDENT"
|
||||
case opStructFieldHeadUint16Indent:
|
||||
return "STRUCT_FIELD_HEAD_UINT16_INDENT"
|
||||
case opStructFieldHeadUint32Indent:
|
||||
return "STRUCT_FIELD_HEAD_UINT32_INDENT"
|
||||
case opStructFieldHeadUint64Indent:
|
||||
return "STRUCT_FIELD_HEAD_UINT64_INDENT"
|
||||
case opStructFieldHeadFloat32Indent:
|
||||
return "STRUCT_FIELD_HEAD_FLOAT32_INDENT"
|
||||
case opStructFieldHeadFloat64Indent:
|
||||
return "STRUCT_FIELD_HEAD_FLOAT64_INDENT"
|
||||
case opStructFieldHeadStringIndent:
|
||||
return "STRUCT_FIELD_HEAD_STRING_INDENT"
|
||||
case opStructFieldHeadBoolIndent:
|
||||
return "STRUCT_FIELD_HEAD_BOOL_INDENT"
|
||||
|
||||
case opStructFieldHeadOmitEmpty:
|
||||
return "STRUCT_FIELD_HEAD_OMIT_EMPTY"
|
||||
case opStructFieldHeadIntOmitEmpty:
|
||||
|
@ -262,6 +432,37 @@ func (t opType) String() string {
|
|||
case opStructFieldHeadBoolOmitEmpty:
|
||||
return "STRUCT_FIELD_HEAD_BOOL_OMIT_EMPTY"
|
||||
|
||||
case opStructFieldHeadOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadIntOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_INT_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadInt8OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_INT8_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadInt16OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_INT16_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadInt32OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_INT32_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadInt64OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_INT64_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadUintOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_UINT_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadUint8OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_UINT8_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadUint16OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_UINT16_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadUint32OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_UINT32_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadUint64OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_UINT64_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadFloat32OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_FLOAT32_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadFloat64OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_FLOAT64_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadStringOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_STRING_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldHeadBoolOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_HEAD_BOOL_OMIT_EMPTY_INDENT"
|
||||
|
||||
case opStructFieldPtrHead:
|
||||
return "STRUCT_FIELD_PTR_HEAD"
|
||||
case opStructFieldPtrHeadInt:
|
||||
|
@ -293,6 +494,37 @@ func (t opType) String() string {
|
|||
case opStructFieldPtrHeadBool:
|
||||
return "STRUCT_FIELD_PTR_HEAD_BOOL"
|
||||
|
||||
case opStructFieldPtrHeadIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_INDENT"
|
||||
case opStructFieldPtrHeadIntIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_INT_INDENT"
|
||||
case opStructFieldPtrHeadInt8Indent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_INT8_INDENT"
|
||||
case opStructFieldPtrHeadInt16Indent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_INT16_INDENT"
|
||||
case opStructFieldPtrHeadInt32Indent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_INT32_INDENT"
|
||||
case opStructFieldPtrHeadInt64Indent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_INT64_INDENT"
|
||||
case opStructFieldPtrHeadUintIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_UINT_INDENT"
|
||||
case opStructFieldPtrHeadUint8Indent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_UINT8_INDENT"
|
||||
case opStructFieldPtrHeadUint16Indent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_UINT16_INDENT"
|
||||
case opStructFieldPtrHeadUint32Indent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_UINT32_INDENT"
|
||||
case opStructFieldPtrHeadUint64Indent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_UINT64_INDENT"
|
||||
case opStructFieldPtrHeadFloat32Indent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_FLOAT32_INDENT"
|
||||
case opStructFieldPtrHeadFloat64Indent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_FLOAT64_INDENT"
|
||||
case opStructFieldPtrHeadStringIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_STRING_INDENT"
|
||||
case opStructFieldPtrHeadBoolIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_BOOL_INDENT"
|
||||
|
||||
case opStructFieldPtrHeadOmitEmpty:
|
||||
return "STRUCT_FIELD_PTR_HEAD_OMIT_EMPTY"
|
||||
case opStructFieldPtrHeadIntOmitEmpty:
|
||||
|
@ -324,6 +556,37 @@ func (t opType) String() string {
|
|||
case opStructFieldPtrHeadBoolOmitEmpty:
|
||||
return "STRUCT_FIELD_PTR_HEAD_BOOL_OMIT_EMPTY"
|
||||
|
||||
case opStructFieldPtrHeadOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadIntOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_INT_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadInt8OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_INT8_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadInt16OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_INT16_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadInt32OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_INT32_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadInt64OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_INT64_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadUintOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_UINT_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadUint8OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_UINT8_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadUint16OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_UINT16_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadUint32OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_UINT32_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadUint64OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_UINT64_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadFloat32OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_FLOAT32_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadFloat64OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_FLOAT64_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadStringOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_STRING_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldPtrHeadBoolOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_PTR_HEAD_BOOL_OMIT_EMPTY_INDENT"
|
||||
|
||||
case opStructField:
|
||||
return "STRUCT_FIELD"
|
||||
case opStructFieldInt:
|
||||
|
@ -355,6 +618,37 @@ func (t opType) String() string {
|
|||
case opStructFieldBool:
|
||||
return "STRUCT_FIELD_BOOL"
|
||||
|
||||
case opStructFieldIndent:
|
||||
return "STRUCT_FIELD_INDENT"
|
||||
case opStructFieldIntIndent:
|
||||
return "STRUCT_FIELD_INT_INDENT"
|
||||
case opStructFieldInt8Indent:
|
||||
return "STRUCT_FIELD_INT8_INDENT"
|
||||
case opStructFieldInt16Indent:
|
||||
return "STRUCT_FIELD_INT16_INDENT"
|
||||
case opStructFieldInt32Indent:
|
||||
return "STRUCT_FIELD_INT32_INDENT"
|
||||
case opStructFieldInt64Indent:
|
||||
return "STRUCT_FIELD_INT64_INDENT"
|
||||
case opStructFieldUintIndent:
|
||||
return "STRUCT_FIELD_UINT_INDENT"
|
||||
case opStructFieldUint8Indent:
|
||||
return "STRUCT_FIELD_UINT8_INDENT"
|
||||
case opStructFieldUint16Indent:
|
||||
return "STRUCT_FIELD_UINT16_INDENT"
|
||||
case opStructFieldUint32Indent:
|
||||
return "STRUCT_FIELD_UINT32_INDENT"
|
||||
case opStructFieldUint64Indent:
|
||||
return "STRUCT_FIELD_UINT64_INDENT"
|
||||
case opStructFieldFloat32Indent:
|
||||
return "STRUCT_FIELD_FLOAT32_INDENT"
|
||||
case opStructFieldFloat64Indent:
|
||||
return "STRUCT_FIELD_FLOAT64_INDENT"
|
||||
case opStructFieldStringIndent:
|
||||
return "STRUCT_FIELD_STRING_INDENT"
|
||||
case opStructFieldBoolIndent:
|
||||
return "STRUCT_FIELD_BOOL_INDENT"
|
||||
|
||||
case opStructFieldOmitEmpty:
|
||||
return "STRUCT_FIELD_OMIT_EMPTY"
|
||||
case opStructFieldIntOmitEmpty:
|
||||
|
@ -386,35 +680,71 @@ func (t opType) String() string {
|
|||
case opStructFieldBoolOmitEmpty:
|
||||
return "STRUCT_FIELD_BOOL_OMIT_EMPTY"
|
||||
|
||||
case opStructFieldOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldIntOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_INT_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldInt8OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_INT8_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldInt16OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_INT16_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldInt32OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_INT32_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldInt64OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_INT64_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldUintOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_UINT_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldUint8OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_UINT8_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldUint16OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_UINT16_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldUint32OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_UINT32_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldUint64OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_UINT64_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldFloat32OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_FLOAT32_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldFloat64OmitEmptyIndent:
|
||||
return "STRUCT_FIELD_FLOAT64_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldStringOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_STRING_OMIT_EMPTY_INDENT"
|
||||
case opStructFieldBoolOmitEmptyIndent:
|
||||
return "STRUCT_FIELD_BOOL_OMIT_EMPTY_INDENT"
|
||||
|
||||
case opStructEnd:
|
||||
return "STRUCT_END"
|
||||
case opStructEndIndent:
|
||||
return "STRUCT_END_INDENT"
|
||||
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type opcodeHeader struct {
|
||||
op opType
|
||||
typ *rtype
|
||||
ptr uintptr
|
||||
next *opcode
|
||||
op opType
|
||||
typ *rtype
|
||||
ptr uintptr
|
||||
indent int
|
||||
next *opcode
|
||||
}
|
||||
|
||||
type opcode struct {
|
||||
*opcodeHeader
|
||||
}
|
||||
|
||||
func newOpCode(op opType, typ *rtype, next *opcode) *opcode {
|
||||
func newOpCode(op opType, typ *rtype, indent int, next *opcode) *opcode {
|
||||
return &opcode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: op,
|
||||
typ: typ,
|
||||
next: next,
|
||||
op: op,
|
||||
typ: typ,
|
||||
indent: indent,
|
||||
next: next,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newEndOp() *opcode {
|
||||
return newOpCode(opEnd, nil, nil)
|
||||
func newEndOp(indent int) *opcode {
|
||||
return newOpCode(opEnd, nil, indent, nil)
|
||||
}
|
||||
|
||||
func (c *opcode) beforeLastCode() *opcode {
|
||||
|
@ -422,11 +752,11 @@ func (c *opcode) beforeLastCode() *opcode {
|
|||
for {
|
||||
var nextCode *opcode
|
||||
switch code.op {
|
||||
case opArrayElem:
|
||||
case opArrayElem, opArrayElemIndent:
|
||||
nextCode = code.toArrayElemCode().end
|
||||
case opSliceElem:
|
||||
case opSliceElem, opSliceElemIndent:
|
||||
nextCode = code.toSliceElemCode().end
|
||||
case opMapKey:
|
||||
case opMapKey, opMapKeyIndent:
|
||||
nextCode = code.toMapKeyCode().end
|
||||
default:
|
||||
nextCode = code.next
|
||||
|
@ -442,13 +772,14 @@ func (c *opcode) beforeLastCode() *opcode {
|
|||
func (c *opcode) dump() string {
|
||||
codes := []string{}
|
||||
for code := c; code.op != opEnd; {
|
||||
codes = append(codes, fmt.Sprintf("%s", code.op))
|
||||
indent := strings.Repeat(" ", code.indent)
|
||||
codes = append(codes, fmt.Sprintf("%s%s", indent, code.op))
|
||||
switch code.op {
|
||||
case opArrayElem:
|
||||
case opArrayElem, opArrayElemIndent:
|
||||
code = code.toArrayElemCode().end
|
||||
case opSliceElem:
|
||||
case opSliceElem, opSliceElemIndent:
|
||||
code = code.toSliceElemCode().end
|
||||
case opMapKey:
|
||||
case opMapKey, opMapKeyIndent:
|
||||
code = code.toMapKeyCode().end
|
||||
default:
|
||||
code = code.next
|
||||
|
@ -495,10 +826,11 @@ type sliceHeaderCode struct {
|
|||
end *opcode
|
||||
}
|
||||
|
||||
func newSliceHeaderCode() *sliceHeaderCode {
|
||||
func newSliceHeaderCode(indent int) *sliceHeaderCode {
|
||||
return &sliceHeaderCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opSliceHead,
|
||||
op: opSliceHead,
|
||||
indent: indent,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -525,10 +857,11 @@ type arrayHeaderCode struct {
|
|||
end *opcode
|
||||
}
|
||||
|
||||
func newArrayHeaderCode(alen int) *arrayHeaderCode {
|
||||
func newArrayHeaderCode(indent, alen int) *arrayHeaderCode {
|
||||
return &arrayHeaderCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opArrayHead,
|
||||
op: opArrayHead,
|
||||
indent: indent,
|
||||
},
|
||||
len: uintptr(alen),
|
||||
}
|
||||
|
@ -580,27 +913,30 @@ func (c *mapValueCode) set(iter unsafe.Pointer) {
|
|||
c.iter = iter
|
||||
}
|
||||
|
||||
func newMapHeaderCode(typ *rtype) *mapHeaderCode {
|
||||
func newMapHeaderCode(typ *rtype, indent int) *mapHeaderCode {
|
||||
return &mapHeaderCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opMapHead,
|
||||
typ: typ,
|
||||
op: opMapHead,
|
||||
typ: typ,
|
||||
indent: indent,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newMapKeyCode() *mapKeyCode {
|
||||
func newMapKeyCode(indent int) *mapKeyCode {
|
||||
return &mapKeyCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opMapKey,
|
||||
op: opMapKey,
|
||||
indent: indent,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newMapValueCode() *mapValueCode {
|
||||
func newMapValueCode(indent int) *mapValueCode {
|
||||
return &mapValueCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opMapValue,
|
||||
op: opMapValue,
|
||||
indent: indent,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
func Test_Encoder(t *testing.T) {
|
||||
func Test_Marshal(t *testing.T) {
|
||||
t.Run("int", func(t *testing.T) {
|
||||
bytes, err := json.Marshal(-10)
|
||||
assertErr(t, err)
|
||||
|
@ -205,3 +205,77 @@ func Test_Encoder(t *testing.T) {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_MarshalIndent(t *testing.T) {
|
||||
prefix := "-"
|
||||
indent := "\t"
|
||||
t.Run("struct", func(t *testing.T) {
|
||||
bytes, err := json.MarshalIndent(struct {
|
||||
A int `json:"a"`
|
||||
B uint `json:"b"`
|
||||
C string `json:"c"`
|
||||
D int `json:"-"` // ignore field
|
||||
a int `json:"aa"` // private field
|
||||
}{
|
||||
A: -1,
|
||||
B: 1,
|
||||
C: "hello world",
|
||||
}, prefix, indent)
|
||||
assertErr(t, err)
|
||||
result := "{\n-\t\"a\": -1,\n-\t\"b\": 1,\n-\t\"c\": \"hello world\"\n-}"
|
||||
assertEq(t, "struct", result, string(bytes))
|
||||
})
|
||||
t.Run("slice", func(t *testing.T) {
|
||||
t.Run("[]int", func(t *testing.T) {
|
||||
bytes, err := json.MarshalIndent([]int{1, 2, 3, 4}, prefix, indent)
|
||||
assertErr(t, err)
|
||||
result := "[\n-\t1,\n-\t2,\n-\t3,\n-\t4\n-]"
|
||||
assertEq(t, "[]int", result, string(bytes))
|
||||
})
|
||||
t.Run("[]interface{}", func(t *testing.T) {
|
||||
bytes, err := json.MarshalIndent([]interface{}{1, 2.1, "hello"}, prefix, indent)
|
||||
assertErr(t, err)
|
||||
result := "[\n-\t1,\n-\t2.1,\n-\t\"hello\"\n-]"
|
||||
assertEq(t, "[]interface{}", result, string(bytes))
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("array", func(t *testing.T) {
|
||||
bytes, err := json.MarshalIndent([4]int{1, 2, 3, 4}, prefix, indent)
|
||||
assertErr(t, err)
|
||||
result := "[\n-\t1,\n-\t2,\n-\t3,\n-\t4\n-]"
|
||||
assertEq(t, "array", result, string(bytes))
|
||||
})
|
||||
t.Run("map", func(t *testing.T) {
|
||||
t.Run("map[string]int", func(t *testing.T) {
|
||||
bytes, err := json.MarshalIndent(map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
}, prefix, indent)
|
||||
assertErr(t, err)
|
||||
result := "{\n-\t\"a\": 1,\n-\t\"b\": 2,\n-\t\"c\": 3,\n-\t\"d\": 4\n-}"
|
||||
assertEq(t, "map", len(result), len(string(bytes)))
|
||||
})
|
||||
t.Run("map[string]interface{}", func(t *testing.T) {
|
||||
type T struct {
|
||||
E int
|
||||
F int
|
||||
}
|
||||
v := map[string]interface{}{
|
||||
"a": 1,
|
||||
"b": 2.1,
|
||||
"c": &T{
|
||||
E: 10,
|
||||
F: 11,
|
||||
},
|
||||
"d": 4,
|
||||
}
|
||||
bytes, err := json.MarshalIndent(v, prefix, indent)
|
||||
assertErr(t, err)
|
||||
result := "{\n-\t\"a\": 1,\n-\t\"b\": 2.1,\n-\t\"c\": {\n-\t\t\"E\": 10,\n-\t\t\"F\": 11\n-\t},\n-\t\"d\": 4\n-}"
|
||||
assertEq(t, "map[string]interface{}", len(result), len(string(bytes)))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
1210
encode_vm.go
1210
encode_vm.go
File diff suppressed because it is too large
Load Diff
14
json.go
14
json.go
|
@ -5,6 +5,20 @@ import "bytes"
|
|||
func Marshal(v interface{}) ([]byte, error) {
|
||||
var b *bytes.Buffer
|
||||
enc := NewEncoder(b)
|
||||
enc.SetIndent("", "")
|
||||
bytes, err := enc.encodeForMarshal(v)
|
||||
if err != nil {
|
||||
enc.release()
|
||||
return nil, err
|
||||
}
|
||||
enc.release()
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
|
||||
var b *bytes.Buffer
|
||||
enc := NewEncoder(b)
|
||||
enc.SetIndent(prefix, indent)
|
||||
bytes, err := enc.encodeForMarshal(v)
|
||||
if err != nil {
|
||||
enc.release()
|
||||
|
|
Loading…
Reference in New Issue