ssob/marshal.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
}