blob: 778d80b937f3ca21480b0e4fd06ddde58b7e0225 [file] [log] [blame]
package msgpack
import (
"fmt"
"reflect"
"github.com/vmihailenco/msgpack/codes"
)
const sliceElemsAllocLimit = 1e4
var sliceStringPtrType = reflect.TypeOf((*[]string)(nil))
// DecodeArrayLen decodes array length. Length is -1 when array is nil.
func (d *Decoder) DecodeArrayLen() (int, error) {
c, err := d.readCode()
if err != nil {
return 0, err
}
return d.arrayLen(c)
}
func (d *Decoder) arrayLen(c codes.Code) (int, error) {
if c == codes.Nil {
return -1, nil
} else if c >= codes.FixedArrayLow && c <= codes.FixedArrayHigh {
return int(c & codes.FixedArrayMask), nil
}
switch c {
case codes.Array16:
n, err := d.uint16()
return int(n), err
case codes.Array32:
n, err := d.uint32()
return int(n), err
}
return 0, fmt.Errorf("msgpack: invalid code=%x decoding array length", c)
}
func decodeStringSliceValue(d *Decoder, v reflect.Value) error {
ptr := v.Addr().Convert(sliceStringPtrType).Interface().(*[]string)
return d.decodeStringSlicePtr(ptr)
}
func (d *Decoder) decodeStringSlicePtr(ptr *[]string) error {
n, err := d.DecodeArrayLen()
if err != nil {
return err
}
if n == -1 {
return nil
}
ss := setStringsCap(*ptr, n)
for i := 0; i < n; i++ {
s, err := d.DecodeString()
if err != nil {
return err
}
ss = append(ss, s)
}
*ptr = ss
return nil
}
func setStringsCap(s []string, n int) []string {
if n > sliceElemsAllocLimit {
n = sliceElemsAllocLimit
}
if s == nil {
return make([]string, 0, n)
}
if cap(s) >= n {
return s[:0]
}
s = s[:cap(s)]
s = append(s, make([]string, n-len(s))...)
return s[:0]
}
func decodeSliceValue(d *Decoder, v reflect.Value) error {
n, err := d.DecodeArrayLen()
if err != nil {
return err
}
if n == -1 {
v.Set(reflect.Zero(v.Type()))
return nil
}
if n == 0 && v.IsNil() {
v.Set(reflect.MakeSlice(v.Type(), 0, 0))
return nil
}
if v.Cap() >= n {
v.Set(v.Slice(0, n))
} else if v.Len() < v.Cap() {
v.Set(v.Slice(0, v.Cap()))
}
for i := 0; i < n; i++ {
if i >= v.Len() {
v.Set(growSliceValue(v, n))
}
sv := v.Index(i)
if err := d.DecodeValue(sv); err != nil {
return err
}
}
return nil
}
func growSliceValue(v reflect.Value, n int) reflect.Value {
diff := n - v.Len()
if diff > sliceElemsAllocLimit {
diff = sliceElemsAllocLimit
}
v = reflect.AppendSlice(v, reflect.MakeSlice(v.Type(), diff, diff))
return v
}
func decodeArrayValue(d *Decoder, v reflect.Value) error {
n, err := d.DecodeArrayLen()
if err != nil {
return err
}
if n == -1 {
return nil
}
if n > v.Len() {
return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n)
}
for i := 0; i < n; i++ {
sv := v.Index(i)
if err := d.DecodeValue(sv); err != nil {
return err
}
}
return nil
}
func (d *Decoder) DecodeSlice() ([]interface{}, error) {
c, err := d.readCode()
if err != nil {
return nil, err
}
return d.decodeSlice(c)
}
func (d *Decoder) decodeSlice(c codes.Code) ([]interface{}, error) {
n, err := d.arrayLen(c)
if err != nil {
return nil, err
}
if n == -1 {
return nil, nil
}
s := make([]interface{}, 0, min(n, sliceElemsAllocLimit))
for i := 0; i < n; i++ {
v, err := d.decodeInterfaceCond()
if err != nil {
return nil, err
}
s = append(s, v)
}
return s, nil
}
func (d *Decoder) skipSlice(c codes.Code) error {
n, err := d.arrayLen(c)
if err != nil {
return err
}
for i := 0; i < n; i++ {
if err := d.Skip(); err != nil {
return err
}
}
return nil
}