surrealpatch/util/bytes/encode.go
2016-02-29 17:29:58 +00:00

147 lines
3.2 KiB
Go

// 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 Encoder struct {
Order binary.ByteOrder
w io.Writer
buf []byte
}
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{
Order: binary.BigEndian,
w: w,
buf: make([]byte, 8),
}
}
func (e *Encoder) writeVarint(v int) error {
l := binary.PutUvarint(e.buf, uint64(v))
_, err := e.w.Write(e.buf[:l])
return err
}
func (b *Encoder) Encode(v interface{}) (err error) {
switch cv := v.(type) {
case encoding.BinaryMarshaler:
buf, err := cv.MarshalBinary()
if err != nil {
return err
}
if err = b.writeVarint(len(buf)); err != nil {
return err
}
_, err = b.w.Write(buf)
case []byte: // fast-path byte arrays
if err = b.writeVarint(len(cv)); err != nil {
return
}
_, err = b.w.Write(cv)
default:
rv := reflect.Indirect(reflect.ValueOf(v))
t := rv.Type()
switch t.Kind() {
case reflect.Array:
l := t.Len()
for i := 0; i < l; i++ {
if err = b.Encode(rv.Index(i).Addr().Interface()); err != nil {
return
}
}
case reflect.Slice:
l := rv.Len()
if err = b.writeVarint(l); err != nil {
return
}
for i := 0; i < l; i++ {
if err = b.Encode(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 != "_" {
// take the address of the field, so structs containing structs
// are correctly encoded.
if err = b.Encode(v.Addr().Interface()); err != nil {
return
}
}
}
case reflect.Map:
l := rv.Len()
if err = b.writeVarint(l); err != nil {
return
}
for _, key := range rv.MapKeys() {
value := rv.MapIndex(key)
if err = b.Encode(key.Interface()); err != nil {
return err
}
if err = b.Encode(value.Interface()); err != nil {
return err
}
}
case reflect.String:
if err = b.writeVarint(rv.Len()); err != nil {
return
}
_, err = b.w.Write([]byte(rv.String()))
case reflect.Bool:
var out byte
if rv.Bool() {
out = 1
}
err = binary.Write(b.w, b.Order, out)
case reflect.Int:
err = binary.Write(b.w, b.Order, int64(rv.Int()))
case reflect.Uint:
err = binary.Write(b.w, b.Order, int64(rv.Uint()))
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.Write(b.w, b.Order, v)
default:
return errors.New("binary: unsupported type " + t.String())
}
}
return
}