401 lines
8.2 KiB
Go
401 lines
8.2 KiB
Go
package ssob
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math"
|
|
"reflect"
|
|
)
|
|
|
|
func marshalBool(e bool) (ret []byte) {
|
|
ret = make([]byte, 1)
|
|
if e == true {
|
|
ret[0] = 0
|
|
} else {
|
|
ret[0] = 1
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func marshalUint8(e uint8) (ret []byte) {
|
|
ret = make([]byte, 1)
|
|
ret[0] = byte(e)
|
|
return ret
|
|
}
|
|
|
|
func marshalUint16(e uint16) (ret []byte) {
|
|
ret = make([]byte, 2)
|
|
binary.BigEndian.PutUint16(ret, e)
|
|
return ret
|
|
}
|
|
|
|
func marshalUint32(e uint32) (ret []byte) {
|
|
ret = make([]byte, 4)
|
|
binary.BigEndian.PutUint32(ret, e)
|
|
return ret
|
|
}
|
|
|
|
func marshalUint64(e uint64) (ret []byte) {
|
|
ret = make([]byte, 8)
|
|
binary.BigEndian.PutUint64(ret, e)
|
|
return ret
|
|
}
|
|
|
|
func marshalInt8(e int8) (ret []byte) {
|
|
ret = make([]byte, 1)
|
|
ret[0] = byte(e)
|
|
return ret
|
|
}
|
|
|
|
func marshalInt16(e int16) (ret []byte) {
|
|
ret = make([]byte, 2)
|
|
binary.BigEndian.PutUint16(ret, uint16(e))
|
|
return ret
|
|
}
|
|
|
|
func marshalInt32(e int32) (ret []byte) {
|
|
ret = make([]byte, 4)
|
|
binary.BigEndian.PutUint32(ret, uint32(e))
|
|
return ret
|
|
}
|
|
|
|
func marshalInt64(e int64) (ret []byte) {
|
|
ret = make([]byte, 8)
|
|
binary.BigEndian.PutUint64(ret, uint64(e))
|
|
return ret
|
|
}
|
|
|
|
func marshalFloat32(e float32) (ret []byte) {
|
|
ret = make([]byte, 4)
|
|
binary.BigEndian.PutUint32(ret, math.Float32bits(e))
|
|
return ret
|
|
}
|
|
|
|
func marshalFloat64(e float64) (ret []byte) {
|
|
ret = make([]byte, 8)
|
|
binary.BigEndian.PutUint64(ret, math.Float64bits(e))
|
|
return ret
|
|
}
|
|
|
|
func marshalString(e string) (ret []byte) {
|
|
slen := len(e)
|
|
ret = make([]byte, slen+4)
|
|
binary.BigEndian.PutUint32(ret, uint32(slen))
|
|
copy(ret[4:], []byte(e))
|
|
return ret
|
|
}
|
|
|
|
func marshalNil(e uint16) (ret []byte) {
|
|
return marshalUint16(e)
|
|
}
|
|
|
|
func marshalPtrIfNil(e interface{}, ntype *NType) (ie interface{}, ret []byte, isNil bool, err error) {
|
|
if ntype.Indirection == 0 {
|
|
return e, nil, false, err
|
|
}
|
|
|
|
nl := uint16(0)
|
|
v := reflect.ValueOf(e)
|
|
if valueIsNil(v) {
|
|
ret = append(ret, marshalTypeId(ST_NIL)...)
|
|
ret = append(ret, marshalNil(nl)...)
|
|
return e, ret, true, err
|
|
}
|
|
|
|
for i := 0; i < ntype.Indirection; i++ {
|
|
if v, err = indirectValue(v); err != nil {
|
|
return e, ret, false, err
|
|
}
|
|
if valueIsNil(v) {
|
|
ret = append(ret, marshalTypeId(ST_NIL)...)
|
|
ret = append(ret, marshalNil(uint16(nl))...)
|
|
return e, ret, true, err
|
|
}
|
|
nl++
|
|
}
|
|
|
|
ret = append(ret, marshalTypeId(ntype.ValType)...)
|
|
return v.Interface(), ret, false, err
|
|
}
|
|
|
|
func marshalError(e interface{}, ntype *NType) (ret []byte, err error) {
|
|
nl := uint16(0)
|
|
v := reflect.ValueOf(e)
|
|
if valueIsNil(v) {
|
|
ret = append(ret, marshalTypeId(ST_NIL)...)
|
|
ret = append(ret, marshalNil(nl)...)
|
|
return ret, err
|
|
}
|
|
|
|
errorString := false
|
|
for i := 0; i < ntype.Indirection; i++ {
|
|
t := reflect.TypeOf(v.Interface())
|
|
|
|
// TODO: Dirty!? Better way?
|
|
if t.String() == "errors.errorString" {
|
|
errorString = true
|
|
break
|
|
}
|
|
if v, err = indirectValue(v); err != nil {
|
|
return ret, err
|
|
}
|
|
if valueIsNil(v) {
|
|
ret = append(ret, marshalTypeId(ST_NIL)...)
|
|
ret = append(ret, marshalNil(uint16(nl))...)
|
|
return ret, err
|
|
}
|
|
nl++
|
|
}
|
|
|
|
if errorString {
|
|
ret = append(ret, marshalTypeId(ST_STRING)...)
|
|
ret = append(ret, marshalString(fmt.Sprintf("%v", v.Interface()))...)
|
|
return ret, err
|
|
}
|
|
|
|
ierr, ok := v.Interface().(error)
|
|
if !ok {
|
|
return ret, ErrValueInvalid
|
|
}
|
|
|
|
ret = append(ret, marshalTypeId(ST_STRING)...)
|
|
ret = append(ret, marshalString(ierr.Error())...)
|
|
return ret, err
|
|
}
|
|
|
|
func marshalTypeId(e uint32) (ret []byte) {
|
|
return marshalUint32(e)
|
|
}
|
|
|
|
func marshalCommon(e interface{}, ntype *NType) (ret []byte, err error) {
|
|
ctype := getTypeById(ntype.ValType)
|
|
if ctype == nil {
|
|
return ret, ErrTypeUnknown
|
|
}
|
|
|
|
// pointer could be nil
|
|
e, ptrNil, isNil, err := marshalPtrIfNil(e, ntype)
|
|
if err != nil {
|
|
return ptrNil, err
|
|
}
|
|
if ptrNil != nil {
|
|
if isNil {
|
|
return ptrNil, err
|
|
}
|
|
ret = append(ret, ptrNil...)
|
|
}
|
|
|
|
switch ctype.Id {
|
|
case ST_BOOL:
|
|
if ie, ok := e.(bool); !ok {
|
|
return ret, ErrTypeInvalid
|
|
} else {
|
|
ret = append(ret, marshalBool(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_UINT8:
|
|
if ie, ok := e.(uint8); !ok {
|
|
return ret, ErrTypeInvalid
|
|
} else {
|
|
ret = append(ret, marshalUint8(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_UINT16:
|
|
if ie, ok := e.(uint16); !ok {
|
|
return ret, ErrTypeInvalid
|
|
} else {
|
|
ret = append(ret, marshalUint16(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_UINT32:
|
|
if ie, ok := e.(uint32); !ok {
|
|
return ret, ErrTypeInvalid
|
|
} else {
|
|
ret = append(ret, marshalUint32(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_UINT64:
|
|
if ie, ok := e.(uint64); !ok {
|
|
return ret, ErrTypeInvalid
|
|
} else {
|
|
ret = append(ret, marshalUint64(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_INT8:
|
|
if ie, ok := e.(int8); !ok {
|
|
return ret, ErrTypeInvalid
|
|
} else {
|
|
ret = append(ret, marshalInt8(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_INT16:
|
|
if ie, ok := e.(int16); !ok {
|
|
return ret, ErrTypeInvalid
|
|
} else {
|
|
ret = append(ret, marshalInt16(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_INT32:
|
|
if ie, ok := e.(int32); !ok {
|
|
return ret, ErrTypeInvalid
|
|
} else {
|
|
ret = append(ret, marshalInt32(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_INT64:
|
|
if ie, ok := e.(int64); !ok {
|
|
return ret, ErrTypeInvalid
|
|
} else {
|
|
ret = append(ret, marshalInt64(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_FLOAT32:
|
|
if ie, ok := e.(float32); !ok {
|
|
return ret, ErrTypeInvalid
|
|
} else {
|
|
ret = append(ret, marshalFloat32(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_FLOAT64:
|
|
if ie, ok := e.(float64); !ok {
|
|
return ret, ErrTypeInvalid
|
|
} else {
|
|
ret = append(ret, marshalFloat64(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_STRING:
|
|
if ie, ok := e.(string); !ok {
|
|
return ret, ErrTypeInvalid
|
|
} else {
|
|
ret = append(ret, marshalString(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_ERROR:
|
|
return marshalError(e, ntype)
|
|
default:
|
|
return ret, ErrTypeUnknown
|
|
}
|
|
}
|
|
|
|
func marshalSlice(e interface{}, ntype *NType) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
if !v.IsValid() || v.Kind() != reflect.Slice {
|
|
return ret, ErrValueInvalid
|
|
}
|
|
|
|
stype := getTypeById(ntype.ValType)
|
|
if stype == nil {
|
|
return ret, ErrTypeUnknown
|
|
}
|
|
|
|
l := v.Len()
|
|
ret = append(ret, marshalUint32(uint32(l))...)
|
|
for i := 0; i < l; i++ {
|
|
tbytes, err := marshalType(v.Index(i).Interface(), stype)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
ret = append(ret, tbytes...)
|
|
}
|
|
|
|
return ret, err
|
|
}
|
|
|
|
func marshalArray(e interface{}, ntype *NType) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
if !v.IsValid() || v.Kind() != reflect.Array {
|
|
return ret, ErrValueInvalid
|
|
}
|
|
|
|
stype := getTypeById(ntype.ValType)
|
|
if stype == nil {
|
|
return ret, ErrTypeUnknown
|
|
}
|
|
|
|
for i := 0; i < ntype.arrayLen; i++ {
|
|
tbytes, err := marshalType(v.Index(i).Interface(), stype)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
ret = append(ret, tbytes...)
|
|
}
|
|
|
|
return ret, err
|
|
}
|
|
|
|
func marshalStruct(e interface{}, ntype *NType) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
if !v.IsValid() || v.Kind() != reflect.Struct {
|
|
return ret, ErrValueInvalid
|
|
}
|
|
|
|
stype := getTypeById(ntype.ValType)
|
|
if stype == nil {
|
|
return ret, ErrTypeUnknown
|
|
}
|
|
|
|
for i, field := range stype.structFields {
|
|
ftype := getTypeById(field.Id)
|
|
if ftype == nil {
|
|
return ret, ErrTypeUnknown
|
|
}
|
|
tbytes, err := marshalType(v.Field(i).Interface(), ftype)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
ret = append(ret, tbytes...)
|
|
}
|
|
|
|
return ret, err
|
|
}
|
|
|
|
func marshalInterface(e interface{}, ntype *NType) (ret []byte, err error) {
|
|
return marshalVal(e)
|
|
}
|
|
|
|
func marshalType(e interface{}, ntype *NType) (ret []byte, err error) {
|
|
switch ntype.MainTypeId {
|
|
case ST_COMMON:
|
|
return marshalCommon(e, ntype)
|
|
case ST_SLICE:
|
|
return marshalSlice(e, ntype)
|
|
case ST_ARRAY:
|
|
return marshalArray(e, ntype)
|
|
case ST_STRUCT:
|
|
return marshalStruct(e, ntype)
|
|
case ST_INTERFACE:
|
|
return marshalInterface(e, ntype)
|
|
default:
|
|
return ret, ErrTypeUnknown
|
|
}
|
|
}
|
|
|
|
func marshalVal(e interface{}) (ret []byte, err error) {
|
|
if err = RegisterType(e); err != nil {
|
|
return ret, err
|
|
}
|
|
|
|
i, n, nl, err := indirectType(e)
|
|
if err != nil {
|
|
return ret, ErrValueInvalid
|
|
}
|
|
|
|
// type id
|
|
ret = marshalTypeId(n.Id)
|
|
|
|
// nil pointer
|
|
if i == nil {
|
|
ret = append(ret, marshalBool(true)...)
|
|
ret = append(ret, marshalNil(nl)...)
|
|
} else {
|
|
ret = append(ret, marshalBool(false)...)
|
|
if tbytes, err := marshalType(i, n); err != nil {
|
|
return ret, err
|
|
} else {
|
|
ret = append(ret, tbytes...)
|
|
}
|
|
}
|
|
|
|
return ret, err
|
|
}
|