package msgpack
import (
"encoding"
"errors"
"fmt"
"reflect"
)
var (
interfaceType = reflect .TypeOf ((*interface {})(nil )).Elem ()
stringType = reflect .TypeOf ((*string )(nil )).Elem ()
boolType = reflect .TypeOf ((*bool )(nil )).Elem ()
)
var valueDecoders []decoderFunc
func init() {
valueDecoders = []decoderFunc {
reflect .Bool : decodeBoolValue ,
reflect .Int : decodeInt64Value ,
reflect .Int8 : decodeInt64Value ,
reflect .Int16 : decodeInt64Value ,
reflect .Int32 : decodeInt64Value ,
reflect .Int64 : decodeInt64Value ,
reflect .Uint : decodeUint64Value ,
reflect .Uint8 : decodeUint64Value ,
reflect .Uint16 : decodeUint64Value ,
reflect .Uint32 : decodeUint64Value ,
reflect .Uint64 : decodeUint64Value ,
reflect .Float32 : decodeFloat32Value ,
reflect .Float64 : decodeFloat64Value ,
reflect .Complex64 : decodeUnsupportedValue ,
reflect .Complex128 : decodeUnsupportedValue ,
reflect .Array : decodeArrayValue ,
reflect .Chan : decodeUnsupportedValue ,
reflect .Func : decodeUnsupportedValue ,
reflect .Interface : decodeInterfaceValue ,
reflect .Map : decodeMapValue ,
reflect .Ptr : decodeUnsupportedValue ,
reflect .Slice : decodeSliceValue ,
reflect .String : decodeStringValue ,
reflect .Struct : decodeStructValue ,
reflect .UnsafePointer : decodeUnsupportedValue ,
}
}
func getDecoder(typ reflect .Type ) decoderFunc {
if v , ok := typeDecMap .Load (typ ); ok {
return v .(decoderFunc )
}
fn := _getDecoder (typ )
typeDecMap .Store (typ , fn )
return fn
}
func _getDecoder(typ reflect .Type ) decoderFunc {
kind := typ .Kind ()
if kind == reflect .Ptr {
if _ , ok := typeDecMap .Load (typ .Elem ()); ok {
return ptrValueDecoder (typ )
}
}
if typ .Implements (customDecoderType ) {
return nilAwareDecoder (typ , decodeCustomValue )
}
if typ .Implements (unmarshalerType ) {
return nilAwareDecoder (typ , unmarshalValue )
}
if typ .Implements (binaryUnmarshalerType ) {
return nilAwareDecoder (typ , unmarshalBinaryValue )
}
if typ .Implements (textUnmarshalerType ) {
return nilAwareDecoder (typ , unmarshalTextValue )
}
if kind != reflect .Ptr {
ptr := reflect .PtrTo (typ )
if ptr .Implements (customDecoderType ) {
return addrDecoder (nilAwareDecoder (typ , decodeCustomValue ))
}
if ptr .Implements (unmarshalerType ) {
return addrDecoder (nilAwareDecoder (typ , unmarshalValue ))
}
if ptr .Implements (binaryUnmarshalerType ) {
return addrDecoder (nilAwareDecoder (typ , unmarshalBinaryValue ))
}
if ptr .Implements (textUnmarshalerType ) {
return addrDecoder (nilAwareDecoder (typ , unmarshalTextValue ))
}
}
switch kind {
case reflect .Ptr :
return ptrValueDecoder (typ )
case reflect .Slice :
elem := typ .Elem ()
if elem .Kind () == reflect .Uint8 {
return decodeBytesValue
}
if elem == stringType {
return decodeStringSliceValue
}
case reflect .Array :
if typ .Elem ().Kind () == reflect .Uint8 {
return decodeByteArrayValue
}
case reflect .Map :
if typ .Key () == stringType {
switch typ .Elem () {
case stringType :
return decodeMapStringStringValue
case interfaceType :
return decodeMapStringInterfaceValue
}
}
}
return valueDecoders [kind ]
}
func ptrValueDecoder(typ reflect .Type ) decoderFunc {
decoder := getDecoder (typ .Elem ())
return func (d *Decoder , v reflect .Value ) error {
if d .hasNilCode () {
if !v .IsNil () {
v .Set (d .newValue (typ ).Elem ())
}
return d .DecodeNil ()
}
if v .IsNil () {
v .Set (d .newValue (typ .Elem ()))
}
return decoder (d , v .Elem ())
}
}
func addrDecoder(fn decoderFunc ) decoderFunc {
return func (d *Decoder , v reflect .Value ) error {
if !v .CanAddr () {
return fmt .Errorf ("msgpack: Decode(nonaddressable %T)" , v .Interface ())
}
return fn (d , v .Addr ())
}
}
func nilAwareDecoder(typ reflect .Type , fn decoderFunc ) decoderFunc {
if nilable (typ .Kind ()) {
return func (d *Decoder , v reflect .Value ) error {
if d .hasNilCode () {
return d .decodeNilValue (v )
}
if v .IsNil () {
v .Set (d .newValue (typ .Elem ()))
}
return fn (d , v )
}
}
return func (d *Decoder , v reflect .Value ) error {
if d .hasNilCode () {
return d .decodeNilValue (v )
}
return fn (d , v )
}
}
func decodeBoolValue(d *Decoder , v reflect .Value ) error {
flag , err := d .DecodeBool ()
if err != nil {
return err
}
v .SetBool (flag )
return nil
}
func decodeInterfaceValue(d *Decoder , v reflect .Value ) error {
if v .IsNil () {
return d .interfaceValue (v )
}
return d .DecodeValue (v .Elem ())
}
func (d *Decoder ) interfaceValue (v reflect .Value ) error {
vv , err := d .decodeInterfaceCond ()
if err != nil {
return err
}
if vv != nil {
if v .Type () == errorType {
if vv , ok := vv .(string ); ok {
v .Set (reflect .ValueOf (errors .New (vv )))
return nil
}
}
v .Set (reflect .ValueOf (vv ))
}
return nil
}
func decodeUnsupportedValue(d *Decoder , v reflect .Value ) error {
return fmt .Errorf ("msgpack: Decode(unsupported %s)" , v .Type ())
}
func decodeCustomValue(d *Decoder , v reflect .Value ) error {
decoder := v .Interface ().(CustomDecoder )
return decoder .DecodeMsgpack (d )
}
func unmarshalValue(d *Decoder , v reflect .Value ) error {
var b []byte
d .rec = make ([]byte , 0 , 64 )
if err := d .Skip (); err != nil {
return err
}
b = d .rec
d .rec = nil
unmarshaler := v .Interface ().(Unmarshaler )
return unmarshaler .UnmarshalMsgpack (b )
}
func unmarshalBinaryValue(d *Decoder , v reflect .Value ) error {
data , err := d .DecodeBytes ()
if err != nil {
return err
}
unmarshaler := v .Interface ().(encoding .BinaryUnmarshaler )
return unmarshaler .UnmarshalBinary (data )
}
func unmarshalTextValue(d *Decoder , v reflect .Value ) error {
data , err := d .DecodeBytes ()
if err != nil {
return err
}
unmarshaler := v .Interface ().(encoding .TextUnmarshaler )
return unmarshaler .UnmarshalText (data )
}
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 .