forked from mirror/go-json
Merge pull request #1 from goccy/feature/encode-vm
Support VirtualMachine for encoding
This commit is contained in:
commit
6a479c7159
635
encode.go
635
encode.go
|
@ -1,15 +1,11 @@
|
||||||
package json
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// An Encoder writes JSON values to an output stream.
|
// An Encoder writes JSON values to an output stream.
|
||||||
|
@ -19,31 +15,28 @@ type Encoder struct {
|
||||||
pool sync.Pool
|
pool sync.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
type EncodeOp func(*Encoder, *rtype, uintptr) error
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
bufSize = 1024
|
bufSize = 1024
|
||||||
)
|
)
|
||||||
|
|
||||||
type EncodeOpMap struct {
|
type opcodeMap struct {
|
||||||
sync.Map
|
sync.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *EncodeOpMap) Get(k string) EncodeOp {
|
func (m *opcodeMap) Get(k string) *opcode {
|
||||||
if v, ok := m.Load(k); ok {
|
if v, ok := m.Load(k); ok {
|
||||||
return v.(EncodeOp)
|
return v.(*opcode)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *EncodeOpMap) Set(k string, op EncodeOp) {
|
func (m *opcodeMap) Set(k string, op *opcode) {
|
||||||
m.Store(k, op)
|
m.Store(k, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
encPool sync.Pool
|
encPool sync.Pool
|
||||||
cachedEncodeOp EncodeOpMap
|
cachedOpcode opcodeMap
|
||||||
errCompileSlowPath = xerrors.New("json: detect dynamic type ( interface{} ) and compile with slow path")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -55,7 +48,7 @@ func init() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cachedEncodeOp = EncodeOpMap{}
|
cachedOpcode = opcodeMap{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEncoder returns a new encoder that writes to w.
|
// NewEncoder returns a new encoder that writes to w.
|
||||||
|
@ -163,6 +156,10 @@ func (e *Encoder) encodeBool(v bool) {
|
||||||
e.buf = strconv.AppendBool(e.buf, v)
|
e.buf = strconv.AppendBool(e.buf, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) encodeBytes(b []byte) {
|
||||||
|
e.buf = append(e.buf, b...)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Encoder) encodeString(s string) {
|
func (e *Encoder) encodeString(s string) {
|
||||||
b := *(*[]byte)(unsafe.Pointer(&s))
|
b := *(*[]byte)(unsafe.Pointer(&s))
|
||||||
e.buf = append(e.buf, b...)
|
e.buf = append(e.buf, b...)
|
||||||
|
@ -179,616 +176,22 @@ func (e *Encoder) encode(v interface{}) error {
|
||||||
typ = typ.Elem()
|
typ = typ.Elem()
|
||||||
}
|
}
|
||||||
name := typ.String()
|
name := typ.String()
|
||||||
if op := cachedEncodeOp.Get(name); op != nil {
|
if code := cachedOpcode.Get(name); code != nil {
|
||||||
p := uintptr(header.ptr)
|
p := uintptr(header.ptr)
|
||||||
op(e, typ, p)
|
code.ptr = p
|
||||||
|
if err := e.run(code); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
op, err := e.compile(typ)
|
code, err := e.compile(typ)
|
||||||
if err != nil {
|
|
||||||
if err == errCompileSlowPath {
|
|
||||||
slowOp, err := e.compileSlowPath(typ)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
op = slowOp
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if name != "" {
|
if name != "" {
|
||||||
cachedEncodeOp.Set(name, op)
|
cachedOpcode.Set(name, code)
|
||||||
}
|
}
|
||||||
p := uintptr(header.ptr)
|
p := uintptr(header.ptr)
|
||||||
op(e, typ, p)
|
code.ptr = p
|
||||||
return nil
|
return e.run(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compile(typ *rtype) (EncodeOp, error) {
|
|
||||||
switch typ.Kind() {
|
|
||||||
case reflect.Ptr:
|
|
||||||
return e.compilePtr(typ)
|
|
||||||
case reflect.Slice:
|
|
||||||
return e.compileSlice(typ)
|
|
||||||
case reflect.Struct:
|
|
||||||
return e.compileStruct(typ)
|
|
||||||
case reflect.Map:
|
|
||||||
return e.compileMap(typ)
|
|
||||||
case reflect.Array:
|
|
||||||
return e.compileArray(typ)
|
|
||||||
case reflect.Int:
|
|
||||||
return e.compileInt()
|
|
||||||
case reflect.Int8:
|
|
||||||
return e.compileInt8()
|
|
||||||
case reflect.Int16:
|
|
||||||
return e.compileInt16()
|
|
||||||
case reflect.Int32:
|
|
||||||
return e.compileInt32()
|
|
||||||
case reflect.Int64:
|
|
||||||
return e.compileInt64()
|
|
||||||
case reflect.Uint:
|
|
||||||
return e.compileUint()
|
|
||||||
case reflect.Uint8:
|
|
||||||
return e.compileUint8()
|
|
||||||
case reflect.Uint16:
|
|
||||||
return e.compileUint16()
|
|
||||||
case reflect.Uint32:
|
|
||||||
return e.compileUint32()
|
|
||||||
case reflect.Uint64:
|
|
||||||
return e.compileUint64()
|
|
||||||
case reflect.Uintptr:
|
|
||||||
return e.compileUint()
|
|
||||||
case reflect.Float32:
|
|
||||||
return e.compileFloat32()
|
|
||||||
case reflect.Float64:
|
|
||||||
return e.compileFloat64()
|
|
||||||
case reflect.String:
|
|
||||||
return e.compileString()
|
|
||||||
case reflect.Bool:
|
|
||||||
return e.compileBool()
|
|
||||||
case reflect.Interface:
|
|
||||||
return nil, errCompileSlowPath
|
|
||||||
}
|
|
||||||
return nil, xerrors.Errorf("failed to encode type %s: %w", typ.String(), ErrUnsupportedType)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileSlowPath(typ *rtype) (EncodeOp, error) {
|
|
||||||
switch typ.Kind() {
|
|
||||||
case reflect.Ptr:
|
|
||||||
return e.compilePtrSlowPath(typ)
|
|
||||||
case reflect.Slice:
|
|
||||||
return e.compileSliceSlowPath(typ)
|
|
||||||
case reflect.Struct:
|
|
||||||
return e.compileStructSlowPath(typ)
|
|
||||||
case reflect.Map:
|
|
||||||
return e.compileMapSlowPath(typ)
|
|
||||||
case reflect.Array:
|
|
||||||
return e.compileArraySlowPath(typ)
|
|
||||||
case reflect.Int:
|
|
||||||
return e.compileInt()
|
|
||||||
case reflect.Int8:
|
|
||||||
return e.compileInt8()
|
|
||||||
case reflect.Int16:
|
|
||||||
return e.compileInt16()
|
|
||||||
case reflect.Int32:
|
|
||||||
return e.compileInt32()
|
|
||||||
case reflect.Int64:
|
|
||||||
return e.compileInt64()
|
|
||||||
case reflect.Uint:
|
|
||||||
return e.compileUint()
|
|
||||||
case reflect.Uint8:
|
|
||||||
return e.compileUint8()
|
|
||||||
case reflect.Uint16:
|
|
||||||
return e.compileUint16()
|
|
||||||
case reflect.Uint32:
|
|
||||||
return e.compileUint32()
|
|
||||||
case reflect.Uint64:
|
|
||||||
return e.compileUint64()
|
|
||||||
case reflect.Uintptr:
|
|
||||||
return e.compileUint()
|
|
||||||
case reflect.Float32:
|
|
||||||
return e.compileFloat32()
|
|
||||||
case reflect.Float64:
|
|
||||||
return e.compileFloat64()
|
|
||||||
case reflect.String:
|
|
||||||
return e.compileString()
|
|
||||||
case reflect.Bool:
|
|
||||||
return e.compileBool()
|
|
||||||
case reflect.Interface:
|
|
||||||
return e.compileInterface()
|
|
||||||
}
|
|
||||||
return nil, xerrors.Errorf("failed to encode type %s: %w", typ.String(), ErrUnsupportedType)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compilePtr(typ *rtype) (EncodeOp, error) {
|
|
||||||
elem := typ.Elem()
|
|
||||||
op, err := e.compile(elem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
return op(enc, elem, e.ptrToPtr(p))
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compilePtrSlowPath(typ *rtype) (EncodeOp, error) {
|
|
||||||
elem := typ.Elem()
|
|
||||||
op, err := e.compileSlowPath(elem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
return op(enc, typ.Elem(), e.ptrToPtr(p))
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileInt() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeInt(e.ptrToInt(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileInt8() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeInt8(e.ptrToInt8(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileInt16() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeInt16(e.ptrToInt16(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileInt32() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeInt32(e.ptrToInt32(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileInt64() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeInt64(e.ptrToInt64(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileUint() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeUint(e.ptrToUint(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileUint8() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeUint8(e.ptrToUint8(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileUint16() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeUint16(e.ptrToUint16(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileUint32() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeUint32(e.ptrToUint32(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileUint64() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeUint64(e.ptrToUint64(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileFloat32() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeFloat32(e.ptrToFloat32(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileFloat64() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeFloat64(e.ptrToFloat64(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileString() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeEscapedString(e.ptrToString(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileBool() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, p uintptr) error {
|
|
||||||
enc.encodeBool(e.ptrToBool(p))
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileSlice(typ *rtype) (EncodeOp, error) {
|
|
||||||
elem := typ.Elem()
|
|
||||||
size := elem.Size()
|
|
||||||
op, err := e.compile(elem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return func(enc *Encoder, typ *rtype, base uintptr) error {
|
|
||||||
if base == 0 {
|
|
||||||
enc.encodeString("null")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
enc.encodeByte('[')
|
|
||||||
slice := (*reflect.SliceHeader)(unsafe.Pointer(base))
|
|
||||||
num := slice.Len
|
|
||||||
for i := 0; i < num; i++ {
|
|
||||||
if err := op(enc, elem, slice.Data+uintptr(i)*size); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if i != num-1 {
|
|
||||||
enc.encodeByte(',')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enc.encodeByte(']')
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileSliceSlowPath(typ *rtype) (EncodeOp, error) {
|
|
||||||
op, err := e.compileSlowPath(typ.Elem())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return func(enc *Encoder, typ *rtype, base uintptr) error {
|
|
||||||
if base == 0 {
|
|
||||||
enc.encodeString("null")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
size := typ.Elem().Size()
|
|
||||||
enc.encodeByte('[')
|
|
||||||
slice := (*reflect.SliceHeader)(unsafe.Pointer(base))
|
|
||||||
num := slice.Len
|
|
||||||
for i := 0; i < num; i++ {
|
|
||||||
if err := op(enc, typ.Elem(), slice.Data+uintptr(i)*size); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if i != num-1 {
|
|
||||||
enc.encodeByte(',')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enc.encodeByte(']')
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileArray(typ *rtype) (EncodeOp, error) {
|
|
||||||
elem := typ.Elem()
|
|
||||||
alen := typ.Len()
|
|
||||||
size := elem.Size()
|
|
||||||
op, err := e.compile(elem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return func(enc *Encoder, typ *rtype, base uintptr) error {
|
|
||||||
if base == 0 {
|
|
||||||
enc.encodeString("null")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
enc.encodeByte('[')
|
|
||||||
for i := 0; i < alen; i++ {
|
|
||||||
if i != 0 {
|
|
||||||
enc.encodeByte(',')
|
|
||||||
}
|
|
||||||
if err := op(enc, elem, base+uintptr(i)*size); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enc.encodeByte(']')
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileArraySlowPath(typ *rtype) (EncodeOp, error) {
|
|
||||||
elem := typ.Elem()
|
|
||||||
alen := typ.Len()
|
|
||||||
op, err := e.compileSlowPath(elem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return func(enc *Encoder, typ *rtype, base uintptr) error {
|
|
||||||
if base == 0 {
|
|
||||||
enc.encodeString("null")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
elem := typ.Elem()
|
|
||||||
size := elem.Size()
|
|
||||||
enc.encodeByte('[')
|
|
||||||
for i := 0; i < alen; i++ {
|
|
||||||
if i != 0 {
|
|
||||||
enc.encodeByte(',')
|
|
||||||
}
|
|
||||||
if err := op(enc, elem, base+uintptr(i)*size); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enc.encodeByte(']')
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) getTag(field reflect.StructField) string {
|
|
||||||
return field.Tag.Get("json")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) isIgnoredStructField(field reflect.StructField) bool {
|
|
||||||
if field.PkgPath != "" && !field.Anonymous {
|
|
||||||
// private field
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
tag := e.getTag(field)
|
|
||||||
if tag == "-" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type encodeStructField struct {
|
|
||||||
op EncodeOp
|
|
||||||
fieldIndex int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileStruct(typ *rtype) (EncodeOp, error) {
|
|
||||||
fieldNum := typ.NumField()
|
|
||||||
opQueue := make([]*encodeStructField, 0, fieldNum)
|
|
||||||
|
|
||||||
for i := 0; i < fieldNum; i++ {
|
|
||||||
field := typ.Field(i)
|
|
||||||
if e.isIgnoredStructField(field) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
keyName := field.Name
|
|
||||||
tag := e.getTag(field)
|
|
||||||
opts := strings.Split(tag, ",")
|
|
||||||
if len(opts) > 0 {
|
|
||||||
if opts[0] != "" {
|
|
||||||
keyName = opts[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fieldType := type2rtype(field.Type)
|
|
||||||
op, err := e.compile(fieldType)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
key := fmt.Sprintf(`"%s":`, keyName)
|
|
||||||
structField := &encodeStructField{fieldIndex: i}
|
|
||||||
structField.op = func(enc *Encoder, typ *rtype, base uintptr) error {
|
|
||||||
enc.encodeString(key)
|
|
||||||
return op(enc, fieldType, base+field.Offset)
|
|
||||||
}
|
|
||||||
opQueue = append(opQueue, structField)
|
|
||||||
}
|
|
||||||
|
|
||||||
queueNum := len(opQueue)
|
|
||||||
return func(enc *Encoder, typ *rtype, base uintptr) error {
|
|
||||||
if base == 0 {
|
|
||||||
enc.encodeString("null")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
enc.encodeByte('{')
|
|
||||||
for i := 0; i < queueNum; i++ {
|
|
||||||
if err := opQueue[i].op(enc, typ, base); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if i != queueNum-1 {
|
|
||||||
enc.encodeByte(',')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enc.encodeByte('}')
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileStructSlowPath(typ *rtype) (EncodeOp, error) {
|
|
||||||
fieldNum := typ.NumField()
|
|
||||||
opQueue := make([]*encodeStructField, 0, fieldNum)
|
|
||||||
|
|
||||||
for i := 0; i < fieldNum; i++ {
|
|
||||||
field := typ.Field(i)
|
|
||||||
if e.isIgnoredStructField(field) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
keyName := field.Name
|
|
||||||
tag := e.getTag(field)
|
|
||||||
opts := strings.Split(tag, ",")
|
|
||||||
if len(opts) > 0 {
|
|
||||||
if opts[0] != "" {
|
|
||||||
keyName = opts[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fieldType := type2rtype(field.Type)
|
|
||||||
op, err := e.compileSlowPath(fieldType)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
key := fmt.Sprintf(`"%s":`, keyName)
|
|
||||||
structField := &encodeStructField{fieldIndex: i}
|
|
||||||
structField.op = func(enc *Encoder, typ *rtype, base uintptr) error {
|
|
||||||
enc.encodeString(key)
|
|
||||||
fieldType := type2rtype(typ.Field(structField.fieldIndex).Type)
|
|
||||||
return op(enc, fieldType, base+field.Offset)
|
|
||||||
}
|
|
||||||
opQueue = append(opQueue, structField)
|
|
||||||
}
|
|
||||||
|
|
||||||
queueNum := len(opQueue)
|
|
||||||
return func(enc *Encoder, typ *rtype, base uintptr) error {
|
|
||||||
if base == 0 {
|
|
||||||
enc.encodeString("null")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
enc.encodeByte('{')
|
|
||||||
for i := 0; i < queueNum; i++ {
|
|
||||||
if err := opQueue[i].op(enc, typ, base); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if i != queueNum-1 {
|
|
||||||
enc.encodeByte(',')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enc.encodeByte('}')
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:linkname mapiterinit reflect.mapiterinit
|
|
||||||
//go:noescape
|
|
||||||
func mapiterinit(mapType *rtype, m unsafe.Pointer) unsafe.Pointer
|
|
||||||
|
|
||||||
//go:linkname mapiterkey reflect.mapiterkey
|
|
||||||
//go:noescape
|
|
||||||
func mapiterkey(it unsafe.Pointer) unsafe.Pointer
|
|
||||||
|
|
||||||
//go:linkname mapiternext reflect.mapiternext
|
|
||||||
//go:noescape
|
|
||||||
func mapiternext(it unsafe.Pointer)
|
|
||||||
|
|
||||||
//go:linkname maplen reflect.maplen
|
|
||||||
//go:noescape
|
|
||||||
func maplen(m unsafe.Pointer) int
|
|
||||||
|
|
||||||
type valueType struct {
|
|
||||||
typ unsafe.Pointer
|
|
||||||
ptr unsafe.Pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileMap(typ *rtype) (EncodeOp, error) {
|
|
||||||
keyType := typ.Key()
|
|
||||||
keyOp, err := e.compile(keyType)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
valueType := typ.Elem()
|
|
||||||
valueOp, err := e.compile(valueType)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return func(enc *Encoder, typ *rtype, base uintptr) error {
|
|
||||||
if base == 0 {
|
|
||||||
enc.encodeString("null")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
enc.encodeByte('{')
|
|
||||||
mlen := maplen(unsafe.Pointer(base))
|
|
||||||
iter := mapiterinit(typ, unsafe.Pointer(base))
|
|
||||||
for i := 0; i < mlen; i++ {
|
|
||||||
key := mapiterkey(iter)
|
|
||||||
if i != 0 {
|
|
||||||
enc.encodeByte(',')
|
|
||||||
}
|
|
||||||
value := mapitervalue(iter)
|
|
||||||
keyptr := uintptr(key)
|
|
||||||
if err := keyOp(enc, keyType, keyptr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
enc.encodeByte(':')
|
|
||||||
valueptr := uintptr(value)
|
|
||||||
if err := valueOp(enc, valueType, valueptr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
mapiternext(iter)
|
|
||||||
}
|
|
||||||
enc.encodeByte('}')
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileMapSlowPath(typ *rtype) (EncodeOp, error) {
|
|
||||||
keyOp, err := e.compileSlowPath(typ.Key())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
valueOp, err := e.compileSlowPath(typ.Elem())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return func(enc *Encoder, typ *rtype, base uintptr) error {
|
|
||||||
if base == 0 {
|
|
||||||
enc.encodeString("null")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
enc.encodeByte('{')
|
|
||||||
mlen := maplen(unsafe.Pointer(base))
|
|
||||||
iter := mapiterinit(typ, unsafe.Pointer(base))
|
|
||||||
for i := 0; i < mlen; i++ {
|
|
||||||
key := mapiterkey(iter)
|
|
||||||
if i != 0 {
|
|
||||||
enc.encodeByte(',')
|
|
||||||
}
|
|
||||||
value := mapitervalue(iter)
|
|
||||||
keyptr := uintptr(key)
|
|
||||||
if err := keyOp(enc, typ.Key(), keyptr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
enc.encodeByte(':')
|
|
||||||
valueptr := uintptr(value)
|
|
||||||
if err := valueOp(enc, typ.Elem(), valueptr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
mapiternext(iter)
|
|
||||||
}
|
|
||||||
enc.encodeByte('}')
|
|
||||||
return nil
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) compileInterface() (EncodeOp, error) {
|
|
||||||
return func(enc *Encoder, typ *rtype, base uintptr) error {
|
|
||||||
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
|
||||||
typ: typ,
|
|
||||||
ptr: unsafe.Pointer(base),
|
|
||||||
}))
|
|
||||||
vv := reflect.ValueOf(v).Interface()
|
|
||||||
header := (*interfaceHeader)(unsafe.Pointer(&vv))
|
|
||||||
t := header.typ
|
|
||||||
if t.Kind() == reflect.Ptr {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
op, err := e.compileSlowPath(t)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return op(enc, t, uintptr(header.ptr))
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Encoder) ptrToPtr(p uintptr) uintptr { return *(*uintptr)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToInt(p uintptr) int { return *(*int)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToInt8(p uintptr) int8 { return *(*int8)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToInt16(p uintptr) int16 { return *(*int16)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToInt32(p uintptr) int32 { return *(*int32)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToInt64(p uintptr) int64 { return *(*int64)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToUint(p uintptr) uint { return *(*uint)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToUint8(p uintptr) uint8 { return *(*uint8)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToUint16(p uintptr) uint16 { return *(*uint16)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToUint32(p uintptr) uint32 { return *(*uint32)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToUint64(p uintptr) uint64 { return *(*uint64)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToFloat32(p uintptr) float32 { return *(*float32)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToFloat64(p uintptr) float64 { return *(*float64)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToBool(p uintptr) bool { return *(*bool)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToByte(p uintptr) byte { return *(*byte)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToBytes(p uintptr) []byte { return *(*[]byte)(unsafe.Pointer(p)) }
|
|
||||||
func (e *Encoder) ptrToString(p uintptr) string { return *(*string)(unsafe.Pointer(p)) }
|
|
||||||
|
|
|
@ -0,0 +1,409 @@
|
||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *Encoder) compile(typ *rtype) (*opcode, error) {
|
||||||
|
switch typ.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
return e.compilePtr(typ)
|
||||||
|
case reflect.Slice:
|
||||||
|
return e.compileSlice(typ)
|
||||||
|
case reflect.Array:
|
||||||
|
return e.compileArray(typ)
|
||||||
|
case reflect.Map:
|
||||||
|
return e.compileMap(typ)
|
||||||
|
case reflect.Struct:
|
||||||
|
return e.compileStruct(typ)
|
||||||
|
case reflect.Int:
|
||||||
|
return e.compileInt(typ)
|
||||||
|
case reflect.Int8:
|
||||||
|
return e.compileInt8(typ)
|
||||||
|
case reflect.Int16:
|
||||||
|
return e.compileInt16(typ)
|
||||||
|
case reflect.Int32:
|
||||||
|
return e.compileInt32(typ)
|
||||||
|
case reflect.Int64:
|
||||||
|
return e.compileInt64(typ)
|
||||||
|
case reflect.Uint:
|
||||||
|
return e.compileUint(typ)
|
||||||
|
case reflect.Uint8:
|
||||||
|
return e.compileUint8(typ)
|
||||||
|
case reflect.Uint16:
|
||||||
|
return e.compileUint16(typ)
|
||||||
|
case reflect.Uint32:
|
||||||
|
return e.compileUint32(typ)
|
||||||
|
case reflect.Uint64:
|
||||||
|
return e.compileUint64(typ)
|
||||||
|
case reflect.Uintptr:
|
||||||
|
return e.compileUint(typ)
|
||||||
|
case reflect.Float32:
|
||||||
|
return e.compileFloat32(typ)
|
||||||
|
case reflect.Float64:
|
||||||
|
return e.compileFloat64(typ)
|
||||||
|
case reflect.String:
|
||||||
|
return e.compileString(typ)
|
||||||
|
case reflect.Bool:
|
||||||
|
return e.compileBool(typ)
|
||||||
|
case reflect.Interface:
|
||||||
|
return e.compileInterface(typ)
|
||||||
|
}
|
||||||
|
return nil, xerrors.Errorf("failed to encode type %s: %w", typ.String(), ErrUnsupportedType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) optimizeStructFieldPtrHead(typ *rtype, code *opcode) *opcode {
|
||||||
|
switch code.op {
|
||||||
|
case opStructFieldHead:
|
||||||
|
code.op = opStructFieldPtrHead
|
||||||
|
case opStructFieldHeadInt:
|
||||||
|
code.op = opStructFieldPtrHeadInt
|
||||||
|
case opStructFieldHeadInt8:
|
||||||
|
code.op = opStructFieldPtrHeadInt8
|
||||||
|
case opStructFieldHeadInt16:
|
||||||
|
code.op = opStructFieldPtrHeadInt16
|
||||||
|
case opStructFieldHeadInt32:
|
||||||
|
code.op = opStructFieldPtrHeadInt32
|
||||||
|
case opStructFieldHeadInt64:
|
||||||
|
code.op = opStructFieldPtrHeadInt64
|
||||||
|
case opStructFieldHeadUint:
|
||||||
|
code.op = opStructFieldPtrHeadUint
|
||||||
|
case opStructFieldHeadUint8:
|
||||||
|
code.op = opStructFieldPtrHeadUint8
|
||||||
|
case opStructFieldHeadUint16:
|
||||||
|
code.op = opStructFieldPtrHeadUint16
|
||||||
|
case opStructFieldHeadUint32:
|
||||||
|
code.op = opStructFieldPtrHeadUint32
|
||||||
|
case opStructFieldHeadUint64:
|
||||||
|
code.op = opStructFieldPtrHeadUint64
|
||||||
|
case opStructFieldHeadFloat32:
|
||||||
|
code.op = opStructFieldPtrHeadFloat32
|
||||||
|
case opStructFieldHeadFloat64:
|
||||||
|
code.op = opStructFieldPtrHeadFloat64
|
||||||
|
case opStructFieldHeadString:
|
||||||
|
code.op = opStructFieldPtrHeadString
|
||||||
|
case opStructFieldHeadBool:
|
||||||
|
code.op = opStructFieldPtrHeadBool
|
||||||
|
default:
|
||||||
|
return newOpCode(opPtr, typ, code)
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compilePtr(typ *rtype) (*opcode, error) {
|
||||||
|
code, err := e.compile(typ.Elem())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return e.optimizeStructFieldPtrHead(typ, code), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileInt(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opInt, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileInt8(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opInt8, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileInt16(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opInt16, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileInt32(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opInt32, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileInt64(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opInt64, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileUint(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opUint, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileUint8(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opUint8, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileUint16(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opUint16, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileUint32(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opUint32, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileUint64(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opUint64, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileFloat32(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opFloat32, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileFloat64(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opFloat64, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileString(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opString, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileBool(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opBool, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileInterface(typ *rtype) (*opcode, error) {
|
||||||
|
return newOpCode(opInterface, typ, newEndOp()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileSlice(typ *rtype) (*opcode, error) {
|
||||||
|
elem := typ.Elem()
|
||||||
|
size := elem.Size()
|
||||||
|
code, err := e.compile(elem)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// header => opcode => elem => end
|
||||||
|
// ^ |
|
||||||
|
// |________|
|
||||||
|
|
||||||
|
header := newSliceHeaderCode()
|
||||||
|
elemCode := &sliceElemCode{opcodeHeader: &opcodeHeader{op: opSliceElem}, size: size}
|
||||||
|
end := newOpCode(opSliceEnd, nil, newEndOp())
|
||||||
|
|
||||||
|
header.elem = elemCode
|
||||||
|
header.end = end
|
||||||
|
header.next = code
|
||||||
|
code.beforeLastCode().next = (*opcode)(unsafe.Pointer(elemCode))
|
||||||
|
elemCode.next = code
|
||||||
|
elemCode.end = end
|
||||||
|
return (*opcode)(unsafe.Pointer(header)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileArray(typ *rtype) (*opcode, error) {
|
||||||
|
elem := typ.Elem()
|
||||||
|
alen := typ.Len()
|
||||||
|
size := elem.Size()
|
||||||
|
code, err := e.compile(elem)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// header => opcode => elem => end
|
||||||
|
// ^ |
|
||||||
|
// |________|
|
||||||
|
|
||||||
|
header := newArrayHeaderCode(alen)
|
||||||
|
elemCode := &arrayElemCode{
|
||||||
|
opcodeHeader: &opcodeHeader{
|
||||||
|
op: opArrayElem,
|
||||||
|
},
|
||||||
|
len: uintptr(alen),
|
||||||
|
size: size,
|
||||||
|
}
|
||||||
|
end := newOpCode(opArrayEnd, nil, newEndOp())
|
||||||
|
|
||||||
|
header.elem = elemCode
|
||||||
|
header.end = end
|
||||||
|
header.next = code
|
||||||
|
code.beforeLastCode().next = (*opcode)(unsafe.Pointer(elemCode))
|
||||||
|
elemCode.next = code
|
||||||
|
elemCode.end = end
|
||||||
|
return (*opcode)(unsafe.Pointer(header)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname mapiterinit reflect.mapiterinit
|
||||||
|
//go:noescape
|
||||||
|
func mapiterinit(mapType *rtype, m unsafe.Pointer) unsafe.Pointer
|
||||||
|
|
||||||
|
//go:linkname mapiterkey reflect.mapiterkey
|
||||||
|
//go:noescape
|
||||||
|
func mapiterkey(it unsafe.Pointer) unsafe.Pointer
|
||||||
|
|
||||||
|
//go:linkname mapiternext reflect.mapiternext
|
||||||
|
//go:noescape
|
||||||
|
func mapiternext(it unsafe.Pointer)
|
||||||
|
|
||||||
|
//go:linkname maplen reflect.maplen
|
||||||
|
//go:noescape
|
||||||
|
func maplen(m unsafe.Pointer) int
|
||||||
|
|
||||||
|
func (e *Encoder) compileMap(typ *rtype) (*opcode, error) {
|
||||||
|
// header => code => value => code => key => code => value => code => end
|
||||||
|
// ^ |
|
||||||
|
// |_______________________|
|
||||||
|
keyType := typ.Key()
|
||||||
|
keyCode, err := e.compile(keyType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
valueType := typ.Elem()
|
||||||
|
valueCode, err := e.compile(valueType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
header := newMapHeaderCode(typ)
|
||||||
|
key := newMapKeyCode()
|
||||||
|
value := newMapValueCode()
|
||||||
|
header.key = key
|
||||||
|
header.value = value
|
||||||
|
end := newOpCode(opMapEnd, nil, newEndOp())
|
||||||
|
|
||||||
|
header.next = keyCode
|
||||||
|
keyCode.beforeLastCode().next = (*opcode)(unsafe.Pointer(value))
|
||||||
|
value.next = valueCode
|
||||||
|
valueCode.beforeLastCode().next = (*opcode)(unsafe.Pointer(key))
|
||||||
|
key.next = keyCode
|
||||||
|
|
||||||
|
header.end = end
|
||||||
|
key.end = end
|
||||||
|
|
||||||
|
return (*opcode)(unsafe.Pointer(header)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) getTag(field reflect.StructField) string {
|
||||||
|
return field.Tag.Get("json")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) isIgnoredStructField(field reflect.StructField) bool {
|
||||||
|
if field.PkgPath != "" && !field.Anonymous {
|
||||||
|
// private field
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
tag := e.getTag(field)
|
||||||
|
if tag == "-" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compileStruct(typ *rtype) (*opcode, error) {
|
||||||
|
// header => code => structField => code => end
|
||||||
|
// ^ |
|
||||||
|
// |__________|
|
||||||
|
fieldNum := typ.NumField()
|
||||||
|
fieldIdx := 0
|
||||||
|
var (
|
||||||
|
head *structFieldCode
|
||||||
|
code *opcode
|
||||||
|
prevField *structFieldCode
|
||||||
|
)
|
||||||
|
for i := 0; i < fieldNum; i++ {
|
||||||
|
field := typ.Field(i)
|
||||||
|
if e.isIgnoredStructField(field) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
keyName := field.Name
|
||||||
|
tag := e.getTag(field)
|
||||||
|
opts := strings.Split(tag, ",")
|
||||||
|
if len(opts) > 0 {
|
||||||
|
if opts[0] != "" {
|
||||||
|
keyName = opts[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fieldType := type2rtype(field.Type)
|
||||||
|
valueCode, err := e.compile(fieldType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
key := fmt.Sprintf(`"%s":`, keyName)
|
||||||
|
fieldCode := &structFieldCode{
|
||||||
|
opcodeHeader: &opcodeHeader{
|
||||||
|
typ: fieldType,
|
||||||
|
next: valueCode,
|
||||||
|
},
|
||||||
|
key: []byte(key),
|
||||||
|
offset: field.Offset,
|
||||||
|
}
|
||||||
|
if fieldIdx == 0 {
|
||||||
|
fieldCode.op = opStructFieldHead
|
||||||
|
head = fieldCode
|
||||||
|
code = (*opcode)(unsafe.Pointer(fieldCode))
|
||||||
|
prevField = fieldCode
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fieldCode.op = opStructField
|
||||||
|
code.next = (*opcode)(unsafe.Pointer(fieldCode))
|
||||||
|
prevField.nextField = (*opcode)(unsafe.Pointer(fieldCode))
|
||||||
|
prevField = fieldCode
|
||||||
|
code = (*opcode)(unsafe.Pointer(fieldCode))
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevField.nextField = newEndOp()
|
||||||
|
fieldIdx++
|
||||||
|
}
|
||||||
|
structEndCode := newOpCode(opStructEnd, nil, nil)
|
||||||
|
head.end = structEndCode
|
||||||
|
code.next = structEndCode
|
||||||
|
structEndCode.next = newEndOp()
|
||||||
|
return (*opcode)(unsafe.Pointer(head)), nil
|
||||||
|
}
|
|
@ -0,0 +1,451 @@
|
||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type opType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
opEnd opType = iota
|
||||||
|
opInt
|
||||||
|
opInt8
|
||||||
|
opInt16
|
||||||
|
opInt32
|
||||||
|
opInt64
|
||||||
|
opUint
|
||||||
|
opUint8
|
||||||
|
opUint16
|
||||||
|
opUint32
|
||||||
|
opUint64
|
||||||
|
opFloat32
|
||||||
|
opFloat64
|
||||||
|
opString
|
||||||
|
opBool
|
||||||
|
opInterface
|
||||||
|
opPtr
|
||||||
|
opSliceHead
|
||||||
|
opSliceElem
|
||||||
|
opSliceEnd
|
||||||
|
opArrayHead
|
||||||
|
opArrayElem
|
||||||
|
opArrayEnd
|
||||||
|
opMapHead
|
||||||
|
opMapKey
|
||||||
|
opMapValue
|
||||||
|
opMapEnd
|
||||||
|
opStructFieldHead
|
||||||
|
opStructFieldHeadInt
|
||||||
|
opStructFieldHeadInt8
|
||||||
|
opStructFieldHeadInt16
|
||||||
|
opStructFieldHeadInt32
|
||||||
|
opStructFieldHeadInt64
|
||||||
|
opStructFieldHeadUint
|
||||||
|
opStructFieldHeadUint8
|
||||||
|
opStructFieldHeadUint16
|
||||||
|
opStructFieldHeadUint32
|
||||||
|
opStructFieldHeadUint64
|
||||||
|
opStructFieldHeadFloat32
|
||||||
|
opStructFieldHeadFloat64
|
||||||
|
opStructFieldHeadString
|
||||||
|
opStructFieldHeadBool
|
||||||
|
opStructFieldPtrHead
|
||||||
|
opStructFieldPtrHeadInt
|
||||||
|
opStructFieldPtrHeadInt8
|
||||||
|
opStructFieldPtrHeadInt16
|
||||||
|
opStructFieldPtrHeadInt32
|
||||||
|
opStructFieldPtrHeadInt64
|
||||||
|
opStructFieldPtrHeadUint
|
||||||
|
opStructFieldPtrHeadUint8
|
||||||
|
opStructFieldPtrHeadUint16
|
||||||
|
opStructFieldPtrHeadUint32
|
||||||
|
opStructFieldPtrHeadUint64
|
||||||
|
opStructFieldPtrHeadFloat32
|
||||||
|
opStructFieldPtrHeadFloat64
|
||||||
|
opStructFieldPtrHeadString
|
||||||
|
opStructFieldPtrHeadBool
|
||||||
|
opStructField
|
||||||
|
opStructFieldInt
|
||||||
|
opStructFieldInt8
|
||||||
|
opStructFieldInt16
|
||||||
|
opStructFieldInt32
|
||||||
|
opStructFieldInt64
|
||||||
|
opStructFieldUint
|
||||||
|
opStructFieldUint8
|
||||||
|
opStructFieldUint16
|
||||||
|
opStructFieldUint32
|
||||||
|
opStructFieldUint64
|
||||||
|
opStructFieldFloat32
|
||||||
|
opStructFieldFloat64
|
||||||
|
opStructFieldString
|
||||||
|
opStructFieldBool
|
||||||
|
opStructEnd
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t opType) String() string {
|
||||||
|
switch t {
|
||||||
|
case opEnd:
|
||||||
|
return "END"
|
||||||
|
case opInt:
|
||||||
|
return "INT"
|
||||||
|
case opInt8:
|
||||||
|
return "INT8"
|
||||||
|
case opInt16:
|
||||||
|
return "INT16"
|
||||||
|
case opInt32:
|
||||||
|
return "INT32"
|
||||||
|
case opInt64:
|
||||||
|
return "INT64"
|
||||||
|
case opUint:
|
||||||
|
return "UINT"
|
||||||
|
case opUint8:
|
||||||
|
return "UINT8"
|
||||||
|
case opUint16:
|
||||||
|
return "UINT16"
|
||||||
|
case opUint32:
|
||||||
|
return "UINT32"
|
||||||
|
case opUint64:
|
||||||
|
return "UINT64"
|
||||||
|
case opFloat32:
|
||||||
|
return "FLOAT32"
|
||||||
|
case opFloat64:
|
||||||
|
return "FLOAT64"
|
||||||
|
case opString:
|
||||||
|
return "STRING"
|
||||||
|
case opBool:
|
||||||
|
return "BOOL"
|
||||||
|
case opInterface:
|
||||||
|
return "INTERFACE"
|
||||||
|
case opPtr:
|
||||||
|
return "PTR"
|
||||||
|
case opSliceHead:
|
||||||
|
return "SLICE_HEAD"
|
||||||
|
case opSliceElem:
|
||||||
|
return "SLICE_ELEM"
|
||||||
|
case opSliceEnd:
|
||||||
|
return "SLICE_END"
|
||||||
|
case opArrayHead:
|
||||||
|
return "ARRAY_HEAD"
|
||||||
|
case opArrayElem:
|
||||||
|
return "ARRAY_ELEM"
|
||||||
|
case opArrayEnd:
|
||||||
|
return "ARRAY_END"
|
||||||
|
case opMapHead:
|
||||||
|
return "MAP_HEAD"
|
||||||
|
case opMapKey:
|
||||||
|
return "MAP_KEY"
|
||||||
|
case opMapValue:
|
||||||
|
return "MAP_VALUE"
|
||||||
|
case opMapEnd:
|
||||||
|
return "MAP_END"
|
||||||
|
case opStructFieldHead:
|
||||||
|
return "STRUCT_FIELD_HEAD"
|
||||||
|
case opStructFieldHeadInt:
|
||||||
|
return "STRUCT_FIELD_HEAD_INT"
|
||||||
|
case opStructFieldHeadInt8:
|
||||||
|
return "STRUCT_FIELD_HEAD_INT8"
|
||||||
|
case opStructFieldHeadInt16:
|
||||||
|
return "STRUCT_FIELD_HEAD_INT16"
|
||||||
|
case opStructFieldHeadInt32:
|
||||||
|
return "STRUCT_FIELD_HEAD_INT32"
|
||||||
|
case opStructFieldHeadInt64:
|
||||||
|
return "STRUCT_FIELD_HEAD_INT64"
|
||||||
|
case opStructFieldHeadUint:
|
||||||
|
return "STRUCT_FIELD_HEAD_UINT"
|
||||||
|
case opStructFieldHeadUint8:
|
||||||
|
return "STRUCT_FIELD_HEAD_UINT8"
|
||||||
|
case opStructFieldHeadUint16:
|
||||||
|
return "STRUCT_FIELD_HEAD_UINT16"
|
||||||
|
case opStructFieldHeadUint32:
|
||||||
|
return "STRUCT_FIELD_HEAD_UINT32"
|
||||||
|
case opStructFieldHeadUint64:
|
||||||
|
return "STRUCT_FIELD_HEAD_UINT64"
|
||||||
|
case opStructFieldHeadFloat32:
|
||||||
|
return "STRUCT_FIELD_HEAD_FLOAT32"
|
||||||
|
case opStructFieldHeadFloat64:
|
||||||
|
return "STRUCT_FIELD_HEAD_FLOAT64"
|
||||||
|
case opStructFieldHeadString:
|
||||||
|
return "STRUCT_FIELD_HEAD_STRING"
|
||||||
|
case opStructFieldHeadBool:
|
||||||
|
return "STRUCT_FIELD_HEAD_BOOL"
|
||||||
|
case opStructFieldPtrHead:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD"
|
||||||
|
case opStructFieldPtrHeadInt:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_INT"
|
||||||
|
case opStructFieldPtrHeadInt8:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_INT8"
|
||||||
|
case opStructFieldPtrHeadInt16:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_INT16"
|
||||||
|
case opStructFieldPtrHeadInt32:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_INT32"
|
||||||
|
case opStructFieldPtrHeadInt64:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_INT64"
|
||||||
|
case opStructFieldPtrHeadUint:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_UINT"
|
||||||
|
case opStructFieldPtrHeadUint8:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_UINT8"
|
||||||
|
case opStructFieldPtrHeadUint16:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_UINT16"
|
||||||
|
case opStructFieldPtrHeadUint32:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_UINT32"
|
||||||
|
case opStructFieldPtrHeadUint64:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_UINT64"
|
||||||
|
case opStructFieldPtrHeadFloat32:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_FLOAT32"
|
||||||
|
case opStructFieldPtrHeadFloat64:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_FLOAT64"
|
||||||
|
case opStructFieldPtrHeadString:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_STRING"
|
||||||
|
case opStructFieldPtrHeadBool:
|
||||||
|
return "STRUCT_FIELD_PTR_HEAD_BOOL"
|
||||||
|
case opStructField:
|
||||||
|
return "STRUCT_FIELD"
|
||||||
|
case opStructFieldInt:
|
||||||
|
return "STRUCT_FIELD_INT"
|
||||||
|
case opStructFieldInt8:
|
||||||
|
return "STRUCT_FIELD_INT8"
|
||||||
|
case opStructFieldInt16:
|
||||||
|
return "STRUCT_FIELD_INT16"
|
||||||
|
case opStructFieldInt32:
|
||||||
|
return "STRUCT_FIELD_INT32"
|
||||||
|
case opStructFieldInt64:
|
||||||
|
return "STRUCT_FIELD_INT64"
|
||||||
|
case opStructFieldUint:
|
||||||
|
return "STRUCT_FIELD_UINT"
|
||||||
|
case opStructFieldUint8:
|
||||||
|
return "STRUCT_FIELD_UINT8"
|
||||||
|
case opStructFieldUint16:
|
||||||
|
return "STRUCT_FIELD_UINT16"
|
||||||
|
case opStructFieldUint32:
|
||||||
|
return "STRUCT_FIELD_UINT32"
|
||||||
|
case opStructFieldUint64:
|
||||||
|
return "STRUCT_FIELD_UINT64"
|
||||||
|
case opStructFieldFloat32:
|
||||||
|
return "STRUCT_FIELD_FLOAT32"
|
||||||
|
case opStructFieldFloat64:
|
||||||
|
return "STRUCT_FIELD_FLOAT64"
|
||||||
|
case opStructFieldString:
|
||||||
|
return "STRUCT_FIELD_STRING"
|
||||||
|
case opStructFieldBool:
|
||||||
|
return "STRUCT_FIELD_BOOL"
|
||||||
|
case opStructEnd:
|
||||||
|
return "STRUCT_END"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type opcodeHeader struct {
|
||||||
|
op opType
|
||||||
|
typ *rtype
|
||||||
|
ptr uintptr
|
||||||
|
next *opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
type opcode struct {
|
||||||
|
*opcodeHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOpCode(op opType, typ *rtype, next *opcode) *opcode {
|
||||||
|
return &opcode{
|
||||||
|
opcodeHeader: &opcodeHeader{
|
||||||
|
op: op,
|
||||||
|
typ: typ,
|
||||||
|
next: next,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEndOp() *opcode {
|
||||||
|
return newOpCode(opEnd, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *opcode) beforeLastCode() *opcode {
|
||||||
|
code := c
|
||||||
|
for {
|
||||||
|
var nextCode *opcode
|
||||||
|
switch code.op {
|
||||||
|
case opArrayElem:
|
||||||
|
nextCode = code.toArrayElemCode().end
|
||||||
|
case opSliceElem:
|
||||||
|
nextCode = code.toSliceElemCode().end
|
||||||
|
case opMapKey:
|
||||||
|
nextCode = code.toMapKeyCode().end
|
||||||
|
default:
|
||||||
|
nextCode = code.next
|
||||||
|
}
|
||||||
|
if nextCode.op == opEnd {
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
code = nextCode
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *opcode) dump() string {
|
||||||
|
codes := []string{}
|
||||||
|
for code := c; code.op != opEnd; {
|
||||||
|
codes = append(codes, fmt.Sprintf("%s", code.op))
|
||||||
|
switch code.op {
|
||||||
|
case opArrayElem:
|
||||||
|
code = code.toArrayElemCode().end
|
||||||
|
case opSliceElem:
|
||||||
|
code = code.toSliceElemCode().end
|
||||||
|
case opMapKey:
|
||||||
|
code = code.toMapKeyCode().end
|
||||||
|
default:
|
||||||
|
code = code.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(codes, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *opcode) toSliceHeaderCode() *sliceHeaderCode {
|
||||||
|
return (*sliceHeaderCode)(unsafe.Pointer(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *opcode) toSliceElemCode() *sliceElemCode {
|
||||||
|
return (*sliceElemCode)(unsafe.Pointer(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *opcode) toArrayHeaderCode() *arrayHeaderCode {
|
||||||
|
return (*arrayHeaderCode)(unsafe.Pointer(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *opcode) toArrayElemCode() *arrayElemCode {
|
||||||
|
return (*arrayElemCode)(unsafe.Pointer(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *opcode) toStructFieldCode() *structFieldCode {
|
||||||
|
return (*structFieldCode)(unsafe.Pointer(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *opcode) toMapHeadCode() *mapHeaderCode {
|
||||||
|
return (*mapHeaderCode)(unsafe.Pointer(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *opcode) toMapKeyCode() *mapKeyCode {
|
||||||
|
return (*mapKeyCode)(unsafe.Pointer(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *opcode) toMapValueCode() *mapValueCode {
|
||||||
|
return (*mapValueCode)(unsafe.Pointer(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
type sliceHeaderCode struct {
|
||||||
|
*opcodeHeader
|
||||||
|
elem *sliceElemCode
|
||||||
|
end *opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSliceHeaderCode() *sliceHeaderCode {
|
||||||
|
return &sliceHeaderCode{
|
||||||
|
opcodeHeader: &opcodeHeader{
|
||||||
|
op: opSliceHead,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type sliceElemCode struct {
|
||||||
|
*opcodeHeader
|
||||||
|
idx uintptr
|
||||||
|
len uintptr
|
||||||
|
size uintptr
|
||||||
|
data uintptr
|
||||||
|
end *opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *sliceElemCode) set(header *reflect.SliceHeader) {
|
||||||
|
c.idx = uintptr(0)
|
||||||
|
c.len = uintptr(header.Len)
|
||||||
|
c.data = header.Data
|
||||||
|
}
|
||||||
|
|
||||||
|
type arrayHeaderCode struct {
|
||||||
|
*opcodeHeader
|
||||||
|
len uintptr
|
||||||
|
elem *arrayElemCode
|
||||||
|
end *opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
func newArrayHeaderCode(alen int) *arrayHeaderCode {
|
||||||
|
return &arrayHeaderCode{
|
||||||
|
opcodeHeader: &opcodeHeader{
|
||||||
|
op: opArrayHead,
|
||||||
|
},
|
||||||
|
len: uintptr(alen),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type arrayElemCode struct {
|
||||||
|
*opcodeHeader
|
||||||
|
idx uintptr
|
||||||
|
len uintptr
|
||||||
|
size uintptr
|
||||||
|
end *opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
type structFieldCode struct {
|
||||||
|
*opcodeHeader
|
||||||
|
key []byte
|
||||||
|
offset uintptr
|
||||||
|
nextField *opcode
|
||||||
|
end *opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
type mapHeaderCode struct {
|
||||||
|
*opcodeHeader
|
||||||
|
key *mapKeyCode
|
||||||
|
value *mapValueCode
|
||||||
|
end *opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
type mapKeyCode struct {
|
||||||
|
*opcodeHeader
|
||||||
|
idx int
|
||||||
|
len int
|
||||||
|
iter unsafe.Pointer
|
||||||
|
end *opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mapKeyCode) set(len int, iter unsafe.Pointer) {
|
||||||
|
c.idx = 0
|
||||||
|
c.len = len
|
||||||
|
c.iter = iter
|
||||||
|
}
|
||||||
|
|
||||||
|
type mapValueCode struct {
|
||||||
|
*opcodeHeader
|
||||||
|
iter unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mapValueCode) set(iter unsafe.Pointer) {
|
||||||
|
c.iter = iter
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMapHeaderCode(typ *rtype) *mapHeaderCode {
|
||||||
|
return &mapHeaderCode{
|
||||||
|
opcodeHeader: &opcodeHeader{
|
||||||
|
op: opMapHead,
|
||||||
|
typ: typ,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMapKeyCode() *mapKeyCode {
|
||||||
|
return &mapKeyCode{
|
||||||
|
opcodeHeader: &opcodeHeader{
|
||||||
|
op: opMapKey,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMapValueCode() *mapValueCode {
|
||||||
|
return &mapValueCode{
|
||||||
|
opcodeHeader: &opcodeHeader{
|
||||||
|
op: opMapValue,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -93,10 +93,18 @@ func Test_Encoder(t *testing.T) {
|
||||||
assertEq(t, "struct", `{"a":-1,"b":1,"c":"hello world"}`, string(bytes))
|
assertEq(t, "struct", `{"a":-1,"b":1,"c":"hello world"}`, string(bytes))
|
||||||
})
|
})
|
||||||
t.Run("slice", func(t *testing.T) {
|
t.Run("slice", func(t *testing.T) {
|
||||||
|
t.Run("[]int", func(t *testing.T) {
|
||||||
bytes, err := json.Marshal([]int{1, 2, 3, 4})
|
bytes, err := json.Marshal([]int{1, 2, 3, 4})
|
||||||
assertErr(t, err)
|
assertErr(t, err)
|
||||||
assertEq(t, "slice", `[1,2,3,4]`, string(bytes))
|
assertEq(t, "[]int", `[1,2,3,4]`, string(bytes))
|
||||||
})
|
})
|
||||||
|
t.Run("[]interface{}", func(t *testing.T) {
|
||||||
|
bytes, err := json.Marshal([]interface{}{1, 2.1, "hello"})
|
||||||
|
assertErr(t, err)
|
||||||
|
assertEq(t, "[]interface{}", `[1,2.1,"hello"]`, string(bytes))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("array", func(t *testing.T) {
|
t.Run("array", func(t *testing.T) {
|
||||||
bytes, err := json.Marshal([4]int{1, 2, 3, 4})
|
bytes, err := json.Marshal([4]int{1, 2, 3, 4})
|
||||||
assertErr(t, err)
|
assertErr(t, err)
|
||||||
|
|
|
@ -0,0 +1,545 @@
|
||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *Encoder) run(code *opcode) error {
|
||||||
|
for {
|
||||||
|
switch code.op {
|
||||||
|
case opPtr:
|
||||||
|
ptr := code.ptr
|
||||||
|
code = code.next
|
||||||
|
code.ptr = e.ptrToPtr(ptr)
|
||||||
|
case opInt:
|
||||||
|
e.encodeInt(e.ptrToInt(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opInt8:
|
||||||
|
e.encodeInt8(e.ptrToInt8(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opInt16:
|
||||||
|
e.encodeInt16(e.ptrToInt16(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opInt32:
|
||||||
|
e.encodeInt32(e.ptrToInt32(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opInt64:
|
||||||
|
e.encodeInt64(e.ptrToInt64(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opUint:
|
||||||
|
e.encodeUint(e.ptrToUint(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opUint8:
|
||||||
|
e.encodeUint8(e.ptrToUint8(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opUint16:
|
||||||
|
e.encodeUint16(e.ptrToUint16(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opUint32:
|
||||||
|
e.encodeUint32(e.ptrToUint32(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opUint64:
|
||||||
|
e.encodeUint64(e.ptrToUint64(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opFloat32:
|
||||||
|
e.encodeFloat32(e.ptrToFloat32(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opFloat64:
|
||||||
|
e.encodeFloat64(e.ptrToFloat64(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opString:
|
||||||
|
e.encodeEscapedString(e.ptrToString(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opBool:
|
||||||
|
e.encodeBool(e.ptrToBool(code.ptr))
|
||||||
|
code = code.next
|
||||||
|
case opInterface:
|
||||||
|
ptr := code.ptr
|
||||||
|
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
||||||
|
typ: code.typ,
|
||||||
|
ptr: unsafe.Pointer(ptr),
|
||||||
|
}))
|
||||||
|
vv := reflect.ValueOf(v).Interface()
|
||||||
|
header := (*interfaceHeader)(unsafe.Pointer(&vv))
|
||||||
|
typ := header.typ
|
||||||
|
if typ.Kind() == reflect.Ptr {
|
||||||
|
typ = typ.Elem()
|
||||||
|
}
|
||||||
|
c, err := e.compile(typ)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.ptr = uintptr(header.ptr)
|
||||||
|
c.beforeLastCode().next = code.next
|
||||||
|
code = c
|
||||||
|
case opSliceHead:
|
||||||
|
p := code.ptr
|
||||||
|
headerCode := code.toSliceHeaderCode()
|
||||||
|
if p == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = headerCode.end.next
|
||||||
|
} else {
|
||||||
|
e.encodeByte('[')
|
||||||
|
header := (*reflect.SliceHeader)(unsafe.Pointer(p))
|
||||||
|
headerCode.elem.set(header)
|
||||||
|
if header.Len > 0 {
|
||||||
|
code = code.next
|
||||||
|
code.ptr = header.Data
|
||||||
|
} else {
|
||||||
|
e.encodeByte(']')
|
||||||
|
code = headerCode.end.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case opSliceElem:
|
||||||
|
c := code.toSliceElemCode()
|
||||||
|
c.idx++
|
||||||
|
if c.idx < c.len {
|
||||||
|
e.encodeByte(',')
|
||||||
|
code = code.next
|
||||||
|
code.ptr = c.data + c.idx*c.size
|
||||||
|
} else {
|
||||||
|
e.encodeByte(']')
|
||||||
|
code = c.end.next
|
||||||
|
}
|
||||||
|
case opArrayHead:
|
||||||
|
p := code.ptr
|
||||||
|
headerCode := code.toArrayHeaderCode()
|
||||||
|
if p == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = headerCode.end.next
|
||||||
|
} else {
|
||||||
|
e.encodeByte('[')
|
||||||
|
if headerCode.len > 0 {
|
||||||
|
code = code.next
|
||||||
|
code.ptr = p
|
||||||
|
headerCode.elem.ptr = p
|
||||||
|
} else {
|
||||||
|
e.encodeByte(']')
|
||||||
|
code = headerCode.end.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case opArrayElem:
|
||||||
|
c := code.toArrayElemCode()
|
||||||
|
c.idx++
|
||||||
|
if c.idx < c.len {
|
||||||
|
e.encodeByte(',')
|
||||||
|
code = code.next
|
||||||
|
code.ptr = c.ptr + c.idx*c.size
|
||||||
|
} else {
|
||||||
|
e.encodeByte(']')
|
||||||
|
code = c.end.next
|
||||||
|
}
|
||||||
|
case opMapHead:
|
||||||
|
ptr := code.ptr
|
||||||
|
mapHeadCode := code.toMapHeadCode()
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = mapHeadCode.end.next
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
mlen := maplen(unsafe.Pointer(ptr))
|
||||||
|
if mlen > 0 {
|
||||||
|
iter := mapiterinit(code.typ, unsafe.Pointer(ptr))
|
||||||
|
mapHeadCode.key.set(mlen, iter)
|
||||||
|
mapHeadCode.value.set(iter)
|
||||||
|
key := mapiterkey(iter)
|
||||||
|
code.next.ptr = uintptr(key)
|
||||||
|
code = code.next
|
||||||
|
} else {
|
||||||
|
e.encodeByte('}')
|
||||||
|
code = mapHeadCode.end.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case opMapKey:
|
||||||
|
c := code.toMapKeyCode()
|
||||||
|
c.idx++
|
||||||
|
if c.idx < c.len {
|
||||||
|
e.encodeByte(',')
|
||||||
|
key := mapiterkey(c.iter)
|
||||||
|
c.next.ptr = uintptr(key)
|
||||||
|
code = c.next
|
||||||
|
} else {
|
||||||
|
e.encodeByte('}')
|
||||||
|
code = c.end.next
|
||||||
|
}
|
||||||
|
case opMapValue:
|
||||||
|
e.encodeByte(':')
|
||||||
|
c := code.toMapValueCode()
|
||||||
|
value := mapitervalue(c.iter)
|
||||||
|
c.next.ptr = uintptr(value)
|
||||||
|
mapiternext(c.iter)
|
||||||
|
code = c.next
|
||||||
|
case opStructFieldPtrHead:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHead:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
code = field.next
|
||||||
|
code.ptr = field.ptr + field.offset
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadInt:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadInt:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeInt(e.ptrToInt(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadInt8:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadInt8:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeInt8(e.ptrToInt8(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadInt16:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadInt16:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeInt16(e.ptrToInt16(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadInt32:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadInt32:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeInt32(e.ptrToInt32(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadInt64:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadInt64:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeInt64(e.ptrToInt64(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadUint:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadUint:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeUint(e.ptrToUint(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadUint8:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadUint8:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeUint8(e.ptrToUint8(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadUint16:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadUint16:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeUint16(e.ptrToUint16(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadUint32:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadUint32:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeUint32(e.ptrToUint32(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadUint64:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadUint64:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeUint64(e.ptrToUint64(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadFloat32:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadFloat32:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeFloat32(e.ptrToFloat32(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadFloat64:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadFloat64:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeFloat64(e.ptrToFloat64(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadString:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadString:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeEscapedString(e.ptrToString(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructFieldPtrHeadBool:
|
||||||
|
code.ptr = e.ptrToPtr(code.ptr)
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldHeadBool:
|
||||||
|
field := code.toStructFieldCode()
|
||||||
|
ptr := field.ptr
|
||||||
|
if ptr == 0 {
|
||||||
|
e.encodeString("null")
|
||||||
|
code = field.end
|
||||||
|
} else {
|
||||||
|
e.encodeByte('{')
|
||||||
|
e.encodeBytes(field.key)
|
||||||
|
e.encodeBool(e.ptrToBool(field.ptr + field.offset))
|
||||||
|
field.nextField.ptr = field.ptr
|
||||||
|
code = field.next
|
||||||
|
}
|
||||||
|
case opStructField:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
code = code.next
|
||||||
|
code.ptr = c.ptr + c.offset
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
case opStructFieldInt:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeInt(e.ptrToInt(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldInt8:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeInt8(e.ptrToInt8(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldInt16:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeInt16(e.ptrToInt16(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldInt32:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeInt32(e.ptrToInt32(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldInt64:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeInt64(e.ptrToInt64(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldUint:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeUint(e.ptrToUint(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldUint8:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeUint8(e.ptrToUint8(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldUint16:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeUint16(e.ptrToUint16(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldUint32:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeUint32(e.ptrToUint32(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldUint64:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeUint64(e.ptrToUint64(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldFloat32:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeFloat32(e.ptrToFloat32(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldFloat64:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeFloat64(e.ptrToFloat64(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldString:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeEscapedString(e.ptrToString(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldBool:
|
||||||
|
e.encodeByte(',')
|
||||||
|
c := code.toStructFieldCode()
|
||||||
|
c.nextField.ptr = c.ptr
|
||||||
|
e.encodeBytes(c.key)
|
||||||
|
e.encodeBool(e.ptrToBool(c.ptr + c.offset))
|
||||||
|
code = code.next
|
||||||
|
case opStructEnd:
|
||||||
|
e.encodeByte('}')
|
||||||
|
code = code.next
|
||||||
|
case opEnd:
|
||||||
|
goto END
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) ptrToPtr(p uintptr) uintptr { return *(*uintptr)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToInt(p uintptr) int { return *(*int)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToInt8(p uintptr) int8 { return *(*int8)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToInt16(p uintptr) int16 { return *(*int16)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToInt32(p uintptr) int32 { return *(*int32)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToInt64(p uintptr) int64 { return *(*int64)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToUint(p uintptr) uint { return *(*uint)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToUint8(p uintptr) uint8 { return *(*uint8)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToUint16(p uintptr) uint16 { return *(*uint16)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToUint32(p uintptr) uint32 { return *(*uint32)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToUint64(p uintptr) uint64 { return *(*uint64)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToFloat32(p uintptr) float32 { return *(*float32)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToFloat64(p uintptr) float64 { return *(*float64)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToBool(p uintptr) bool { return *(*bool)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToByte(p uintptr) byte { return *(*byte)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToBytes(p uintptr) []byte { return *(*[]byte)(unsafe.Pointer(p)) }
|
||||||
|
func (e *Encoder) ptrToString(p uintptr) string { return *(*string)(unsafe.Pointer(p)) }
|
Loading…
Reference in New Issue