package msgpack
import (
"bytes"
"io"
"reflect"
"sync"
"time"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
const (
sortMapKeysFlag uint32 = 1 << iota
arrayEncodedStructsFlag
useCompactIntsFlag
useCompactFloatsFlag
useInternedStringsFlag
omitEmptyFlag
)
type writer interface {
io .Writer
WriteByte(byte ) error
}
type byteWriter struct {
io .Writer
}
func newByteWriter(w io .Writer ) byteWriter {
return byteWriter {
Writer : w ,
}
}
func (bw byteWriter ) WriteByte (c byte ) error {
_ , err := bw .Write ([]byte {c })
return err
}
var encPool = sync .Pool {
New : func () interface {} {
return NewEncoder (nil )
},
}
func GetEncoder () *Encoder {
return encPool .Get ().(*Encoder )
}
func PutEncoder (enc *Encoder ) {
enc .w = nil
encPool .Put (enc )
}
func Marshal (v interface {}) ([]byte , error ) {
enc := GetEncoder ()
var buf bytes .Buffer
enc .Reset (&buf )
err := enc .Encode (v )
b := buf .Bytes ()
PutEncoder (enc )
if err != nil {
return nil , err
}
return b , err
}
type Encoder struct {
w writer
dict map [string ]int
structTag string
buf []byte
timeBuf []byte
flags uint32
}
func NewEncoder (w io .Writer ) *Encoder {
e := &Encoder {
buf : make ([]byte , 9 ),
}
e .Reset (w )
return e
}
func (e *Encoder ) Writer () io .Writer {
return e .w
}
func (e *Encoder ) Reset (w io .Writer ) {
e .ResetDict (w , nil )
}
func (e *Encoder ) ResetDict (w io .Writer , dict map [string ]int ) {
e .ResetWriter (w )
e .flags = 0
e .structTag = ""
e .dict = dict
}
func (e *Encoder ) WithDict (dict map [string ]int , fn func (*Encoder ) error ) error {
oldDict := e .dict
e .dict = dict
err := fn (e )
e .dict = oldDict
return err
}
func (e *Encoder ) ResetWriter (w io .Writer ) {
e .dict = nil
if bw , ok := w .(writer ); ok {
e .w = bw
} else if w == nil {
e .w = nil
} else {
e .w = newByteWriter (w )
}
}
func (e *Encoder ) SetSortMapKeys (on bool ) *Encoder {
if on {
e .flags |= sortMapKeysFlag
} else {
e .flags &= ^sortMapKeysFlag
}
return e
}
func (e *Encoder ) SetCustomStructTag (tag string ) {
e .structTag = tag
}
func (e *Encoder ) SetOmitEmpty (on bool ) {
if on {
e .flags |= omitEmptyFlag
} else {
e .flags &= ^omitEmptyFlag
}
}
func (e *Encoder ) UseArrayEncodedStructs (on bool ) {
if on {
e .flags |= arrayEncodedStructsFlag
} else {
e .flags &= ^arrayEncodedStructsFlag
}
}
func (e *Encoder ) UseCompactInts (on bool ) {
if on {
e .flags |= useCompactIntsFlag
} else {
e .flags &= ^useCompactIntsFlag
}
}
func (e *Encoder ) UseCompactFloats (on bool ) {
if on {
e .flags |= useCompactFloatsFlag
} else {
e .flags &= ^useCompactFloatsFlag
}
}
func (e *Encoder ) UseInternedStrings (on bool ) {
if on {
e .flags |= useInternedStringsFlag
} else {
e .flags &= ^useInternedStringsFlag
}
}
func (e *Encoder ) Encode (v interface {}) error {
switch v := v .(type ) {
case nil :
return e .EncodeNil ()
case string :
return e .EncodeString (v )
case []byte :
return e .EncodeBytes (v )
case int :
return e .EncodeInt (int64 (v ))
case int64 :
return e .encodeInt64Cond (v )
case uint :
return e .EncodeUint (uint64 (v ))
case uint64 :
return e .encodeUint64Cond (v )
case bool :
return e .EncodeBool (v )
case float32 :
return e .EncodeFloat32 (v )
case float64 :
return e .EncodeFloat64 (v )
case time .Duration :
return e .encodeInt64Cond (int64 (v ))
case time .Time :
return e .EncodeTime (v )
}
return e .EncodeValue (reflect .ValueOf (v ))
}
func (e *Encoder ) EncodeMulti (v ...interface {}) error {
for _ , vv := range v {
if err := e .Encode (vv ); err != nil {
return err
}
}
return nil
}
func (e *Encoder ) EncodeValue (v reflect .Value ) error {
fn := getEncoder (v .Type ())
return fn (e , v )
}
func (e *Encoder ) EncodeNil () error {
return e .writeCode (msgpcode .Nil )
}
func (e *Encoder ) EncodeBool (value bool ) error {
if value {
return e .writeCode (msgpcode .True )
}
return e .writeCode (msgpcode .False )
}
func (e *Encoder ) EncodeDuration (d time .Duration ) error {
return e .EncodeInt (int64 (d ))
}
func (e *Encoder ) writeCode (c byte ) error {
return e .w .WriteByte (c )
}
func (e *Encoder ) write (b []byte ) error {
_ , err := e .w .Write (b )
return err
}
func (e *Encoder ) writeString (s string ) error {
_ , err := e .w .Write (stringToBytes (s ))
return err
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .