package msgpack
import (
"errors"
"fmt"
"reflect"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
var errArrayStruct = errors .New ("msgpack: number of fields in array-encoded struct has changed" )
var (
mapStringStringPtrType = reflect .TypeOf ((*map [string ]string )(nil ))
mapStringStringType = mapStringStringPtrType .Elem ()
mapStringBoolPtrType = reflect .TypeOf ((*map [string ]bool )(nil ))
mapStringBoolType = mapStringBoolPtrType .Elem ()
)
var (
mapStringInterfacePtrType = reflect .TypeOf ((*map [string ]interface {})(nil ))
mapStringInterfaceType = mapStringInterfacePtrType .Elem ()
)
func decodeMapValue(d *Decoder , v reflect .Value ) error {
n , err := d .DecodeMapLen ()
if err != nil {
return err
}
typ := v .Type ()
if n == -1 {
v .Set (reflect .Zero (typ ))
return nil
}
if v .IsNil () {
ln := n
if d .flags &disableAllocLimitFlag == 0 {
ln = min (ln , maxMapSize )
}
v .Set (reflect .MakeMapWithSize (typ , ln ))
}
if n == 0 {
return nil
}
return d .decodeTypedMapValue (v , n )
}
func (d *Decoder ) decodeMapDefault () (interface {}, error ) {
if d .mapDecoder != nil {
return d .mapDecoder (d )
}
return d .DecodeMap ()
}
func (d *Decoder ) DecodeMapLen () (int , error ) {
c , err := d .readCode ()
if err != nil {
return 0 , err
}
if msgpcode .IsExt (c ) {
if err = d .skipExtHeader (c ); err != nil {
return 0 , err
}
c , err = d .readCode ()
if err != nil {
return 0 , err
}
}
return d .mapLen (c )
}
func (d *Decoder ) mapLen (c byte ) (int , error ) {
if c == msgpcode .Nil {
return -1 , nil
}
if c >= msgpcode .FixedMapLow && c <= msgpcode .FixedMapHigh {
return int (c & msgpcode .FixedMapMask ), nil
}
if c == msgpcode .Map16 {
size , err := d .uint16 ()
return int (size ), err
}
if c == msgpcode .Map32 {
size , err := d .uint32 ()
return int (size ), err
}
return 0 , unexpectedCodeError {code : c , hint : "map length" }
}
func decodeMapStringStringValue(d *Decoder , v reflect .Value ) error {
mptr := v .Addr ().Convert (mapStringStringPtrType ).Interface ().(*map [string ]string )
return d .decodeMapStringStringPtr (mptr )
}
func (d *Decoder ) decodeMapStringStringPtr (ptr *map [string ]string ) error {
size , err := d .DecodeMapLen ()
if err != nil {
return err
}
if size == -1 {
*ptr = nil
return nil
}
m := *ptr
if m == nil {
ln := size
if d .flags &disableAllocLimitFlag == 0 {
ln = min (size , maxMapSize )
}
*ptr = make (map [string ]string , ln )
m = *ptr
}
for i := 0 ; i < size ; i ++ {
mk , err := d .DecodeString ()
if err != nil {
return err
}
mv , err := d .DecodeString ()
if err != nil {
return err
}
m [mk ] = mv
}
return nil
}
func decodeMapStringInterfaceValue(d *Decoder , v reflect .Value ) error {
ptr := v .Addr ().Convert (mapStringInterfacePtrType ).Interface ().(*map [string ]interface {})
return d .decodeMapStringInterfacePtr (ptr )
}
func (d *Decoder ) decodeMapStringInterfacePtr (ptr *map [string ]interface {}) error {
m , err := d .DecodeMap ()
if err != nil {
return err
}
*ptr = m
return nil
}
func (d *Decoder ) DecodeMap () (map [string ]interface {}, error ) {
n , err := d .DecodeMapLen ()
if err != nil {
return nil , err
}
if n == -1 {
return nil , nil
}
m := make (map [string ]interface {}, n )
for i := 0 ; i < n ; i ++ {
mk , err := d .DecodeString ()
if err != nil {
return nil , err
}
mv , err := d .decodeInterfaceCond ()
if err != nil {
return nil , err
}
m [mk ] = mv
}
return m , nil
}
func (d *Decoder ) DecodeUntypedMap () (map [interface {}]interface {}, error ) {
n , err := d .DecodeMapLen ()
if err != nil {
return nil , err
}
if n == -1 {
return nil , nil
}
m := make (map [interface {}]interface {}, n )
for i := 0 ; i < n ; i ++ {
mk , err := d .decodeInterfaceCond ()
if err != nil {
return nil , err
}
mv , err := d .decodeInterfaceCond ()
if err != nil {
return nil , err
}
m [mk ] = mv
}
return m , nil
}
func (d *Decoder ) DecodeTypedMap () (interface {}, error ) {
n , err := d .DecodeMapLen ()
if err != nil {
return nil , err
}
if n <= 0 {
return nil , nil
}
key , err := d .decodeInterfaceCond ()
if err != nil {
return nil , err
}
value , err := d .decodeInterfaceCond ()
if err != nil {
return nil , err
}
keyType := reflect .TypeOf (key )
valueType := reflect .TypeOf (value )
if !keyType .Comparable () {
return nil , fmt .Errorf ("msgpack: unsupported map key: %s" , keyType .String ())
}
mapType := reflect .MapOf (keyType , valueType )
ln := n
if d .flags &disableAllocLimitFlag == 0 {
ln = min (ln , maxMapSize )
}
mapValue := reflect .MakeMapWithSize (mapType , ln )
mapValue .SetMapIndex (reflect .ValueOf (key ), reflect .ValueOf (value ))
n --
if err := d .decodeTypedMapValue (mapValue , n ); err != nil {
return nil , err
}
return mapValue .Interface (), nil
}
func (d *Decoder ) decodeTypedMapValue (v reflect .Value , n int ) error {
var (
typ = v .Type ()
keyType = typ .Key ()
valueType = typ .Elem ()
)
for i := 0 ; i < n ; i ++ {
mk := d .newValue (keyType ).Elem ()
if err := d .DecodeValue (mk ); err != nil {
return err
}
mv := d .newValue (valueType ).Elem ()
if err := d .DecodeValue (mv ); err != nil {
return err
}
v .SetMapIndex (mk , mv )
}
return nil
}
func (d *Decoder ) skipMap (c byte ) error {
n , err := d .mapLen (c )
if err != nil {
return err
}
for i := 0 ; i < n ; i ++ {
if err := d .Skip (); err != nil {
return err
}
if err := d .Skip (); err != nil {
return err
}
}
return nil
}
func decodeStructValue(d *Decoder , v reflect .Value ) error {
c , err := d .readCode ()
if err != nil {
return err
}
n , err := d .mapLen (c )
if err == nil {
return d .decodeStruct (v , n )
}
var err2 error
n , err2 = d .arrayLen (c )
if err2 != nil {
return err
}
if n <= 0 {
v .Set (reflect .Zero (v .Type ()))
return nil
}
fields := structs .Fields (v .Type (), d .structTag )
if n != len (fields .List ) {
return errArrayStruct
}
for _ , f := range fields .List {
if err := f .DecodeValue (d , v ); err != nil {
return err
}
}
return nil
}
func (d *Decoder ) decodeStruct (v reflect .Value , n int ) error {
if n == -1 {
v .Set (reflect .Zero (v .Type ()))
return nil
}
fields := structs .Fields (v .Type (), d .structTag )
for i := 0 ; i < n ; i ++ {
name , err := d .decodeStringTemp ()
if err != nil {
return err
}
if f := fields .Map [name ]; f != nil {
if err := f .DecodeValue (d , v ); err != nil {
return err
}
continue
}
if d .flags &disallowUnknownFieldsFlag != 0 {
return fmt .Errorf ("msgpack: unknown field %q" , name )
}
if err := d .Skip (); err != nil {
return err
}
}
return nil
}
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 .