862 lines
22 KiB
Go
862 lines
22 KiB
Go
package ssob
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"math"
|
|
"reflect"
|
|
|
|
"gitea.olznet.de/OlzNet/slog"
|
|
)
|
|
|
|
func MarshalString(in string) (ret []byte) {
|
|
l := int32(len(in))
|
|
b := MarshalInt32(l)
|
|
ret = make([]byte, int(l)+len(b))
|
|
copy(ret, b)
|
|
copy(ret[4:], []byte(in))
|
|
return ret
|
|
}
|
|
|
|
func MarshalBool(in bool) (ret []byte) {
|
|
if in {
|
|
return []byte{byte(0)}
|
|
}
|
|
|
|
return []byte{byte(1)}
|
|
}
|
|
|
|
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, math.Float32bits(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, math.Float64bits(in))
|
|
return out
|
|
}
|
|
|
|
type MarshalFunc func(e interface{}) (ret []byte, err error)
|
|
|
|
var encoderCache map[string]MarshalFunc
|
|
|
|
func init() {
|
|
encoderCache = make(map[string]MarshalFunc)
|
|
RegisterEncoder("bool", func(e interface{}) (ret []byte, err error) {
|
|
if i, ok := e.(bool); ok {
|
|
return MarshalBool(i), nil
|
|
}
|
|
return nil, fmt.Errorf("ssob: Incompatible type - expected bool: %w", ErrTypeMismatch)
|
|
})
|
|
RegisterEncoder("int8", func(e interface{}) (ret []byte, err error) {
|
|
if i, ok := e.(int8); ok {
|
|
return MarshalInt8(i), nil
|
|
}
|
|
return nil, fmt.Errorf("ssob: Incompatible type - expected int8: %w", ErrTypeMismatch)
|
|
})
|
|
RegisterEncoder("uint8", func(e interface{}) (ret []byte, err error) {
|
|
if i, ok := e.(uint8); ok {
|
|
return MarshalUint8(i), nil
|
|
}
|
|
return nil, fmt.Errorf("ssob: Incompatible type - expected uint8: %w", ErrTypeMismatch)
|
|
})
|
|
RegisterEncoder("int16", func(e interface{}) (ret []byte, err error) {
|
|
if i, ok := e.(int16); ok {
|
|
return MarshalInt16(i), nil
|
|
}
|
|
return nil, fmt.Errorf("ssob: Incompatible type - expected int16: %w", ErrTypeMismatch)
|
|
})
|
|
RegisterEncoder("uint16", func(e interface{}) (ret []byte, err error) {
|
|
if i, ok := e.(uint16); ok {
|
|
return MarshalUint16(i), nil
|
|
}
|
|
return nil, fmt.Errorf("ssob: Incompatible type - expected uint16: %w", ErrTypeMismatch)
|
|
})
|
|
RegisterEncoder("int32", func(e interface{}) (ret []byte, err error) {
|
|
if i, ok := e.(int32); ok {
|
|
return MarshalInt32(i), nil
|
|
}
|
|
return nil, fmt.Errorf("ssob: Incompatible type - expected int32: %w", ErrTypeMismatch)
|
|
})
|
|
RegisterEncoder("uint32", func(e interface{}) (ret []byte, err error) {
|
|
if i, ok := e.(uint32); ok {
|
|
return MarshalUint32(i), nil
|
|
}
|
|
return nil, fmt.Errorf("ssob: Incompatible type - expected uint32: %w", ErrTypeMismatch)
|
|
})
|
|
RegisterEncoder("float32", func(e interface{}) (ret []byte, err error) {
|
|
if i, ok := e.(float32); ok {
|
|
return MarshalFloat32(i), nil
|
|
}
|
|
return nil, fmt.Errorf("ssob: Incompatible type - expected float32: %w", ErrTypeMismatch)
|
|
})
|
|
RegisterEncoder("int64", func(e interface{}) (ret []byte, err error) {
|
|
if i, ok := e.(int64); ok {
|
|
return MarshalInt64(i), nil
|
|
}
|
|
return nil, fmt.Errorf("ssob: Incompatible type - expected int64: %w", ErrTypeMismatch)
|
|
})
|
|
RegisterEncoder("uint64", func(e interface{}) (ret []byte, err error) {
|
|
if i, ok := e.(uint64); ok {
|
|
return MarshalUint64(i), nil
|
|
}
|
|
return nil, fmt.Errorf("ssob: Incompatible type - expected uint64: %w", ErrTypeMismatch)
|
|
})
|
|
RegisterEncoder("float64", func(e interface{}) (ret []byte, err error) {
|
|
if i, ok := e.(float64); ok {
|
|
return MarshalFloat64(i), nil
|
|
}
|
|
return nil, fmt.Errorf("ssob: Incompatible type - expected float64: %w", ErrTypeMismatch)
|
|
})
|
|
RegisterEncoder("string", func(e interface{}) (ret []byte, err error) {
|
|
if i, ok := e.(string); ok {
|
|
return MarshalString(i), nil
|
|
}
|
|
return nil, fmt.Errorf("ssob: Incompatible type - expected string: %w", ErrTypeMismatch)
|
|
})
|
|
}
|
|
|
|
func encRegister(e interface{}) (err error) {
|
|
t := reflect.TypeOf(e)
|
|
if t == nil {
|
|
return fmt.Errorf("ssob: nil type: %w", ErrTypeInvalid)
|
|
}
|
|
|
|
switch t.Kind() {
|
|
case reflect.Invalid:
|
|
return fmt.Errorf("ssob: invalid type: %w", ErrTypeInvalid)
|
|
case reflect.Array:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
l := v.Len()
|
|
slen := MarshalInt32(int32(l))
|
|
blen := 4
|
|
bs := make([][]byte, l)
|
|
for i := 0; i < l; i++ {
|
|
bs[i], err = marshal(v.Index(i).Interface())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
blen += len(bs[i])
|
|
}
|
|
|
|
ret = make([]byte, blen)
|
|
i := copy(ret, slen)
|
|
for c := 0; c < l; c++ {
|
|
i += copy(ret[i:], bs[c])
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
encoderCache[string(t.Kind())] = f
|
|
case reflect.Slice:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
l := v.Len()
|
|
slen := MarshalInt32(int32(l))
|
|
blen := 4
|
|
bs := make([][]byte, l)
|
|
for i := 0; i < l; i++ {
|
|
bs[i], err = marshal(v.Index(i).Interface())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
blen += len(bs[i])
|
|
}
|
|
|
|
ret = make([]byte, blen)
|
|
i := copy(ret, slen)
|
|
for c := 0; c < l; c++ {
|
|
i += copy(ret[i:], bs[c])
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
encoderCache[string(t.Kind())] = f
|
|
case reflect.Map:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
l := v.Len()
|
|
ret = MarshalInt32(int32(l))
|
|
for _, ek := range v.MapKeys() {
|
|
ee := v.MapIndex(ek)
|
|
b, err := marshal(ek.Interface())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ret = append(ret, b...)
|
|
|
|
b, err = marshal(ee.Interface())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ret = append(ret, b...)
|
|
}
|
|
return ret, nil
|
|
}
|
|
encoderCache[string(t.Kind())] = f
|
|
case reflect.Struct:
|
|
zt := reflect.New(t)
|
|
n := zt.Elem().NumField()
|
|
mfields := []int{}
|
|
for i := 0; i < n; i++ {
|
|
if zt.Elem().Field(i).CanSet() {
|
|
mfields = append(mfields, i)
|
|
}
|
|
}
|
|
if len(mfields) == 0 {
|
|
return fmt.Errorf("ssob: No exported fields for %s: %w", string(t.Name()), ErrParseFailed)
|
|
}
|
|
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
bs := make([][]byte, n)
|
|
blen := 0
|
|
for _, i := range mfields {
|
|
bs[i], err = marshal(v.Field(i).Interface())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
blen += len(bs[i])
|
|
}
|
|
ret = make([]byte, blen)
|
|
i := 0
|
|
for c := 0; c < n; c++ {
|
|
i += copy(ret[i:], bs[c])
|
|
}
|
|
return ret, nil
|
|
}
|
|
encoderCache[t.Name()] = f
|
|
case reflect.Bool:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
return marshalBaseType(bool(v.Bool()))
|
|
}
|
|
encoderCache[t.Name()] = f
|
|
case reflect.Uint8:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
return marshalBaseType(uint8(v.Uint()))
|
|
}
|
|
encoderCache[t.Name()] = f
|
|
case reflect.Uint16:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
return marshalBaseType(uint16(v.Uint()))
|
|
}
|
|
encoderCache[t.Name()] = f
|
|
case reflect.Uint32:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
return marshalBaseType(uint32(v.Uint()))
|
|
}
|
|
encoderCache[t.Name()] = f
|
|
case reflect.Uint64:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
return marshalBaseType(uint64(v.Uint()))
|
|
}
|
|
encoderCache[t.Name()] = f
|
|
case reflect.Int8:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
return marshalBaseType(int8(v.Uint()))
|
|
}
|
|
encoderCache[t.Name()] = f
|
|
case reflect.Int16:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
return marshalBaseType(int16(v.Uint()))
|
|
}
|
|
encoderCache[t.Name()] = f
|
|
case reflect.Int32:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
return marshalBaseType(int32(v.Uint()))
|
|
}
|
|
encoderCache[t.Name()] = f
|
|
case reflect.Int64:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
return marshalBaseType(int64(v.Uint()))
|
|
}
|
|
encoderCache[t.Name()] = f
|
|
case reflect.String:
|
|
f := func(e interface{}) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
return marshalBaseType(string(v.String()))
|
|
}
|
|
encoderCache[t.Name()] = f
|
|
default:
|
|
return fmt.Errorf("ssob: %s: %w", string(t.Name()), ErrTypeUnknown)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func marshalBaseType(e interface{}) (ret []byte, err error) {
|
|
switch t := e.(type) {
|
|
case bool:
|
|
return encoderCache["bool"](t)
|
|
case int8:
|
|
return encoderCache["int8"](t)
|
|
case uint8:
|
|
return encoderCache["uint8"](t)
|
|
case int16:
|
|
return encoderCache["int16"](t)
|
|
case uint16:
|
|
return encoderCache["uint16"](t)
|
|
case int32:
|
|
return encoderCache["int32"](t)
|
|
case uint32:
|
|
return encoderCache["uint32"](t)
|
|
case int64:
|
|
return encoderCache["int64"](t)
|
|
case uint64:
|
|
return encoderCache["uint64"](t)
|
|
case float32:
|
|
return encoderCache["float32"](t)
|
|
case float64:
|
|
return encoderCache["float64"](t)
|
|
case string:
|
|
return encoderCache["string"](t)
|
|
default:
|
|
return nil, fmt.Errorf("ssob: No base type: %w", ErrTypeUnknown)
|
|
}
|
|
}
|
|
|
|
func marshal(e interface{}) (ret []byte, err error) {
|
|
ret, err = marshalBaseType(e)
|
|
if err == nil {
|
|
return ret, err
|
|
}
|
|
|
|
var key string
|
|
t := reflect.TypeOf(e)
|
|
v := reflect.ValueOf(e)
|
|
switch t.Kind() {
|
|
case reflect.Ptr:
|
|
if v.IsNil() {
|
|
return nil, fmt.Errorf("ssob: Cannot marshal nil pointer: %w", ErrValueInvalid)
|
|
}
|
|
p := reflect.Indirect(v)
|
|
return marshal(p.Interface())
|
|
case reflect.Bool, reflect.Int8, reflect.Int16, reflect.Int32,
|
|
reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32,
|
|
reflect.Uint64, reflect.String, reflect.Struct:
|
|
key = t.Name()
|
|
default:
|
|
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)
|
|
}
|
|
|
|
func RegisterEncoder(name string, f MarshalFunc) {
|
|
encoderCache[name] = f
|
|
}
|
|
|
|
func baseTypeMarshaller(e interface{}, w io.Writer) (err error) {
|
|
var sb []byte
|
|
|
|
switch e.(type) {
|
|
case bool:
|
|
sb = make([]byte, ST_ID_SIZE+1)
|
|
binary.BigEndian.PutUint32(sb, ST_BOOL)
|
|
if e.(bool) == true {
|
|
sb[ST_ID_SIZE] = 0
|
|
} else {
|
|
sb[ST_ID_SIZE] = 1
|
|
}
|
|
case uint8:
|
|
sb = make([]byte, ST_ID_SIZE+1)
|
|
binary.BigEndian.PutUint32(sb, ST_UINT8)
|
|
sb[ST_ID_SIZE] = byte(e.(uint8))
|
|
case uint16:
|
|
sb = make([]byte, ST_ID_SIZE+2)
|
|
binary.BigEndian.PutUint32(sb, ST_UINT16)
|
|
binary.BigEndian.PutUint16(sb[ST_ID_SIZE:], e.(uint16))
|
|
case uint32:
|
|
sb = make([]byte, ST_ID_SIZE+4)
|
|
binary.BigEndian.PutUint32(sb, ST_UINT32)
|
|
binary.BigEndian.PutUint32(sb[ST_ID_SIZE:], e.(uint32))
|
|
case uint64:
|
|
sb = make([]byte, ST_ID_SIZE+8)
|
|
binary.BigEndian.PutUint32(sb, ST_UINT64)
|
|
binary.BigEndian.PutUint64(sb[ST_ID_SIZE:], e.(uint64))
|
|
case int8:
|
|
sb = make([]byte, ST_ID_SIZE+1)
|
|
binary.BigEndian.PutUint32(sb[ST_ID_SIZE:], ST_INT8)
|
|
sb[ST_ID_SIZE] = byte(e.(int8))
|
|
case int16:
|
|
sb = make([]byte, ST_ID_SIZE+2)
|
|
binary.BigEndian.PutUint32(sb, ST_INT16)
|
|
binary.BigEndian.PutUint16(sb[ST_ID_SIZE:], uint16(e.(int16)))
|
|
case int32:
|
|
sb = make([]byte, ST_ID_SIZE+4)
|
|
binary.BigEndian.PutUint32(sb, ST_INT32)
|
|
binary.BigEndian.PutUint32(sb[ST_ID_SIZE:], uint32(e.(int32)))
|
|
case int64:
|
|
sb = make([]byte, ST_ID_SIZE+8)
|
|
binary.BigEndian.PutUint32(sb, ST_INT64)
|
|
binary.BigEndian.PutUint64(sb[ST_ID_SIZE:], uint64(e.(int64)))
|
|
case float32:
|
|
sb = make([]byte, ST_ID_SIZE+4)
|
|
binary.BigEndian.PutUint32(sb, ST_FLOAT32)
|
|
binary.BigEndian.PutUint32(sb[ST_ID_SIZE:], math.Float32bits(e.(float32)))
|
|
case float64:
|
|
sb = make([]byte, ST_ID_SIZE+8)
|
|
binary.BigEndian.PutUint32(sb, ST_FLOAT64)
|
|
binary.BigEndian.PutUint64(sb[ST_ID_SIZE:], math.Float64bits(e.(float64)))
|
|
case string:
|
|
slen := len(e.(string))
|
|
sb = make([]byte, ST_ID_SIZE+slen+4)
|
|
binary.BigEndian.PutUint32(sb, ST_STRING)
|
|
binary.BigEndian.PutUint32(sb[ST_ID_SIZE:], uint32(slen))
|
|
copy(sb[ST_ID_SIZE+4:], []byte(e.(string)))
|
|
default:
|
|
return fmt.Errorf("ssob: Unknown type: %s: %w", reflect.TypeOf(e), ErrValueInvalid)
|
|
}
|
|
|
|
return binary.Write(w, binary.BigEndian, sb)
|
|
}
|
|
|
|
func marshalBool(e bool) (ret []byte) {
|
|
ret = make([]byte, ST_ID_SIZE+1)
|
|
ret[0] = 1
|
|
if e == true {
|
|
ret[0] = 0
|
|
}
|
|
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) {
|
|
if ntype.Indirection == 0 {
|
|
return e, nil, false
|
|
}
|
|
|
|
nl := uint16(0)
|
|
v := reflect.ValueOf(e)
|
|
if v.Kind() == reflect.Invalid {
|
|
ret = append(ret, marshalTypeId(ST_NIL)...)
|
|
ret = append(ret, marshalNil(nl)...)
|
|
return e, ret, true
|
|
}
|
|
|
|
for i := 0; i < ntype.Indirection; i++ {
|
|
v = reflect.Indirect(v)
|
|
nl++
|
|
if v.Kind() == reflect.Invalid || (v.Kind() == reflect.Ptr && v.IsNil()) {
|
|
ret = append(ret, marshalTypeId(ST_NIL)...)
|
|
ret = append(ret, marshalNil(uint16(nl))...)
|
|
return e, ret, true
|
|
}
|
|
}
|
|
|
|
ret = append(ret, marshalTypeId(ntype.ValType)...)
|
|
return v.Interface(), ret, false
|
|
}
|
|
|
|
func marshalError(e interface{}, ntype *NType) (ret []byte, err error) {
|
|
nl := uint16(0)
|
|
v := reflect.ValueOf(e)
|
|
if v.Kind() == reflect.Invalid {
|
|
ret = append(ret, marshalTypeId(ST_NIL)...)
|
|
ret = append(ret, marshalNil(nl)...)
|
|
return ret, err
|
|
}
|
|
|
|
for i := 0; i < ntype.Indirection; i++ {
|
|
v = reflect.Indirect(v)
|
|
nl++
|
|
if v.Kind() == reflect.Invalid || v.IsNil() {
|
|
ret = append(ret, marshalTypeId(ST_NIL)...)
|
|
ret = append(ret, marshalNil(uint16(nl))...)
|
|
return ret, err
|
|
}
|
|
}
|
|
|
|
ierr, ok := v.Interface().(error)
|
|
if !ok {
|
|
return ret, fmt.Errorf("Not an error interface '%v': %w", v.Interface(), 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, fmt.Errorf("ssob: Unknown common type '%d': %w", ntype.ValType, ErrTypeUnknown)
|
|
}
|
|
|
|
// pointer could be nil
|
|
e, ptrNil, isNil := marshalPtrIfNil(e, ntype)
|
|
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, fmt.Errorf("ssob: Invalid interface type '%v' expected 'bool': %w", e, ErrTypeInvalid)
|
|
} else {
|
|
ret = append(ret, marshalBool(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_UINT8:
|
|
if ie, ok := e.(uint8); !ok {
|
|
return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'uint8': %w", e, ErrTypeInvalid)
|
|
} else {
|
|
ret = append(ret, marshalUint8(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_UINT16:
|
|
if ie, ok := e.(uint16); !ok {
|
|
return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'uint16': %w", e, ErrTypeInvalid)
|
|
} else {
|
|
ret = append(ret, marshalUint16(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_UINT32:
|
|
if ie, ok := e.(uint32); !ok {
|
|
return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'uint32': %w", e, ErrTypeInvalid)
|
|
} else {
|
|
ret = append(ret, marshalUint32(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_UINT64:
|
|
if ie, ok := e.(uint64); !ok {
|
|
return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'uint64': %w", e, ErrTypeInvalid)
|
|
} else {
|
|
ret = append(ret, marshalUint64(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_INT8:
|
|
if ie, ok := e.(int8); !ok {
|
|
return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'int8': %w", e, ErrTypeInvalid)
|
|
} else {
|
|
ret = append(ret, marshalInt8(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_INT16:
|
|
if ie, ok := e.(int16); !ok {
|
|
return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'int16': %w", e, ErrTypeInvalid)
|
|
} else {
|
|
ret = append(ret, marshalInt16(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_INT32:
|
|
if ie, ok := e.(int32); !ok {
|
|
return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'int32': %w", e, ErrTypeInvalid)
|
|
} else {
|
|
ret = append(ret, marshalInt32(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_INT64:
|
|
if ie, ok := e.(int64); !ok {
|
|
return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'int64': %w", e, ErrTypeInvalid)
|
|
} else {
|
|
ret = append(ret, marshalInt64(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_FLOAT32:
|
|
if ie, ok := e.(float32); !ok {
|
|
return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'float32': %w", e, ErrTypeInvalid)
|
|
} else {
|
|
ret = append(ret, marshalFloat32(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_FLOAT64:
|
|
if ie, ok := e.(float64); !ok {
|
|
return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'float64': %w", e, ErrTypeInvalid)
|
|
} else {
|
|
ret = append(ret, marshalFloat64(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_STRING:
|
|
if ie, ok := e.(string); !ok {
|
|
return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'string': %w", e, ErrTypeInvalid)
|
|
} else {
|
|
ret = append(ret, marshalString(ie)...)
|
|
return ret, err
|
|
}
|
|
case ST_ERROR:
|
|
return marshalError(e, ntype)
|
|
default:
|
|
return ret, fmt.Errorf("ssob: Unknown common type '%d': %w", ctype.Id, ErrTypeUnknown)
|
|
}
|
|
}
|
|
|
|
func marshalSlice(e interface{}, ntype *NType) (ret []byte, err error) {
|
|
v := reflect.ValueOf(e)
|
|
if v.Kind() != reflect.Slice {
|
|
return ret, fmt.Errorf("ssob: Invalid value '%v': %w", v.Kind(), ErrValueInvalid)
|
|
}
|
|
|
|
stype := getTypeById(ntype.ValType)
|
|
if stype == nil {
|
|
return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, 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.Kind() != reflect.Array {
|
|
return ret, fmt.Errorf("ssob: Invalid value '%v': %w", v.Kind(), ErrValueInvalid)
|
|
}
|
|
|
|
stype := getTypeById(ntype.ValType)
|
|
if stype == nil {
|
|
return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, 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.Kind() != reflect.Struct {
|
|
return ret, fmt.Errorf("ssob: Invalid value '%v': %w", v.Kind(), ErrValueInvalid)
|
|
}
|
|
|
|
stype := getTypeById(ntype.ValType)
|
|
if stype == nil {
|
|
return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown)
|
|
}
|
|
|
|
for i, field := range stype.structFields {
|
|
ftype := getTypeById(field.Id)
|
|
if ftype == nil {
|
|
return ret, fmt.Errorf("ssob: Unknown type '%d': %w", field.Id, ErrTypeUnknown)
|
|
}
|
|
slog.LOG_DEBUGFLN("sfield: %v", ftype)
|
|
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) {
|
|
stype := getTypeById(ntype.ValType)
|
|
if stype == nil {
|
|
return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown)
|
|
}
|
|
|
|
return marshalCommon(e, ntype)
|
|
}
|
|
|
|
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, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.MainTypeId, ErrTypeUnknown)
|
|
}
|
|
}
|
|
|
|
func marshalVal(e interface{}) (ret []byte, err error) {
|
|
i, n, nl, err := indirectType(e)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
slog.LOG_DEBUGFLN("i: %v | n: %v | nl: %v | err: %v", i, n, nl, err)
|
|
|
|
// type id
|
|
bytes := marshalTypeId(n.Id)
|
|
|
|
// nil pointer
|
|
if i == nil {
|
|
bytes = append(bytes, marshalTypeId(ST_NIL)...)
|
|
bytes = append(bytes, marshalNil(nl)...)
|
|
} else {
|
|
if tbytes, err := marshalType(i, n); err != nil {
|
|
return ret, err
|
|
} else {
|
|
bytes = append(bytes, tbytes...)
|
|
}
|
|
}
|
|
|
|
ret = append(ret, marshalUint32(uint32(len(bytes)))...)
|
|
ret = append(ret, bytes...)
|
|
|
|
return ret, err
|
|
}
|