From 45dbd7cbcacfafc96f4d30a6c3033119fa61bd60 Mon Sep 17 00:00:00 2001 From: Matthias Fulz Date: Sat, 5 Oct 2019 22:12:53 +0200 Subject: [PATCH] Added boolean and arrays --- marshal.go | 40 ++++++++++++++++++++++++++++++++++ unmarshal.go | 52 +++++++++++++++++++++++++++++++++++++++++++++ unsafe_marshal.go | 40 ++++++++++++++++++++++++++++++++++ unsafe_unmarshal.go | 52 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+) diff --git a/marshal.go b/marshal.go index 01d7a55..bf0af1d 100644 --- a/marshal.go +++ b/marshal.go @@ -15,6 +15,14 @@ func MarshalString(in string) (ret []byte) { 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)} } @@ -85,6 +93,12 @@ 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, errors.New("ssob: Incompatible type - expected bool") + }) RegisterEncoder("int8", func(e interface{}) (ret []byte, err error) { if i, ok := e.(int8); ok { return MarshalInt8(i), nil @@ -159,6 +173,30 @@ func encRegister(e interface{}) (err error) { switch t.Kind() { case reflect.Invalid: return errors.New("ssob: Invalid type") + 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) @@ -234,6 +272,8 @@ func encRegister(e interface{}) (err error) { 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: diff --git a/unmarshal.go b/unmarshal.go index 0301e99..f29cd1f 100644 --- a/unmarshal.go +++ b/unmarshal.go @@ -18,6 +18,17 @@ func UnmarshalString(in []byte) (ret string, n int, err error) { return string(in[4 : l+4]), int(l) + 4, nil } +func UnmarshalBool(in []byte) (ret bool, n int, err error) { + if len(in) < 1 { + return false, 0, errors.New("ssob: Invalid input to decode bool") + } + + if in[0] == byte(0) { + return true, 1, nil + } + return false, 1, nil +} + func UnmarshalInt8(in []byte) (ret int8, n int, err error) { if len(in) < 1 { return 0, 0, errors.New("ssob: Invalid input to decode int8") @@ -104,6 +115,13 @@ var decoderCache map[string]unmarshalFunc func init() { decoderCache = make(map[string]unmarshalFunc) + RegisterDecoder("bool", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*bool); ok { + *i, n, err = UnmarshalBool(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected bool") + }) RegisterDecoder("int8", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int8); ok { *i, n, err = UnmarshalInt8(in) @@ -189,6 +207,38 @@ func decRegister(e interface{}) (err error) { switch t.Kind() { case reflect.Invalid: return errors.New("ssob: Invalid type") + case reflect.Array: + f := func(e interface{}, in []byte) (n int, err error) { + t := reflect.TypeOf(e) + v := reflect.ValueOf(e) + pos := 0 + + if t.Kind() != reflect.Ptr || v.IsNil() { + return 0, errors.New("ssob: Cannot unmarshal to nil pointer") + } + + l, r, err := UnmarshalInt32(in) + pos += r + if err != nil { + return pos, err + } + + ti := v.Elem() + if int(l) != ti.Len() { + return pos, errors.New("ssob: Invalid array length. Expected " + string(l) + " got " + string(ti.Len())) + } + for i := 0; i < int(l); i++ { + e := reflect.New(reflect.TypeOf(ti.Interface()).Elem()) + r, err := unmarshal(e.Interface(), in[pos:]) + pos += r + if err != nil { + return pos, err + } + ti.Index(i).Set(reflect.Indirect(e)) + } + return pos, nil + } + decoderCache[string(t.Kind())] = f case reflect.Slice: f := func(e interface{}, in []byte) (n int, err error) { t := reflect.TypeOf(e) @@ -290,6 +340,8 @@ func decRegister(e interface{}) (err error) { func unmarshalBaseType(e interface{}, in []byte) (n int, err error) { switch t := e.(type) { + case *bool: + return decoderCache["bool"](t, in) case *int8: return decoderCache["int8"](t, in) case *uint8: diff --git a/unsafe_marshal.go b/unsafe_marshal.go index 3782aa1..9a07637 100644 --- a/unsafe_marshal.go +++ b/unsafe_marshal.go @@ -15,6 +15,14 @@ func UnsafeMarshalString(in string) (ret []byte) { return ret } +func UnsafeMarshalBool(in bool) (ret []byte) { + if in { + return []byte{byte(0)} + } + + return []byte{byte(1)} +} + func UnsafeMarshalInt8(in int8) (ret []byte) { return []byte{byte(in)} } @@ -195,6 +203,12 @@ var unsafeEncoderCache map[string]MarshalFunc func init() { unsafeEncoderCache = make(map[string]MarshalFunc) + RegisterUnsafeEncoder("bool", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(bool); ok { + return UnsafeMarshalBool(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected bool") + }) RegisterUnsafeEncoder("int8", func(e interface{}) (ret []byte, err error) { if i, ok := e.(int8); ok { return UnsafeMarshalInt8(i), nil @@ -269,6 +283,30 @@ func encRegisterUnsafe(e interface{}) (err error) { switch t.Kind() { case reflect.Invalid: return errors.New("ssob: Invalid type") + case reflect.Array: + f := func(e interface{}) (ret []byte, err error) { + v := reflect.ValueOf(e) + l := v.Len() + slen := UnsafeMarshalInt32(int32(l)) + blen := 4 + bs := make([][]byte, l) + for i := 0; i < l; i++ { + bs[i], err = unsafeMarshal(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 + } + unsafeEncoderCache[string(t.Kind())] = f case reflect.Slice: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) @@ -344,6 +382,8 @@ func encRegisterUnsafe(e interface{}) (err error) { func unsafeMarshalBaseType(e interface{}) (ret []byte, err error) { switch t := e.(type) { + case bool: + return unsafeEncoderCache["bool"](t) case int8: return unsafeEncoderCache["int8"](t) case uint8: diff --git a/unsafe_unmarshal.go b/unsafe_unmarshal.go index cf04438..7fb5519 100644 --- a/unsafe_unmarshal.go +++ b/unsafe_unmarshal.go @@ -19,6 +19,17 @@ func UnsafeUnmarshalString(in []byte) (ret string, n int, err error) { return string(in[4 : l+4]), int(l) + 4, nil } +func UnsafeUnmarshalBool(in []byte) (ret bool, n int, err error) { + if len(in) < 1 { + return false, 0, errors.New("ssob: Invalid input to decode bool") + } + + if in[0] == byte(0) { + return true, 1, nil + } + return false, 1, nil +} + func UnsafeUnmarshalInt8(in []byte) (ret int8, n int, err error) { if len(in) < 1 { return 0, 0, errors.New("ssob: Invalid input to decode int8") @@ -231,6 +242,13 @@ var unsafeDecoderCache map[string]unmarshalFunc func init() { unsafeDecoderCache = make(map[string]unmarshalFunc) + RegisterUnsafeDecoder("bool", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*bool); ok { + *i, n, err = UnsafeUnmarshalBool(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected bool") + }) RegisterUnsafeDecoder("int8", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int8); ok { *i, n, err = UnsafeUnmarshalInt8(in) @@ -316,6 +334,38 @@ func decRegisterUnsafe(e interface{}) (err error) { switch t.Kind() { case reflect.Invalid: return errors.New("ssob: Invalid type") + case reflect.Array: + f := func(e interface{}, in []byte) (n int, err error) { + t := reflect.TypeOf(e) + v := reflect.ValueOf(e) + pos := 0 + + if t.Kind() != reflect.Ptr || v.IsNil() { + return 0, errors.New("ssob: Cannot unmarshal to nil pointer") + } + + l, r, err := UnsafeUnmarshalInt32(in) + pos += r + if err != nil { + return pos, err + } + + ti := v.Elem() + if int(l) != ti.Len() { + return pos, errors.New("ssob: Invalid array length. Expected " + string(l) + " got " + string(ti.Len())) + } + for i := 0; i < int(l); i++ { + e := reflect.New(reflect.TypeOf(ti.Interface()).Elem()) + r, err := unsafeUnmarshal(e.Interface(), in[pos:]) + pos += r + if err != nil { + return pos, err + } + ti.Index(i).Set(reflect.Indirect(e)) + } + return pos, nil + } + unsafeDecoderCache[string(t.Kind())] = f case reflect.Slice: f := func(e interface{}, in []byte) (n int, err error) { t := reflect.TypeOf(e) @@ -417,6 +467,8 @@ func decRegisterUnsafe(e interface{}) (err error) { func unsafeUnmarshalBaseType(e interface{}, in []byte) (n int, err error) { switch t := e.(type) { + case *bool: + return unsafeDecoderCache["bool"](t, in) case *int8: return unsafeDecoderCache["int8"](t, in) case *uint8: