surrealpatch/util/bytes/decode.go

148 lines
3.4 KiB
Go
Raw Normal View History

// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bytes
import (
"encoding"
"encoding/binary"
"errors"
"io"
"reflect"
)
type Decoder struct {
Order binary.ByteOrder
r *reader
}
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{
Order: binary.BigEndian,
r: &reader{r},
}
}
func (d *Decoder) Decode(v interface{}) (err error) {
// Check if the type implements the encoding.BinaryUnmarshaler interface, and use it if so.
if i, ok := v.(encoding.BinaryUnmarshaler); ok {
var l uint64
if l, err = binary.ReadUvarint(d.r); err != nil {
return
}
buf := make([]byte, l)
_, err = d.r.Read(buf)
return i.UnmarshalBinary(buf)
}
// Otherwise, use reflection.
rv := reflect.Indirect(reflect.ValueOf(v))
if !rv.CanAddr() {
return errors.New("binary: can only Decode to pointer type")
}
t := rv.Type()
switch t.Kind() {
case reflect.Array:
len := t.Len()
for i := 0; i < int(len); i++ {
if err = d.Decode(rv.Index(i).Addr().Interface()); err != nil {
return
}
}
case reflect.Slice:
var l uint64
if l, err = binary.ReadUvarint(d.r); err != nil {
return
}
if t.Kind() == reflect.Slice {
rv.Set(reflect.MakeSlice(t, int(l), int(l)))
} else if int(l) != t.Len() {
return errors.New("binary: encoded size != real size")
}
for i := 0; i < int(l); i++ {
if err = d.Decode(rv.Index(i).Addr().Interface()); err != nil {
return
}
}
case reflect.Struct:
l := rv.NumField()
for i := 0; i < l; i++ {
if v := rv.Field(i); v.CanSet() && t.Field(i).Name != "_" {
if err = d.Decode(v.Addr().Interface()); err != nil {
return
}
}
}
case reflect.Map:
var l uint64
if l, err = binary.ReadUvarint(d.r); err != nil {
return
}
kt := t.Key()
vt := t.Elem()
rv.Set(reflect.MakeMap(t))
for i := 0; i < int(l); i++ {
kv := reflect.Indirect(reflect.New(kt))
if err = d.Decode(kv.Addr().Interface()); err != nil {
return
}
vv := reflect.Indirect(reflect.New(vt))
if err = d.Decode(vv.Addr().Interface()); err != nil {
return
}
rv.SetMapIndex(kv, vv)
}
case reflect.String:
var l uint64
if l, err = binary.ReadUvarint(d.r); err != nil {
return
}
buf := make([]byte, l)
_, err = d.r.Read(buf)
rv.SetString(string(buf))
case reflect.Bool:
var out byte
err = binary.Read(d.r, d.Order, &out)
rv.SetBool(out != 0)
case reflect.Int:
var out int64
err = binary.Read(d.r, d.Order, &out)
rv.SetInt(out)
case reflect.Uint:
var out uint64
err = binary.Read(d.r, d.Order, &out)
rv.SetUint(out)
case reflect.Int8, reflect.Uint8, reflect.Int16, reflect.Uint16,
reflect.Int32, reflect.Uint32, reflect.Int64, reflect.Uint64,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
err = binary.Read(d.r, d.Order, v)
default:
return errors.New("binary: unsupported type " + t.String())
}
return
}