go-json/encode_compile.go

410 lines
10 KiB
Go
Raw Normal View History

2020-04-29 18:31:50 +03:00
package json
import (
"fmt"
"reflect"
"strings"
"unsafe"
"golang.org/x/xerrors"
)
2020-04-30 07:52:24 +03:00
func (e *Encoder) compile(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
switch typ.Kind() {
case reflect.Ptr:
2020-04-30 07:52:24 +03:00
return e.compilePtr(typ)
2020-04-29 18:31:50 +03:00
case reflect.Slice:
2020-04-30 07:52:24 +03:00
return e.compileSlice(typ)
case reflect.Array:
2020-04-30 07:52:24 +03:00
return e.compileArray(typ)
case reflect.Map:
2020-04-30 07:52:24 +03:00
return e.compileMap(typ)
2020-04-29 18:31:50 +03:00
case reflect.Struct:
2020-04-30 07:52:24 +03:00
return e.compileStruct(typ)
2020-04-29 18:31:50 +03:00
case reflect.Int:
2020-04-30 07:52:24 +03:00
return e.compileInt(typ)
2020-04-29 18:31:50 +03:00
case reflect.Int8:
2020-04-30 07:52:24 +03:00
return e.compileInt8(typ)
2020-04-29 18:31:50 +03:00
case reflect.Int16:
2020-04-30 07:52:24 +03:00
return e.compileInt16(typ)
2020-04-29 18:31:50 +03:00
case reflect.Int32:
2020-04-30 07:52:24 +03:00
return e.compileInt32(typ)
2020-04-29 18:31:50 +03:00
case reflect.Int64:
2020-04-30 07:52:24 +03:00
return e.compileInt64(typ)
2020-04-29 18:31:50 +03:00
case reflect.Uint:
2020-04-30 07:52:24 +03:00
return e.compileUint(typ)
2020-04-29 18:31:50 +03:00
case reflect.Uint8:
2020-04-30 07:52:24 +03:00
return e.compileUint8(typ)
2020-04-29 18:31:50 +03:00
case reflect.Uint16:
2020-04-30 07:52:24 +03:00
return e.compileUint16(typ)
2020-04-29 18:31:50 +03:00
case reflect.Uint32:
2020-04-30 07:52:24 +03:00
return e.compileUint32(typ)
2020-04-29 18:31:50 +03:00
case reflect.Uint64:
2020-04-30 07:52:24 +03:00
return e.compileUint64(typ)
2020-04-29 18:31:50 +03:00
case reflect.Uintptr:
2020-04-30 07:52:24 +03:00
return e.compileUint(typ)
2020-04-29 18:31:50 +03:00
case reflect.Float32:
2020-04-30 07:52:24 +03:00
return e.compileFloat32(typ)
2020-04-29 18:31:50 +03:00
case reflect.Float64:
2020-04-30 07:52:24 +03:00
return e.compileFloat64(typ)
2020-04-29 18:31:50 +03:00
case reflect.String:
2020-04-30 07:52:24 +03:00
return e.compileString(typ)
2020-04-29 18:31:50 +03:00
case reflect.Bool:
2020-04-30 07:52:24 +03:00
return e.compileBool(typ)
2020-04-29 18:31:50 +03:00
case reflect.Interface:
2020-04-30 07:52:24 +03:00
return e.compileInterface(typ)
2020-04-29 18:31:50 +03:00
}
return nil, xerrors.Errorf("failed to encode type %s: %w", typ.String(), ErrUnsupportedType)
}
2020-04-30 05:56:56 +03:00
func (e *Encoder) optimizeStructFieldPtrHead(typ *rtype, code *opcode) *opcode {
2020-04-29 19:44:48 +03:00
switch code.op {
case opStructFieldHead:
code.op = opStructFieldPtrHead
case opStructFieldHeadInt:
code.op = opStructFieldPtrHeadInt
2020-04-30 05:56:56 +03:00
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
2020-04-29 19:44:48 +03:00
case opStructFieldHeadString:
code.op = opStructFieldPtrHeadString
2020-04-30 05:56:56 +03:00
case opStructFieldHeadBool:
code.op = opStructFieldPtrHeadBool
2020-04-29 19:44:48 +03:00
default:
2020-04-30 05:56:56 +03:00
return newOpCode(opPtr, typ, code)
}
return code
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compilePtr(typ *rtype) (*opcode, error) {
code, err := e.compile(typ.Elem())
2020-04-30 05:56:56 +03:00
if err != nil {
return nil, err
2020-04-29 19:44:48 +03:00
}
2020-04-30 05:56:56 +03:00
return e.optimizeStructFieldPtrHead(typ, code), nil
2020-04-29 18:31:50 +03:00
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileInt(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opInt, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileInt8(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opInt8, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileInt16(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opInt16, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileInt32(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opInt32, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileInt64(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opInt64, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileUint(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opUint, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileUint8(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opUint8, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileUint16(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opUint16, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileUint32(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opUint32, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileUint64(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opUint64, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileFloat32(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opFloat32, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileFloat64(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opFloat64, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileString(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opString, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileBool(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
return newOpCode(opBool, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileInterface(typ *rtype) (*opcode, error) {
return newOpCode(opInterface, typ, newEndOp()), nil
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileSlice(typ *rtype) (*opcode, error) {
2020-04-29 18:31:50 +03:00
elem := typ.Elem()
size := elem.Size()
2020-04-30 07:52:24 +03:00
code, err := e.compile(elem)
2020-04-29 18:31:50 +03:00
if err != nil {
return nil, err
}
2020-04-29 19:44:48 +03:00
// header => opcode => elem => end
// ^ |
// |________|
2020-04-29 18:31:50 +03:00
2020-04-29 19:44:48 +03:00
header := newSliceHeaderCode()
2020-04-29 18:31:50 +03:00
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
}
2020-04-30 07:52:24 +03:00
func (e *Encoder) compileArray(typ *rtype) (*opcode, error) {
elem := typ.Elem()
alen := typ.Len()
size := elem.Size()
2020-04-30 07:52:24 +03:00
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())
2020-04-29 18:31:50 +03:00
2020-04-29 19:44:48 +03:00
header.elem = elemCode
header.end = end
header.next = code
2020-04-29 18:31:50 +03:00
code.beforeLastCode().next = (*opcode)(unsafe.Pointer(elemCode))
elemCode.next = code
elemCode.end = end
return (*opcode)(unsafe.Pointer(header)), nil
}
2020-04-30 07:52:24 +03:00
//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()
2020-04-30 07:52:24 +03:00
keyCode, err := e.compile(keyType)
if err != nil {
return nil, err
}
valueType := typ.Elem()
2020-04-30 07:52:24 +03:00
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
2020-04-29 18:31:50 +03:00
return (*opcode)(unsafe.Pointer(header)), nil
}
2020-04-30 07:52: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
}
func (e *Encoder) compileStruct(typ *rtype) (*opcode, error) {
2020-04-30 05:56:56 +03:00
// header => code => structField => code => end
// ^ |
// |__________|
2020-04-29 18:31:50 +03:00
fieldNum := typ.NumField()
fieldIdx := 0
2020-04-29 19:44:48 +03:00
var (
head *structFieldCode
code *opcode
prevField *structFieldCode
)
2020-04-29 18:31:50 +03:00
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)
2020-04-30 07:52:24 +03:00
valueCode, err := e.compile(fieldType)
2020-04-29 18:31:50 +03:00
if err != nil {
return nil, err
}
key := fmt.Sprintf(`"%s":`, keyName)
2020-04-30 05:56:56 +03:00
fieldCode := &structFieldCode{
opcodeHeader: &opcodeHeader{
typ: fieldType,
next: valueCode,
},
key: []byte(key),
offset: field.Offset,
}
2020-04-29 18:31:50 +03:00
if fieldIdx == 0 {
2020-04-30 05:56:56 +03:00
fieldCode.op = opStructFieldHead
2020-04-29 19:44:48 +03:00
head = fieldCode
code = (*opcode)(unsafe.Pointer(fieldCode))
2020-04-29 18:31:50 +03:00
prevField = fieldCode
2020-04-29 19:44:48 +03:00
switch valueCode.op {
case opInt:
fieldCode.op = opStructFieldHeadInt
2020-04-30 05:56:56 +03:00
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
2020-04-29 19:44:48 +03:00
case opString:
fieldCode.op = opStructFieldHeadString
2020-04-30 05:56:56 +03:00
case opBool:
fieldCode.op = opStructFieldHeadBool
2020-04-29 19:44:48 +03:00
default:
2020-04-29 18:31:50 +03:00
code = valueCode.beforeLastCode()
}
} else {
2020-04-30 05:56:56 +03:00
fieldCode.op = opStructField
2020-04-29 18:31:50 +03:00
code.next = (*opcode)(unsafe.Pointer(fieldCode))
prevField.nextField = (*opcode)(unsafe.Pointer(fieldCode))
prevField = fieldCode
2020-04-30 05:56:56 +03:00
code = (*opcode)(unsafe.Pointer(fieldCode))
2020-04-29 19:44:48 +03:00
switch valueCode.op {
case opInt:
2020-04-29 18:31:50 +03:00
fieldCode.op = opStructFieldInt
2020-04-30 05:56:56 +03:00
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
2020-04-29 19:44:48 +03:00
case opString:
2020-04-29 18:31:50 +03:00
fieldCode.op = opStructFieldString
2020-04-30 05:56:56 +03:00
case opBool:
fieldCode.op = opStructFieldBool
2020-04-29 19:44:48 +03:00
default:
2020-04-29 18:31:50 +03:00
code = valueCode.beforeLastCode()
}
}
2020-04-29 19:44:48 +03:00
prevField.nextField = newEndOp()
2020-04-29 18:31:50 +03:00
fieldIdx++
}
2020-04-29 19:44:48 +03:00
structEndCode := newOpCode(opStructEnd, nil, nil)
head.end = structEndCode
2020-04-29 18:31:50 +03:00
code.next = structEndCode
2020-04-29 19:44:48 +03:00
structEndCode.next = newEndOp()
return (*opcode)(unsafe.Pointer(head)), nil
2020-04-29 18:31:50 +03:00
}