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
}
2020-04-28 12:25:51 +03:00
type EncodeOp func ( * Encoder , * rtype , uintptr ) error
2020-04-19 13:51:22 +03:00
const (
bufSize = 1024
)
2020-04-28 12:25:51 +03:00
type EncodeOpMap struct {
sync . Map
}
func ( m * EncodeOpMap ) Get ( k string ) EncodeOp {
if v , ok := m . Load ( k ) ; ok {
return v . ( EncodeOp )
}
return nil
}
func ( m * EncodeOpMap ) Set ( k string , op EncodeOp ) {
m . Store ( k , op )
}
2020-04-19 13:51:22 +03:00
var (
2020-04-28 12:25:51 +03:00
encPool sync . Pool
cachedEncodeOp EncodeOpMap
errCompileSlowPath = xerrors . New ( "json: detect dynamic type ( interface{} ) and compile with slow path" )
2020-04-19 13:51:22 +03:00
)
func init ( ) {
encPool = sync . Pool {
New : func ( ) interface { } {
return & Encoder {
buf : make ( [ ] byte , 0 , bufSize ) ,
pool : encPool ,
}
} ,
}
2020-04-28 12:25:51 +03:00
cachedEncodeOp = EncodeOpMap { }
2020-04-19 13:51:22 +03:00
}
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
2020-04-20 11:13:03 +03:00
if typ . Kind ( ) == reflect . Ptr {
2020-04-22 09:29:54 +03:00
typ = typ . Elem ( )
2020-04-20 11:13:03 +03:00
}
2020-04-28 12:25:51 +03:00
name := typ . String ( )
if op := cachedEncodeOp . Get ( name ) ; op != nil {
p := uintptr ( header . ptr )
op ( e , typ , p )
return nil
}
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-28 12:25:51 +03:00
if err == errCompileSlowPath {
slowOp , err := e . compileSlowPath ( typ )
if err != nil {
return err
}
op = slowOp
} else {
return err
}
2020-04-19 13:51:22 +03:00
}
2020-04-19 17:13:24 +03:00
if name != "" {
2020-04-28 12:25:51 +03:00
cachedEncodeOp . Set ( name , op )
2020-04-19 17:13:24 +03:00
}
2020-04-28 12:25:51 +03:00
p := uintptr ( header . ptr )
op ( e , typ , p )
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 ( )
2020-04-21 07:38:48 +03:00
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 :
2020-04-28 12:25:51 +03:00
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 ( )
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-28 12:25:51 +03:00
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 )
2020-04-19 21:25:26 +03:00
if err != nil {
return nil , err
}
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
return op ( enc , typ . Elem ( ) , e . ptrToPtr ( p ) )
2020-04-19 21:25:26 +03:00
} , nil
}
2020-04-19 13:51:22 +03:00
func ( e * Encoder ) compileInt ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeInt ( e . ptrToInt ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileInt8 ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeInt8 ( e . ptrToInt8 ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileInt16 ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeInt16 ( e . ptrToInt16 ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileInt32 ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeInt32 ( e . ptrToInt32 ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileInt64 ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeInt64 ( e . ptrToInt64 ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileUint ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeUint ( e . ptrToUint ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileUint8 ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeUint8 ( e . ptrToUint8 ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileUint16 ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeUint16 ( e . ptrToUint16 ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileUint32 ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeUint32 ( e . ptrToUint32 ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileUint64 ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeUint64 ( e . ptrToUint64 ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileFloat32 ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeFloat32 ( e . ptrToFloat32 ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileFloat64 ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeFloat64 ( e . ptrToFloat64 ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileString ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeEscapedString ( e . ptrToString ( p ) )
return nil
} , nil
2020-04-19 13:51:22 +03:00
}
func ( e * Encoder ) compileBool ( ) ( EncodeOp , error ) {
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , p uintptr ) error {
enc . encodeBool ( e . ptrToBool ( p ) )
return nil
} , 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-28 12:25:51 +03:00
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 ( ) )
2020-04-19 17:13:24 +03:00
if err != nil {
return nil , err
}
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , base uintptr ) error {
2020-04-19 21:25:26 +03:00
if base == 0 {
2020-04-21 08:19:50 +03:00
enc . encodeString ( "null" )
2020-04-28 12:25:51 +03:00
return nil
2020-04-19 21:25:26 +03:00
}
2020-04-28 12:25:51 +03:00
size := typ . Elem ( ) . Size ( )
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 ++ {
2020-04-28 12:25:51 +03:00
if err := op ( enc , typ . Elem ( ) , slice . Data + uintptr ( i ) * size ) ; err != nil {
return err
}
2020-04-19 17:13:24 +03:00
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-28 12:25:51 +03:00
return nil
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-28 12:25:51 +03:00
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 ( )
2020-04-21 07:19:53 +03:00
alen := typ . Len ( )
2020-04-28 12:25:51 +03:00
op , err := e . compileSlowPath ( elem )
2020-04-21 07:19:53 +03:00
if err != nil {
return nil , err
}
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , base uintptr ) error {
2020-04-21 07:19:53 +03:00
if base == 0 {
2020-04-21 08:19:50 +03:00
enc . encodeString ( "null" )
2020-04-28 12:25:51 +03:00
return nil
2020-04-21 07:19:53 +03:00
}
2020-04-28 12:25:51 +03:00
elem := typ . Elem ( )
size := elem . Size ( )
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
}
2020-04-28 12:25:51 +03:00
if err := op ( enc , elem , base + uintptr ( i ) * size ) ; err != nil {
return err
}
2020-04-21 07:19:53 +03:00
}
2020-04-21 08:19:50 +03:00
enc . encodeByte ( ']' )
2020-04-28 12:25:51 +03:00
return nil
2020-04-21 07:19:53 +03:00
} , nil
2020-04-19 17:13:24 +03:00
}
2020-04-21 07:38:48 +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-28 12:25:51 +03:00
type encodeStructField struct {
op EncodeOp
fieldIndex int
}
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-28 12:25:51 +03:00
opQueue := make ( [ ] * encodeStructField , 0 , fieldNum )
2020-04-19 13:51:22 +03:00
for i := 0 ; i < fieldNum ; i ++ {
field := typ . Field ( i )
2020-04-21 07:38:48 +03:00
if e . isIgnoredStructField ( field ) {
continue
}
2020-04-19 14:28:13 +03:00
keyName := field . Name
2020-04-21 07:38:48 +03:00
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-28 12:25:51 +03:00
structField := & encodeStructField { fieldIndex : i }
structField . op = func ( enc * Encoder , typ * rtype , base uintptr ) error {
2020-04-21 08:19:50 +03:00
enc . encodeString ( key )
2020-04-28 12:25:51 +03:00
return op ( enc , fieldType , base + field . Offset )
}
opQueue = append ( opQueue , structField )
2020-04-19 13:51:22 +03:00
}
2020-04-28 12:25:51 +03:00
2020-04-19 13:51:22 +03:00
queueNum := len ( opQueue )
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , base uintptr ) error {
2020-04-19 21:25:26 +03:00
if base == 0 {
2020-04-21 08:19:50 +03:00
enc . encodeString ( "null" )
2020-04-28 12:25:51 +03:00
return nil
2020-04-19 21:25:26 +03:00
}
2020-04-21 08:19:50 +03:00
enc . encodeByte ( '{' )
2020-04-19 13:51:22 +03:00
for i := 0 ; i < queueNum ; i ++ {
2020-04-28 12:25:51 +03:00
if err := opQueue [ i ] . op ( enc , typ , base ) ; err != nil {
return err
}
2020-04-19 13:51:22 +03:00
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-28 12:25:51 +03:00
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
2020-04-19 13:51:22 +03:00
} , nil
}
2020-04-20 18:06:27 +03:00
//go:linkname mapiterinit reflect.mapiterinit
2020-04-28 12:25:51 +03:00
//go:noescape
func mapiterinit ( mapType * rtype , m unsafe . Pointer ) unsafe . Pointer
2020-04-20 18:06:27 +03:00
//go:linkname mapiterkey reflect.mapiterkey
2020-04-28 12:25:51 +03:00
//go:noescape
2020-04-20 18:06:27 +03:00
func mapiterkey ( it unsafe . Pointer ) unsafe . Pointer
//go:linkname mapiternext reflect.mapiternext
2020-04-28 12:25:51 +03:00
//go:noescape
2020-04-20 18:06:27 +03:00
func mapiternext ( it unsafe . Pointer )
//go:linkname maplen reflect.maplen
2020-04-28 12:25:51 +03:00
//go:noescape
2020-04-20 18:06:27 +03:00
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 ) {
2020-04-28 12:25:51 +03:00
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 ( ) )
2020-04-20 18:06:27 +03:00
if err != nil {
return nil , err
}
2020-04-28 12:25:51 +03:00
valueOp , err := e . compileSlowPath ( typ . Elem ( ) )
2020-04-20 18:06:27 +03:00
if err != nil {
return nil , err
}
2020-04-28 12:25:51 +03:00
return func ( enc * Encoder , typ * rtype , base uintptr ) error {
2020-04-20 18:06:27 +03:00
if base == 0 {
2020-04-21 08:19:50 +03:00
enc . encodeString ( "null" )
2020-04-28 12:25:51 +03:00
return nil
2020-04-20 18:06:27 +03:00
}
2020-04-21 08:19:50 +03:00
enc . encodeByte ( '{' )
2020-04-20 18:06:27 +03:00
mlen := maplen ( unsafe . Pointer ( base ) )
2020-04-28 12:25:51 +03:00
iter := mapiterinit ( typ , unsafe . Pointer ( base ) )
2020-04-20 18:06:27 +03:00
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 )
2020-04-28 12:25:51 +03:00
keyptr := uintptr ( key )
if err := keyOp ( enc , typ . Key ( ) , keyptr ) ; err != nil {
return err
}
2020-04-21 08:19:50 +03:00
enc . encodeByte ( ':' )
2020-04-28 12:25:51 +03:00
valueptr := uintptr ( value )
if err := valueOp ( enc , typ . Elem ( ) , valueptr ) ; err != nil {
return err
}
2020-04-20 18:06:27 +03:00
mapiternext ( iter )
}
2020-04-21 08:19:50 +03:00
enc . encodeByte ( '}' )
2020-04-28 12:25:51 +03:00
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 ) )
2020-04-20 18:06:27 +03:00
} , nil
}
2020-04-19 21:25:26 +03:00
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 ) ) }