package msgpack
import (
"encoding"
"fmt"
"reflect"
)
var valueEncoders []encoderFunc
func init () {
valueEncoders = []encoderFunc {
reflect .Bool : encodeBoolValue ,
reflect .Int : encodeIntValue ,
reflect .Int8 : encodeInt8CondValue ,
reflect .Int16 : encodeInt16CondValue ,
reflect .Int32 : encodeInt32CondValue ,
reflect .Int64 : encodeInt64CondValue ,
reflect .Uint : encodeUintValue ,
reflect .Uint8 : encodeUint8CondValue ,
reflect .Uint16 : encodeUint16CondValue ,
reflect .Uint32 : encodeUint32CondValue ,
reflect .Uint64 : encodeUint64CondValue ,
reflect .Float32 : encodeFloat32Value ,
reflect .Float64 : encodeFloat64Value ,
reflect .Complex64 : encodeUnsupportedValue ,
reflect .Complex128 : encodeUnsupportedValue ,
reflect .Array : encodeArrayValue ,
reflect .Chan : encodeUnsupportedValue ,
reflect .Func : encodeUnsupportedValue ,
reflect .Interface : encodeInterfaceValue ,
reflect .Map : encodeMapValue ,
reflect .Ptr : encodeUnsupportedValue ,
reflect .Slice : encodeSliceValue ,
reflect .String : encodeStringValue ,
reflect .Struct : encodeStructValue ,
reflect .UnsafePointer : encodeUnsupportedValue ,
}
}
func getEncoder (typ reflect .Type ) encoderFunc {
if v , ok := typeEncMap .Load (typ ); ok {
return v .(encoderFunc )
}
fn := _getEncoder (typ )
typeEncMap .Store (typ , fn )
return fn
}
func _getEncoder (typ reflect .Type ) encoderFunc {
kind := typ .Kind ()
if kind == reflect .Ptr {
if _ , ok := typeEncMap .Load (typ .Elem ()); ok {
return ptrEncoderFunc (typ )
}
}
if typ .Implements (customEncoderType ) {
return encodeCustomValue
}
if typ .Implements (marshalerType ) {
return marshalValue
}
if typ .Implements (binaryMarshalerType ) {
return marshalBinaryValue
}
if typ .Implements (textMarshalerType ) {
return marshalTextValue
}
if kind != reflect .Ptr {
ptr := reflect .PtrTo (typ )
if ptr .Implements (customEncoderType ) {
return encodeCustomValuePtr
}
if ptr .Implements (marshalerType ) {
return marshalValuePtr
}
if ptr .Implements (binaryMarshalerType ) {
return marshalBinaryValueAddr
}
if ptr .Implements (textMarshalerType ) {
return marshalTextValueAddr
}
}
if typ == errorType {
return encodeErrorValue
}
switch kind {
case reflect .Ptr :
return ptrEncoderFunc (typ )
case reflect .Slice :
elem := typ .Elem ()
if elem .Kind () == reflect .Uint8 {
return encodeByteSliceValue
}
if elem == stringType {
return encodeStringSliceValue
}
case reflect .Array :
if typ .Elem ().Kind () == reflect .Uint8 {
return encodeByteArrayValue
}
case reflect .Map :
if typ .Key () == stringType {
switch typ .Elem () {
case stringType :
return encodeMapStringStringValue
case interfaceType :
return encodeMapStringInterfaceValue
}
}
}
return valueEncoders [kind ]
}
func ptrEncoderFunc (typ reflect .Type ) encoderFunc {
encoder := getEncoder (typ .Elem ())
return func (e *Encoder , v reflect .Value ) error {
if v .IsNil () {
return e .EncodeNil ()
}
return encoder (e , v .Elem ())
}
}
func encodeCustomValuePtr (e *Encoder , v reflect .Value ) error {
if !v .CanAddr () {
return fmt .Errorf ("msgpack: Encode(non-addressable %T)" , v .Interface ())
}
encoder := v .Addr ().Interface ().(CustomEncoder )
return encoder .EncodeMsgpack (e )
}
func encodeCustomValue (e *Encoder , v reflect .Value ) error {
if nilable (v .Kind ()) && v .IsNil () {
return e .EncodeNil ()
}
encoder := v .Interface ().(CustomEncoder )
return encoder .EncodeMsgpack (e )
}
func marshalValuePtr (e *Encoder , v reflect .Value ) error {
if !v .CanAddr () {
return fmt .Errorf ("msgpack: Encode(non-addressable %T)" , v .Interface ())
}
return marshalValue (e , v .Addr ())
}
func marshalValue (e *Encoder , v reflect .Value ) error {
if nilable (v .Kind ()) && v .IsNil () {
return e .EncodeNil ()
}
marshaler := v .Interface ().(Marshaler )
b , err := marshaler .MarshalMsgpack ()
if err != nil {
return err
}
_, err = e .w .Write (b )
return err
}
func encodeBoolValue (e *Encoder , v reflect .Value ) error {
return e .EncodeBool (v .Bool ())
}
func encodeInterfaceValue (e *Encoder , v reflect .Value ) error {
if v .IsNil () {
return e .EncodeNil ()
}
return e .EncodeValue (v .Elem ())
}
func encodeErrorValue (e *Encoder , v reflect .Value ) error {
if v .IsNil () {
return e .EncodeNil ()
}
return e .EncodeString (v .Interface ().(error ).Error())
}
func encodeUnsupportedValue (e *Encoder , v reflect .Value ) error {
return fmt .Errorf ("msgpack: Encode(unsupported %s)" , v .Type ())
}
func nilable (kind reflect .Kind ) bool {
switch kind {
case reflect .Chan , reflect .Func , reflect .Interface , reflect .Map , reflect .Ptr , reflect .Slice :
return true
}
return false
}
func marshalBinaryValueAddr (e *Encoder , v reflect .Value ) error {
if !v .CanAddr () {
return fmt .Errorf ("msgpack: Encode(non-addressable %T)" , v .Interface ())
}
return marshalBinaryValue (e , v .Addr ())
}
func marshalBinaryValue (e *Encoder , v reflect .Value ) error {
if nilable (v .Kind ()) && v .IsNil () {
return e .EncodeNil ()
}
marshaler := v .Interface ().(encoding .BinaryMarshaler )
data , err := marshaler .MarshalBinary ()
if err != nil {
return err
}
return e .EncodeBytes (data )
}
func marshalTextValueAddr (e *Encoder , v reflect .Value ) error {
if !v .CanAddr () {
return fmt .Errorf ("msgpack: Encode(non-addressable %T)" , v .Interface ())
}
return marshalTextValue (e , v .Addr ())
}
func marshalTextValue (e *Encoder , v reflect .Value ) error {
if nilable (v .Kind ()) && v .IsNil () {
return e .EncodeNil ()
}
marshaler := v .Interface ().(encoding .TextMarshaler )
data , err := marshaler .MarshalText ()
if err != nil {
return err
}
return e .EncodeBytes (data )
}
The pages are generated with Golds v0.3.6 . (GOOS=darwin 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 @Go100and1 (reachable from the left QR code) to get the latest news of Golds .