261 lines
6.3 KiB
Go
261 lines
6.3 KiB
Go
|
package ssob
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"errors"
|
||
|
"reflect"
|
||
|
)
|
||
|
|
||
|
func marshalString(in string) (ret []byte) {
|
||
|
l := int64(len(in))
|
||
|
b := marshalInt64(l)
|
||
|
b = append(b, []byte(in)...)
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
func marshalInt8(in int8) (ret []byte) {
|
||
|
return []byte{byte(in)}
|
||
|
}
|
||
|
|
||
|
func marshalUint8(in uint8) (ret []byte) {
|
||
|
return []byte{byte(in)}
|
||
|
}
|
||
|
|
||
|
func marshalInt16(in int16) (ret []byte) {
|
||
|
out := make([]byte, 2)
|
||
|
|
||
|
binary.BigEndian.PutUint16(out, uint16(in))
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
func marshalUint16(in uint16) (ret []byte) {
|
||
|
out := make([]byte, 2)
|
||
|
|
||
|
binary.BigEndian.PutUint16(out, in)
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
func marshalInt32(in int32) (ret []byte) {
|
||
|
out := make([]byte, 4)
|
||
|
|
||
|
binary.BigEndian.PutUint32(out, uint32(in))
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
func marshalUint32(in uint32) (ret []byte) {
|
||
|
out := make([]byte, 4)
|
||
|
|
||
|
binary.BigEndian.PutUint32(out, in)
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
func marshalFloat32(in float32) (ret []byte) {
|
||
|
out := make([]byte, 4)
|
||
|
|
||
|
binary.BigEndian.PutUint32(out, uint32(in))
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
func marshalInt64(in int64) (ret []byte) {
|
||
|
out := make([]byte, 8)
|
||
|
|
||
|
binary.BigEndian.PutUint64(out, uint64(in))
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
func marshalUint64(in uint64) (ret []byte) {
|
||
|
out := make([]byte, 8)
|
||
|
|
||
|
binary.BigEndian.PutUint64(out, in)
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
func marshalFloat64(in float64) (ret []byte) {
|
||
|
out := make([]byte, 8)
|
||
|
|
||
|
binary.BigEndian.PutUint64(out, uint64(in))
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
type marshalFunc func(e interface{}) (ret []byte, err error)
|
||
|
|
||
|
var encoderCache map[string]marshalFunc
|
||
|
|
||
|
func init() {
|
||
|
encoderCache = make(map[string]marshalFunc)
|
||
|
encRegister(int8(0))
|
||
|
encRegister(uint8(0))
|
||
|
encRegister(int16(0))
|
||
|
encRegister(uint16(0))
|
||
|
encRegister(int32(0))
|
||
|
encRegister(uint32(0))
|
||
|
encRegister(float32(0))
|
||
|
encRegister(int64(0))
|
||
|
encRegister(uint64(0))
|
||
|
encRegister(float64(0))
|
||
|
encRegister(string(""))
|
||
|
}
|
||
|
|
||
|
func encRegister(e interface{}) (err error) {
|
||
|
v := reflect.ValueOf(e)
|
||
|
t := reflect.TypeOf(e)
|
||
|
switch t.Kind() {
|
||
|
case reflect.Invalid:
|
||
|
return errors.New("ssob: Invalid type")
|
||
|
case reflect.Slice:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
v := reflect.ValueOf(e)
|
||
|
l := v.Len()
|
||
|
ret, err = marshal(int64(l))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
for i := 0; i < l; i++ {
|
||
|
b, err := marshal(v.Index(i).Interface())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
ret = append(ret, b...)
|
||
|
}
|
||
|
|
||
|
return ret, nil
|
||
|
}
|
||
|
encoderCache[string(t.Kind())] = f
|
||
|
case reflect.Struct:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
n := v.NumField()
|
||
|
ret = []byte{}
|
||
|
for i := 0; i < n; i++ {
|
||
|
b, err := marshal(v.Field(i).Interface())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
ret = append(ret, b...)
|
||
|
}
|
||
|
return ret, nil
|
||
|
}
|
||
|
encoderCache[t.Name()] = f
|
||
|
case reflect.Int8:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
if i, ok := e.(int8); ok {
|
||
|
return marshalInt8(i), nil
|
||
|
}
|
||
|
return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected int8")
|
||
|
}
|
||
|
encoderCache[string(v.Kind())] = f
|
||
|
case reflect.Uint8:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
if i, ok := e.(uint8); ok {
|
||
|
return marshalUint8(i), nil
|
||
|
}
|
||
|
return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected uint8")
|
||
|
}
|
||
|
encoderCache[string(v.Kind())] = f
|
||
|
case reflect.Int16:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
if i, ok := e.(int16); ok {
|
||
|
return marshalInt16(i), nil
|
||
|
}
|
||
|
return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected int16")
|
||
|
}
|
||
|
encoderCache[string(v.Kind())] = f
|
||
|
case reflect.Uint16:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
if i, ok := e.(uint16); ok {
|
||
|
return marshalUint16(i), nil
|
||
|
}
|
||
|
return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected uint16")
|
||
|
}
|
||
|
encoderCache[string(v.Kind())] = f
|
||
|
case reflect.Int32:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
if i, ok := e.(int32); ok {
|
||
|
return marshalInt32(i), nil
|
||
|
}
|
||
|
return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected int32")
|
||
|
}
|
||
|
encoderCache[string(v.Kind())] = f
|
||
|
case reflect.Uint32:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
if i, ok := e.(uint32); ok {
|
||
|
return marshalUint32(i), nil
|
||
|
}
|
||
|
return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected uint32")
|
||
|
}
|
||
|
encoderCache[string(v.Kind())] = f
|
||
|
case reflect.Float32:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
if i, ok := e.(float32); ok {
|
||
|
return marshalFloat32(i), nil
|
||
|
}
|
||
|
return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected float32")
|
||
|
}
|
||
|
encoderCache[string(v.Kind())] = f
|
||
|
case reflect.Int64:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
if i, ok := e.(int64); ok {
|
||
|
return marshalInt64(i), nil
|
||
|
}
|
||
|
return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected int64")
|
||
|
}
|
||
|
encoderCache[string(v.Kind())] = f
|
||
|
case reflect.Uint64:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
if i, ok := e.(uint64); ok {
|
||
|
return marshalUint64(i), nil
|
||
|
}
|
||
|
return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected uint64")
|
||
|
}
|
||
|
encoderCache[string(v.Kind())] = f
|
||
|
case reflect.Float64:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
if i, ok := e.(float64); ok {
|
||
|
return marshalFloat64(i), nil
|
||
|
}
|
||
|
return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected float64")
|
||
|
}
|
||
|
encoderCache[string(v.Kind())] = f
|
||
|
case reflect.String:
|
||
|
f := func(e interface{}) (ret []byte, err error) {
|
||
|
if i, ok := e.(string); ok {
|
||
|
return marshalString(i), nil
|
||
|
}
|
||
|
return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected string")
|
||
|
}
|
||
|
encoderCache[string(v.Kind())] = f
|
||
|
default:
|
||
|
return errors.New("ssob: Unknown type " + string(v.Kind()))
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func marshal(e interface{}) (ret []byte, err error) {
|
||
|
var key string
|
||
|
t := reflect.TypeOf(e)
|
||
|
v := reflect.ValueOf(e)
|
||
|
if t.Kind() == reflect.Ptr {
|
||
|
if v.IsNil() {
|
||
|
return nil, errors.New("ssob: Cannot marshal nil pointer")
|
||
|
}
|
||
|
p := reflect.Indirect(v)
|
||
|
return marshal(p.Interface())
|
||
|
}
|
||
|
if t.Kind() == reflect.Struct {
|
||
|
key = reflect.TypeOf(e).Name()
|
||
|
} else {
|
||
|
key = string(t.Kind())
|
||
|
}
|
||
|
|
||
|
if f, ok := encoderCache[key]; ok {
|
||
|
return f(e)
|
||
|
} else {
|
||
|
err = encRegister(e)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return marshal(e)
|
||
|
}
|