go-json/encode.go

472 lines
12 KiB
Go
Raw Normal View History

2020-04-19 13:51:22 +03:00
package json
import (
"fmt"
2020-04-21 08:19:50 +03:00
"io"
2020-04-19 13:51:22 +03:00
"reflect"
"strconv"
2020-04-19 14:28:13 +03:00
"strings"
2020-04-19 13:51:22 +03:00
"sync"
"unsafe"
"golang.org/x/xerrors"
)
2020-04-21 08:19:50 +03:00
// An Encoder writes JSON values to an output stream.
2020-04-19 13:51:22 +03:00
type Encoder struct {
2020-04-21 08:19:50 +03:00
w io.Writer
2020-04-19 13:51:22 +03:00
buf []byte
pool sync.Pool
}
type EncodeOp func(*Encoder, uintptr)
const (
bufSize = 1024
)
var (
encPool sync.Pool
cachedEncodeOp map[string]EncodeOp
)
func init() {
encPool = sync.Pool{
New: func() interface{} {
return &Encoder{
buf: make([]byte, 0, bufSize),
pool: encPool,
}
},
}
cachedEncodeOp = map[string]EncodeOp{}
}
2020-04-21 08:19:50 +03:00
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
2020-04-19 13:51:22 +03:00
enc := encPool.Get().(*Encoder)
2020-04-21 08:19:50 +03:00
enc.w = w
enc.reset()
2020-04-19 13:51:22 +03:00
return enc
}
2020-04-21 08:19:50 +03:00
// Encode writes the JSON encoding of v to the stream, followed by a newline character.
//
// See the documentation for Marshal for details about the conversion of Go values to JSON.
func (e *Encoder) Encode(v interface{}) error {
2020-04-24 14:23:26 +03:00
if err := e.encode(v); err != nil {
2020-04-21 08:19:50 +03:00
return err
}
if _, err := e.w.Write(e.buf); err != nil {
return err
}
return nil
}
func (e *Encoder) encodeForMarshal(v interface{}) ([]byte, error) {
2020-04-24 14:23:26 +03:00
if err := e.encode(v); err != nil {
2020-04-21 08:19:50 +03:00
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.
//
// In non-HTML settings where the escaping interferes with the readability of the output, SetEscapeHTML(false) disables this behavior.
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) {
}
func (e *Encoder) release() {
e.w = nil
2020-04-22 07:06:52 +03:00
e.pool.Put(e)
2020-04-19 13:51:22 +03:00
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) reset() {
2020-04-19 13:51:22 +03:00
e.buf = e.buf[:0]
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeInt(v int) {
e.encodeInt64(int64(v))
2020-04-19 13:51:22 +03:00
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeInt8(v int8) {
e.encodeInt64(int64(v))
2020-04-19 13:51:22 +03:00
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeInt16(v int16) {
e.encodeInt64(int64(v))
2020-04-19 13:51:22 +03:00
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeInt32(v int32) {
e.encodeInt64(int64(v))
2020-04-19 13:51:22 +03:00
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeInt64(v int64) {
2020-04-19 13:51:22 +03:00
e.buf = strconv.AppendInt(e.buf, v, 10)
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeUint(v uint) {
e.encodeUint64(uint64(v))
2020-04-19 13:51:22 +03:00
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeUint8(v uint8) {
e.encodeUint64(uint64(v))
2020-04-19 13:51:22 +03:00
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeUint16(v uint16) {
e.encodeUint64(uint64(v))
2020-04-19 13:51:22 +03:00
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeUint32(v uint32) {
e.encodeUint64(uint64(v))
2020-04-19 13:51:22 +03:00
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeUint64(v uint64) {
2020-04-19 13:51:22 +03:00
e.buf = strconv.AppendUint(e.buf, v, 10)
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeFloat32(v float32) {
2020-04-19 13:51:22 +03:00
e.buf = strconv.AppendFloat(e.buf, float64(v), 'f', -1, 32)
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeFloat64(v float64) {
2020-04-19 13:51:22 +03:00
e.buf = strconv.AppendFloat(e.buf, v, 'f', -1, 64)
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeBool(v bool) {
2020-04-19 13:51:22 +03:00
e.buf = strconv.AppendBool(e.buf, v)
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeString(s string) {
2020-04-19 13:51:22 +03:00
b := *(*[]byte)(unsafe.Pointer(&s))
e.buf = append(e.buf, b...)
}
2020-04-21 08:19:50 +03:00
func (e *Encoder) encodeByte(b byte) {
2020-04-19 13:51:22 +03:00
e.buf = append(e.buf, b)
}
2020-04-24 14:23:26 +03:00
func (e *Encoder) encode(v interface{}) error {
header := (*interfaceHeader)(unsafe.Pointer(&v))
typ := header.typ
name := typ.String()
2020-04-19 13:51:22 +03:00
if op, exists := cachedEncodeOp[name]; exists {
2020-04-24 14:23:26 +03:00
op(e, uintptr(header.ptr))
2020-04-21 08:19:50 +03:00
return nil
2020-04-19 13:51:22 +03:00
}
if typ.Kind() == reflect.Ptr {
2020-04-22 09:29:54 +03:00
typ = typ.Elem()
}
2020-04-22 09:29:54 +03:00
op, err := e.compile(typ)
2020-04-19 13:51:22 +03:00
if err != nil {
2020-04-21 08:19:50 +03:00
return err
2020-04-19 13:51:22 +03:00
}
2020-04-19 17:13:24 +03:00
if name != "" {
cachedEncodeOp[name] = op
}
2020-04-24 14:23:26 +03:00
op(e, uintptr(header.ptr))
2020-04-21 08:19:50 +03:00
return nil
2020-04-19 13:51:22 +03:00
}
2020-04-24 14:23:26 +03:00
func (e *Encoder) compile(typ *rtype) (EncodeOp, error) {
2020-04-22 09:29:54 +03:00
switch typ.Kind() {
2020-04-19 13:51:22 +03:00
case reflect.Ptr:
2020-04-22 09:29:54 +03:00
return e.compilePtr(typ)
2020-04-19 17:13:24 +03:00
case reflect.Slice:
2020-04-22 09:29:54 +03:00
return e.compileSlice(typ)
2020-04-19 13:51:22 +03:00
case reflect.Struct:
2020-04-22 09:29:54 +03:00
return e.compileStruct(typ)
2020-04-20 18:06:27 +03:00
case reflect.Map:
2020-04-22 09:29:54 +03:00
return e.compileMap(typ)
2020-04-21 07:19:53 +03:00
case reflect.Array:
2020-04-22 09:29:54 +03:00
return e.compileArray(typ)
2020-04-19 13:51:22 +03:00
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()
2020-04-19 17:13:24 +03:00
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()
2020-04-19 13:51:22 +03:00
case reflect.Float32:
return e.compileFloat32()
case reflect.Float64:
return e.compileFloat64()
case reflect.String:
return e.compileString()
case reflect.Bool:
return e.compileBool()
2020-04-21 07:19:53 +03:00
case reflect.Interface:
return nil, ErrCompileSlowPath
2020-04-19 13:51:22 +03:00
}
2020-04-24 14:23:26 +03:00
return nil, xerrors.Errorf("failed to encode type %s: %w", typ.String(), ErrUnsupportedType)
2020-04-19 13:51:22 +03:00
}
2020-04-24 14:23:26 +03:00
func (e *Encoder) compilePtr(typ *rtype) (EncodeOp, error) {
2020-04-22 09:29:54 +03:00
op, err := e.compile(typ.Elem())
if err != nil {
return nil, err
}
return func(enc *Encoder, p uintptr) {
op(enc, e.ptrToPtr(p))
}, nil
}
2020-04-19 13:51:22 +03:00
func (e *Encoder) compileInt() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeInt(e.ptrToInt(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileInt8() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeInt8(e.ptrToInt8(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileInt16() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeInt16(e.ptrToInt16(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileInt32() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeInt32(e.ptrToInt32(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileInt64() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeInt64(e.ptrToInt64(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileUint() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeUint(e.ptrToUint(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileUint8() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeUint8(e.ptrToUint8(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileUint16() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeUint16(e.ptrToUint16(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileUint32() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeUint32(e.ptrToUint32(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileUint64() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeUint64(e.ptrToUint64(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileFloat32() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeFloat32(e.ptrToFloat32(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileFloat64() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeFloat64(e.ptrToFloat64(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileString() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeEscapedString(e.ptrToString(p)) }, nil
2020-04-19 13:51:22 +03:00
}
func (e *Encoder) compileBool() (EncodeOp, error) {
2020-04-21 08:19:50 +03:00
return func(enc *Encoder, p uintptr) { enc.encodeBool(e.ptrToBool(p)) }, nil
2020-04-19 13:51:22 +03:00
}
2020-04-24 14:23:26 +03:00
func (e *Encoder) compileSlice(typ *rtype) (EncodeOp, error) {
2020-04-19 17:13:24 +03:00
size := typ.Elem().Size()
2020-04-22 09:29:54 +03:00
op, err := e.compile(typ.Elem())
2020-04-19 17:13:24 +03:00
if err != nil {
return nil, err
}
return func(enc *Encoder, base uintptr) {
if base == 0 {
2020-04-21 08:19:50 +03:00
enc.encodeString("null")
return
}
2020-04-21 08:19:50 +03:00
enc.encodeByte('[')
2020-04-19 17:13:24 +03:00
slice := (*reflect.SliceHeader)(unsafe.Pointer(base))
num := slice.Len
for i := 0; i < num; i++ {
op(enc, slice.Data+uintptr(i)*size)
if i != num-1 {
2020-04-21 08:19:50 +03:00
enc.encodeByte(',')
2020-04-19 17:13:24 +03:00
}
}
2020-04-21 08:19:50 +03:00
enc.encodeByte(']')
2020-04-19 17:13:24 +03:00
}, nil
2020-04-21 07:19:53 +03:00
}
2020-04-19 17:13:24 +03:00
2020-04-24 14:23:26 +03:00
func (e *Encoder) compileArray(typ *rtype) (EncodeOp, error) {
2020-04-21 07:19:53 +03:00
alen := typ.Len()
size := typ.Elem().Size()
2020-04-22 09:29:54 +03:00
op, err := e.compile(typ.Elem())
2020-04-21 07:19:53 +03:00
if err != nil {
return nil, err
}
return func(enc *Encoder, base uintptr) {
if base == 0 {
2020-04-21 08:19:50 +03:00
enc.encodeString("null")
2020-04-21 07:19:53 +03:00
return
}
2020-04-21 08:19:50 +03:00
enc.encodeByte('[')
2020-04-21 07:19:53 +03:00
for i := 0; i < alen; i++ {
if i != 0 {
2020-04-21 08:19:50 +03:00
enc.encodeByte(',')
2020-04-21 07:19:53 +03:00
}
op(enc, base+uintptr(i)*size)
}
2020-04-21 08:19:50 +03:00
enc.encodeByte(']')
2020-04-21 07:19:53 +03:00
}, nil
2020-04-19 17:13:24 +03:00
}
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
}
2020-04-24 14:23:26 +03:00
func (e *Encoder) compileStruct(typ *rtype) (EncodeOp, error) {
2020-04-19 17:13:24 +03:00
fieldNum := typ.NumField()
2020-04-19 13:51:22 +03:00
opQueue := make([]EncodeOp, 0, fieldNum)
for i := 0; i < fieldNum; i++ {
field := typ.Field(i)
if e.isIgnoredStructField(field) {
continue
}
2020-04-19 14:28:13 +03:00
keyName := field.Name
tag := e.getTag(field)
2020-04-19 14:28:13 +03:00
opts := strings.Split(tag, ",")
if len(opts) > 0 {
if opts[0] != "" {
keyName = opts[0]
}
}
2020-04-24 14:23:26 +03:00
fieldType := type2rtype(field.Type)
op, err := e.compile(fieldType)
2020-04-19 13:51:22 +03:00
if err != nil {
return nil, err
}
2020-04-19 14:28:13 +03:00
key := fmt.Sprintf(`"%s":`, keyName)
2020-04-19 13:51:22 +03:00
opQueue = append(opQueue, func(enc *Encoder, base uintptr) {
2020-04-21 08:19:50 +03:00
enc.encodeString(key)
2020-04-19 13:51:22 +03:00
op(enc, base+field.Offset)
})
}
queueNum := len(opQueue)
return func(enc *Encoder, base uintptr) {
if base == 0 {
2020-04-21 08:19:50 +03:00
enc.encodeString("null")
return
}
2020-04-21 08:19:50 +03:00
enc.encodeByte('{')
2020-04-19 13:51:22 +03:00
for i := 0; i < queueNum; i++ {
opQueue[i](enc, base)
if i != queueNum-1 {
2020-04-21 08:19:50 +03:00
enc.encodeByte(',')
2020-04-19 13:51:22 +03:00
}
}
2020-04-21 08:19:50 +03:00
enc.encodeByte('}')
2020-04-19 13:51:22 +03:00
}, nil
}
2020-04-20 18:06:27 +03:00
//go:linkname mapiterinit reflect.mapiterinit
func mapiterinit(mapType unsafe.Pointer, m unsafe.Pointer) unsafe.Pointer
//go:linkname mapiterkey reflect.mapiterkey
func mapiterkey(it unsafe.Pointer) unsafe.Pointer
//go:linkname mapitervalue reflect.mapitervalue
func mapitervalue(it unsafe.Pointer) unsafe.Pointer
//go:linkname mapiternext reflect.mapiternext
func mapiternext(it unsafe.Pointer)
//go:linkname maplen reflect.maplen
func maplen(m unsafe.Pointer) int
type valueType struct {
typ unsafe.Pointer
ptr unsafe.Pointer
}
2020-04-24 14:23:26 +03:00
func (e *Encoder) compileMap(typ *rtype) (EncodeOp, error) {
mapType := unsafe.Pointer(typ)
2020-04-22 09:29:54 +03:00
keyOp, err := e.compile(typ.Key())
2020-04-20 18:06:27 +03:00
if err != nil {
return nil, err
}
2020-04-22 09:29:54 +03:00
valueOp, err := e.compile(typ.Elem())
2020-04-20 18:06:27 +03:00
if err != nil {
return nil, err
}
return func(enc *Encoder, base uintptr) {
if base == 0 {
2020-04-21 08:19:50 +03:00
enc.encodeString("null")
2020-04-20 18:06:27 +03:00
return
}
2020-04-21 08:19:50 +03:00
enc.encodeByte('{')
2020-04-20 18:06:27 +03:00
mlen := maplen(unsafe.Pointer(base))
iter := mapiterinit(mapType, unsafe.Pointer(base))
for i := 0; i < mlen; i++ {
key := mapiterkey(iter)
if i != 0 {
2020-04-21 08:19:50 +03:00
enc.encodeByte(',')
2020-04-20 18:06:27 +03:00
}
value := mapitervalue(iter)
keyOp(enc, uintptr(key))
2020-04-21 08:19:50 +03:00
enc.encodeByte(':')
2020-04-20 18:06:27 +03:00
valueOp(enc, uintptr(value))
mapiternext(iter)
}
2020-04-21 08:19:50 +03:00
enc.encodeByte('}')
2020-04-20 18:06:27 +03:00
}, nil
}
func (e *Encoder) ptrToPtr(p uintptr) uintptr { return *(*uintptr)(unsafe.Pointer(p)) }
2020-04-19 13:51:22 +03:00
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)) }