2020-04-19 13:51:22 +03:00
package json
import (
2020-04-21 08:19:50 +03:00
"io"
2020-04-19 13:51:22 +03:00
"reflect"
"strconv"
"sync"
"unsafe"
)
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
}
const (
bufSize = 1024
)
2020-04-30 07:52:24 +03:00
type opcodeMap struct {
2020-04-28 12:25:51 +03:00
sync . Map
}
2020-05-01 07:12:01 +03:00
func ( m * opcodeMap ) Get ( k * rtype ) * opcode {
2020-04-28 12:25:51 +03:00
if v , ok := m . Load ( k ) ; ok {
2020-04-30 07:52:24 +03:00
return v . ( * opcode )
2020-04-28 12:25:51 +03:00
}
return nil
}
2020-05-01 07:12:01 +03:00
func ( m * opcodeMap ) Set ( k * rtype , op * opcode ) {
2020-04-28 12:25:51 +03:00
m . Store ( k , op )
}
2020-04-19 13:51:22 +03:00
var (
2020-04-30 07:52:24 +03:00
encPool sync . Pool
cachedOpcode opcodeMap
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-30 07:52:24 +03:00
cachedOpcode = opcodeMap { }
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-30 05:56:56 +03:00
func ( e * Encoder ) encodeBytes ( b [ ] byte ) {
e . buf = append ( e . buf , b ... )
}
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-05-01 07:12:01 +03:00
if code := cachedOpcode . Get ( typ ) ; code != nil {
2020-04-28 12:25:51 +03:00
p := uintptr ( header . ptr )
2020-04-30 07:52:24 +03:00
code . ptr = p
if err := e . run ( code ) ; err != nil {
2020-04-29 18:31:50 +03:00
return err
}
2020-04-28 12:25:51 +03:00
return nil
}
2020-04-30 07:52:24 +03:00
code , err := e . compile ( typ )
2020-04-19 13:51:22 +03:00
if err != nil {
2020-04-30 07:52:24 +03:00
return err
2020-04-19 13:51:22 +03:00
}
2020-05-01 07:12:01 +03:00
cachedOpcode . Set ( typ , code )
2020-04-28 12:25:51 +03:00
p := uintptr ( header . ptr )
2020-04-30 07:52:24 +03:00
code . ptr = p
return e . run ( code )
2020-04-28 12:25:51 +03:00
}