From c228d3fcce780d25d03c6ebafe365889ce7c02bf Mon Sep 17 00:00:00 2001 From: Matthias Fulz Date: Tue, 7 Sep 2021 16:05:04 +0200 Subject: [PATCH] Cleanup --- decoder.go | 58 +-- encoder.go | 83 ---- marshal.go | 566 +++----------------------- types.go | 274 ++++--------- unmarshal.go | 951 +++++++++----------------------------------- unsafe_decoder.go | 56 --- unsafe_encoder.go | 49 --- unsafe_marshal.go | 527 ------------------------ unsafe_unmarshal.go | 720 --------------------------------- 9 files changed, 310 insertions(+), 2974 deletions(-) delete mode 100644 unsafe_decoder.go delete mode 100644 unsafe_encoder.go delete mode 100644 unsafe_marshal.go delete mode 100644 unsafe_unmarshal.go diff --git a/decoder.go b/decoder.go index fa1aeba..9526fba 100644 --- a/decoder.go +++ b/decoder.go @@ -2,13 +2,9 @@ package ssob import ( "encoding/binary" - "errors" "fmt" "io" - "reflect" "sync" - - "gitea.olznet.de/OlzNet/slog" ) type Decoder struct { @@ -22,56 +18,7 @@ func NewDecoder(r io.Reader) *Decoder { return dec } -func (dec *Decoder) Decode(e interface{}) (err error) { - t := reflect.TypeOf(e) - slog.LOG_DEBUGFLN("Dec: %v", t) - if t == reflect.TypeOf(errors.New("")) || t == reflect.TypeOf((*error)(nil)) { - var errstr string - if err = dec.Decode(&errstr); err != nil { - return err - } - if errstr != "" { - *e.(*error) = errors.New(errstr) - } - return nil - } - - return dec.DecodeValue(reflect.ValueOf(e)) -} - -func (dec *Decoder) DecodeValue(value reflect.Value) (err error) { - if value.Kind() == reflect.Invalid { - return fmt.Errorf("ssob: Cannot decode nil: %w", ErrValueInvalid) - } - - if value.Kind() == reflect.Ptr && value.IsNil() { - return fmt.Errorf("ssob: Cannot decode nil of type %s: %w", value.Type().String(), ErrValueInvalid) - } - - dec.mutex.Lock() - defer dec.mutex.Unlock() - - lb := make([]byte, 4) - err = binary.Read(dec.r, binary.BigEndian, lb) - if err != nil { - return err - } - l, n, err := UnmarshalInt32(lb) - if err != nil || n != 4 { - return err - } - - bb := make([]byte, l) - err = binary.Read(dec.r, binary.BigEndian, bb) - if err != nil { - return err - } - - _, err = unmarshal(value.Interface(), bb) - return err -} - -func (dec *Decoder) NDecode() (ret interface{}, err error) { +func (dec *Decoder) Decode() (ret interface{}, err error) { st := make([]byte, ST_ID_SIZE) dec.mutex.Lock() @@ -84,8 +31,7 @@ func (dec *Decoder) NDecode() (ret interface{}, err error) { l := binary.BigEndian.Uint32(st) b := make([]byte, l) - var rl int - if rl, err = dec.r.Read(b); err != nil || rl != int(l) { + if err = binary.Read(dec.r, binary.BigEndian, b); err != nil { return nil, fmt.Errorf("ssob: Cannot decode value: %w", err) } diff --git a/encoder.go b/encoder.go index ef03336..8a72375 100644 --- a/encoder.go +++ b/encoder.go @@ -1,11 +1,8 @@ package ssob import ( - "encoding/binary" - "errors" "fmt" "io" - "reflect" "sync" "gitea.olznet.de/OlzNet/slog" @@ -23,51 +20,6 @@ func NewEncoder(w io.Writer) *Encoder { } func (enc *Encoder) Encode(e interface{}) (err error) { - t := reflect.TypeOf(e) - slog.LOG_DEBUGFLN("Enc: %v", t) - if t == reflect.TypeOf(errors.New("")) || t == reflect.TypeOf((*error)(nil)).Elem() { - if reflect.ValueOf(e).IsNil() { - return enc.Encode(string("")) - } else { - return enc.Encode(e.(error).Error()) - } - } else if t == reflect.TypeOf((*error)(nil)) { - if reflect.Indirect(reflect.ValueOf(e)).IsNil() { - return enc.Encode(string("")) - } else { - return enc.Encode((*e.(*error)).Error()) - } - } - - return enc.EncodeValue(reflect.ValueOf(e)) -} - -func (enc *Encoder) EncodeValue(value reflect.Value) (err error) { - if value.Kind() == reflect.Invalid { - return fmt.Errorf("ssob: Cannot encode nil: %w", ErrValueInvalid) - } - - if value.Kind() == reflect.Ptr && value.IsNil() { - return fmt.Errorf("ssob: Cannot encode nil of type %s: %w", value.Type().String(), ErrValueInvalid) - } - - bb, err := marshal(value.Interface()) - if err != nil { - return err - } - bl := MarshalInt32(int32(len(bb))) - - w := make([]byte, 4+len(bb)) - copy(w, bl) - copy(w[4:], bb) - - enc.mutex.Lock() - defer enc.mutex.Unlock() - - return binary.Write(enc.w, binary.BigEndian, w) -} - -func (enc *Encoder) NEncode(e interface{}) (err error) { RegisterType(e) for _, t := range cacheTypes.ntypes { slog.LOG_DEBUGFLN("t: %v", t) @@ -87,38 +39,3 @@ func (enc *Encoder) NEncode(e interface{}) (err error) { return nil } - -func (enc *Encoder) encode(e interface{}, indirectLevel int) (err error) { - t := reflect.TypeOf(e) - - if t.Kind() == reflect.Invalid { - return fmt.Errorf("ssob: Cannot encode nil: %w", ErrValueInvalid) - } - - v := reflect.ValueOf(e) - //slog.LOG_DEBUGFLN("ssob: encode t.name: %s", t.Name()) - //slog.LOG_DEBUGFLN("ssob: encode t.kind: %s", t.Kind()) - slog.LOG_DEBUGFLN("ssob: encode v.type: %s", v.Type()) - switch t.Kind() { - case reflect.Ptr: - if v.IsNil() { - return fmt.Errorf("ssob: Cannot encode nil pointer: %w", ErrValueInvalid) - } - p := reflect.Indirect(v) - return enc.encode(p.Interface(), indirectLevel+1) - case reflect.Struct: - return fmt.Errorf("ssob: Type '%s' named '%s' unknown: %w", t.Kind().String(), t.Name(), ErrTypeUnknown) - case reflect.Slice: - return fmt.Errorf("ssob: Type '%s' with types '%s' unknown: %w", t.Kind().String(), t.Elem().Kind().String(), ErrTypeUnknown) - case reflect.Array: - return fmt.Errorf("ssob: Type '%s' with types '%s' unknown: %w", t.Kind().String(), t.Name(), ErrTypeUnknown) - default: - if v, ok := cacheTypes.names[t.Kind().String()]; !ok { - return fmt.Errorf("ssob: Type '%s' unknown: %w", t.Kind().String(), ErrTypeUnknown) - } else { - enc.mutex.Lock() - defer enc.mutex.Unlock() - return cacheTypes.types[v].marshal(e, enc.w) - } - } -} diff --git a/marshal.go b/marshal.go index ba82128..5353e7f 100644 --- a/marshal.go +++ b/marshal.go @@ -3,486 +3,10 @@ package ssob import ( "encoding/binary" "fmt" - "io" "math" "reflect" ) -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, 1) if e == true { @@ -565,37 +89,39 @@ func marshalNil(e uint16) (ret []byte) { return marshalUint16(e) } -func marshalPtrIfNil(e interface{}, ntype *NType) (ie interface{}, ret []byte, isNil bool) { +func marshalPtrIfNil(e interface{}, ntype *NType) (ie interface{}, ret []byte, isNil bool, err error) { if ntype.Indirection == 0 { - return e, nil, false + return e, nil, false, err } nl := uint16(0) v := reflect.ValueOf(e) - if v.Kind() == reflect.Invalid { + if valueIsNil(v) { ret = append(ret, marshalTypeId(ST_NIL)...) ret = append(ret, marshalNil(nl)...) - return e, ret, true + return e, ret, true, err } for i := 0; i < ntype.Indirection; i++ { - v = reflect.Indirect(v) - if v.Kind() == reflect.Invalid || (v.Kind() == reflect.Ptr && v.IsNil()) { + 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 + return e, ret, true, err } nl++ } ret = append(ret, marshalTypeId(ntype.ValType)...) - return v.Interface(), ret, false + return v.Interface(), ret, false, err } func marshalError(e interface{}, ntype *NType) (ret []byte, err error) { nl := uint16(0) v := reflect.ValueOf(e) - if v.Kind() == reflect.Invalid { + if valueIsNil(v) { ret = append(ret, marshalTypeId(ST_NIL)...) ret = append(ret, marshalNil(nl)...) return ret, err @@ -605,12 +131,15 @@ func marshalError(e interface{}, ntype *NType) (ret []byte, err error) { for i := 0; i < ntype.Indirection; i++ { t := reflect.TypeOf(v.Interface()) + // TODO: Dirty!? Better way? if t.String() == "errors.errorString" { errorString = true break } - v = reflect.Indirect(v) - if v.Kind() == reflect.Invalid || v.IsNil() { + 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 @@ -626,7 +155,7 @@ func marshalError(e interface{}, ntype *NType) (ret []byte, err error) { ierr, ok := v.Interface().(error) if !ok { - return ret, fmt.Errorf("Not an error interface '%v': %w", v.Interface(), ErrValueInvalid) + return ret, ErrValueInvalid } ret = append(ret, marshalTypeId(ST_STRING)...) @@ -641,11 +170,14 @@ func marshalTypeId(e uint32) (ret []byte) { 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) + return ret, ErrTypeUnknown } // pointer could be nil - e, ptrNil, isNil := marshalPtrIfNil(e, ntype) + e, ptrNil, isNil, err := marshalPtrIfNil(e, ntype) + if err != nil { + return ptrNil, err + } if ptrNil != nil { if isNil { return ptrNil, err @@ -656,84 +188,84 @@ func marshalCommon(e interface{}, ntype *NType) (ret []byte, err error) { 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) + return ret, 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) + return ret, 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) + return ret, 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) + return ret, 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) + return ret, 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) + return ret, 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) + return ret, 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) + return ret, 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) + return ret, 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) + return ret, 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) + return ret, 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) + return ret, ErrTypeInvalid } else { ret = append(ret, marshalString(ie)...) return ret, err @@ -741,19 +273,19 @@ func marshalCommon(e interface{}, ntype *NType) (ret []byte, err error) { case ST_ERROR: return marshalError(e, ntype) default: - return ret, fmt.Errorf("ssob: Unknown common type '%d': %w", ctype.Id, ErrTypeUnknown) + return ret, 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) + if !v.IsValid() || v.Kind() != reflect.Slice { + return ret, ErrValueInvalid } stype := getTypeById(ntype.ValType) if stype == nil { - return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + return ret, ErrTypeUnknown } l := v.Len() @@ -771,13 +303,13 @@ func marshalSlice(e interface{}, ntype *NType) (ret []byte, err error) { 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) + if !v.IsValid() || v.Kind() != reflect.Array { + return ret, ErrValueInvalid } stype := getTypeById(ntype.ValType) if stype == nil { - return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + return ret, ErrTypeUnknown } for i := 0; i < ntype.arrayLen; i++ { @@ -793,19 +325,19 @@ func marshalArray(e interface{}, ntype *NType) (ret []byte, err error) { 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) + if !v.IsValid() || v.Kind() != reflect.Struct { + return ret, ErrValueInvalid } stype := getTypeById(ntype.ValType) if stype == nil { - return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + return ret, 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) + return ret, ErrTypeUnknown } tbytes, err := marshalType(v.Field(i).Interface(), ftype) if err != nil { @@ -820,7 +352,7 @@ func marshalStruct(e interface{}, ntype *NType) (ret []byte, err error) { 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 ret, ErrTypeUnknown } return marshalCommon(e, ntype) @@ -839,14 +371,14 @@ func marshalType(e interface{}, ntype *NType) (ret []byte, err error) { case ST_INTERFACE: return marshalInterface(e, ntype) default: - return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.MainTypeId, ErrTypeUnknown) + return ret, ErrTypeUnknown } } func marshalVal(e interface{}) (ret []byte, err error) { i, n, nl, err := indirectType(e) if err != nil { - return ret, err + return ret, ErrValueInvalid } // type id @@ -854,9 +386,7 @@ func marshalVal(e interface{}) (ret []byte, err error) { // nil pointer if i == nil { - // nil bytes = append(bytes, marshalBool(true)...) - //bytes = append(bytes, marshalTypeId(ST_NIL)...) bytes = append(bytes, marshalNil(nl)...) } else { bytes = append(bytes, marshalBool(false)...) diff --git a/types.go b/types.go index c1f839d..4cc4cfe 100644 --- a/types.go +++ b/types.go @@ -4,8 +4,6 @@ import ( "fmt" "io" "reflect" - - "gitea.olznet.de/OlzNet/slog" ) type allocatorFunc func(vals ...interface{}) interface{} @@ -17,8 +15,6 @@ type nallocFunc func() interface{} type RegisteredTypes struct { NextId uint32 - types map[uint32]Type - names map[string]uint32 ntypes map[uint32]*NType nnames map[string]*NType } @@ -36,6 +32,7 @@ type StructField struct { Id uint32 Name string Tag string + SId int } type NType struct { @@ -86,8 +83,6 @@ const ( func init() { cacheTypes.NextId = 128 - cacheTypes.types = make(map[uint32]Type) - cacheTypes.names = make(map[string]uint32) cacheTypes.ntypes = make(map[uint32]*NType) cacheTypes.nnames = make(map[string]*NType) @@ -188,154 +183,6 @@ func init() { } cacheTypes.ntypes[ST_NIL] = nilType cacheTypes.nnames["nil"] = nilType - - cacheTypes.types[ST_BOOL] = Type{ - "bool", ST_BOOL, - func(vals ...interface{}) interface{} { return new(bool) }, - baseTypeMarshaller, - func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_BOOL, r) }, - } - cacheTypes.names["bool"] = ST_BOOL - - cacheTypes.types[ST_UINT8] = Type{ - "uint8", ST_UINT8, - func(vals ...interface{}) interface{} { return new(uint8) }, - baseTypeMarshaller, - func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_UINT8, r) }, - } - cacheTypes.names["uint8"] = ST_UINT8 - - cacheTypes.types[ST_UINT16] = Type{ - "uint16", ST_UINT16, - func(vals ...interface{}) interface{} { return new(uint16) }, - baseTypeMarshaller, - func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_UINT16, r) }, - } - cacheTypes.names["uint16"] = ST_UINT16 - - cacheTypes.types[ST_UINT32] = Type{ - "uint32", ST_UINT32, - func(vals ...interface{}) interface{} { return new(uint32) }, - baseTypeMarshaller, - func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_UINT32, r) }, - } - cacheTypes.names["uint32"] = ST_UINT32 - - cacheTypes.types[ST_UINT64] = Type{ - "uint64", ST_UINT64, - func(vals ...interface{}) interface{} { return new(uint64) }, - baseTypeMarshaller, - func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_UINT64, r) }, - } - cacheTypes.names["uint64"] = ST_UINT64 - - cacheTypes.types[ST_INT8] = Type{ - "int8", ST_INT8, - func(vals ...interface{}) interface{} { return new(int8) }, - baseTypeMarshaller, - func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_INT8, r) }, - } - cacheTypes.names["int8"] = ST_UINT8 - - cacheTypes.types[ST_INT16] = Type{ - "int16", ST_INT16, - func(vals ...interface{}) interface{} { return new(int16) }, - baseTypeMarshaller, - func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_INT16, r) }, - } - cacheTypes.names["int16"] = ST_INT16 - - cacheTypes.types[ST_INT32] = Type{ - "int32", ST_INT32, - func(vals ...interface{}) interface{} { return new(int32) }, - baseTypeMarshaller, - func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_INT32, r) }, - } - cacheTypes.names["int32"] = ST_INT32 - - cacheTypes.types[ST_INT64] = Type{ - "int64", ST_INT64, - func(vals ...interface{}) interface{} { return new(int64) }, - baseTypeMarshaller, - func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_INT64, r) }, - } - cacheTypes.names["int64"] = ST_INT64 - - cacheTypes.types[ST_FLOAT32] = Type{ - "float32", ST_FLOAT32, - func(vals ...interface{}) interface{} { return new(float32) }, - baseTypeMarshaller, - func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_FLOAT32, r) }, - } - cacheTypes.names["float32"] = ST_FLOAT32 - - cacheTypes.types[ST_FLOAT64] = Type{ - "float64", ST_FLOAT64, - func(vals ...interface{}) interface{} { return new(float64) }, - baseTypeMarshaller, - func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_FLOAT64, r) }, - } - cacheTypes.names["float64"] = ST_FLOAT64 - - cacheTypes.types[ST_STRING] = Type{ - "string", ST_STRING, - func(vals ...interface{}) interface{} { return new(string) }, - baseTypeMarshaller, - func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_STRING, r) }, - } - cacheTypes.names["string"] = ST_STRING -} - -func getTypeId(e interface{}, indirectLevel int) (id uint32, level int) { - level = indirectLevel - t := reflect.TypeOf(e) - - if t.Kind() == reflect.Invalid { - return ST_INVALID, level - } - - v := reflect.ValueOf(e) - switch t.Kind() { - case reflect.Ptr: - if v.IsNil() { - return ST_INVALID, level - } - p := reflect.Indirect(v) - level += 1 - return getTypeId(p.Interface(), level) - } - - if id, ok := cacheTypes.names[t.Kind().String()]; ok { - return id, level - } - - return ST_INVALID, level -} - -func getIndirection(e interface{}, level int) (indirection int, maintype uint32, typ reflect.Type) { - indirection = level - maintype = ST_COMMON - - t := reflect.TypeOf(e) - v := reflect.ValueOf(e) - - switch t.Kind() { - case reflect.Ptr: - if v.IsNil() { - return indirection, maintype, t - } - p := reflect.Indirect(v) - indirection += 1 - return getIndirection(p.Interface(), indirection) - case reflect.Slice: - maintype = ST_SLICE - case reflect.Array: - maintype = ST_ARRAY - case reflect.Struct: - maintype = ST_STRUCT - } - - return indirection, maintype, t } func getTypeById(id uint32) (ret *NType) { @@ -393,7 +240,7 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i typ := reflect.TypeOf(val.Interface()) vt, err := getTypeByNameRegister(typ.Elem().String(), typ.Elem()) if err != nil { - return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, err } valType = vt.Id base = false @@ -403,7 +250,7 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i arrayLen = val.Len() vt, err := getTypeByNameRegister(typ.Elem().String(), typ.Elem()) if err != nil { - return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, err } valType = vt.Id base = false @@ -413,7 +260,7 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i if !base { vt, err := getTypeByNameRegister(typ.Elem().String(), typ.Elem()) if err != nil { - return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, err } valType = vt.Id } @@ -423,7 +270,7 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i if !base { vt, err := getTypeByNameRegister(typ.String(), typ) if err != nil { - return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, err } valType = vt.Id } else { @@ -435,9 +282,10 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i sfield.Tag = string(val.Type().Field(i).Tag) vt, err := getTypeByNameRegister(val.Field(i).Type().String(), val.Field(i).Type()) if err != nil { - return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, err } sfield.Id = vt.Id + sfield.SId = i sfields = append(sfields, sfield) } } @@ -449,21 +297,21 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i if !base { vt, err := getTypeByNameRegister(typ.String(), typ) if err != nil { - return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, err } valType = vt.Id } else { // Key vt, err := getTypeByNameRegister(typ.Key().String(), typ.Key()) if err != nil { - return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, err } valType = vt.Id // Val vt, err = getTypeByNameRegister(typ.Elem().String(), typ.Elem()) if err != nil { - return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, err } valType = vt.Id base = false @@ -474,7 +322,7 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i if !base { vt, err := getTypeByNameRegister(typ.Kind().String(), typ) if err != nil { - return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, err } valType = vt.Id } @@ -517,7 +365,7 @@ func createType(t reflect.Type) (ret *NType, base bool, err error) { func registerType(t reflect.Type) (err error) { if t == nil || t.Kind() == reflect.Invalid { - return fmt.Errorf("ssob: Cannot register nil: %w", ErrTypeInvalid) + return ErrTypeInvalid } if getTypeByName(t.String()) != nil { @@ -527,7 +375,7 @@ func registerType(t reflect.Type) (err error) { var base bool ntype, base, err := createType(t) if err != nil { - return fmt.Errorf("ssob: Cannot register type '%s': %w", t, err) + return err } ntype.Id = cacheTypes.NextId if base { @@ -537,25 +385,18 @@ func registerType(t reflect.Type) (err error) { cacheTypes.nnames[ntype.Name] = ntype cacheTypes.NextId += 1 - if ntype.MainTypeId == ST_STRUCT { - for _, f := range ntype.structFields { - slog.LOG_DEBUGFLN(" Field: %v", f) - } - } - slog.LOG_DEBUGFLN("Type: %v registered", t) - return err } func splitType(e interface{}) (t reflect.Type, v reflect.Value, err error) { t = reflect.TypeOf(e) if t == nil || t.Kind() != reflect.Ptr { - return t, v, fmt.Errorf("ssob: Interface is not a valid address: %w", ErrTypeInvalid) + return t, v, ErrTypeInvalid } v = reflect.ValueOf(e) if v.IsNil() { - return t, v, fmt.Errorf("ssob: Got nil: %w", ErrValueInvalid) + return t, v, ErrValueInvalid } return t, v, err @@ -575,37 +416,42 @@ func indirectType(e interface{}) (ret interface{}, ntype *NType, nilLevel uint16 } for i := 0; i < ntype.Indirection; i++ { - v = reflect.Indirect(v) - if v.IsNil() { + if v, err = indirectValue(v); err != nil { + return nil, ntype, nilLevel, ErrValueInvalid + } + if v.IsValid() && v.IsNil() { nilLevel += uint16(i) return nil, ntype, nilLevel, err } } - return reflect.Indirect(v).Interface(), ntype, nilLevel, err + if v, err = indirectValue(v); err != nil { + return nil, ntype, nilLevel, err + } + + return v.Interface(), ntype, nilLevel, err } func setTypeNil(e interface{}, indirection int) (err error) { - v := reflect.ValueOf(e) + var v reflect.Value - if v.Kind() != reflect.Ptr || v.IsNil() { - return fmt.Errorf("ssob: Not a pointer: %w", ErrValueInvalid) + if v, err = getValPtr(e); err != nil { + return err } - v = reflect.Indirect(v) - if (v.Kind() != reflect.Ptr || v.IsNil()) && indirection > 0 { - return fmt.Errorf("ssob: Not a pointer: %w", ErrValueInvalid) - } - - for i := 0; i < indirection; i++ { - v = reflect.Indirect(v) - if v.Kind() != reflect.Ptr || v.IsNil() { - return fmt.Errorf("ssob: Not a pointer: %w", ErrValueInvalid) + if v, err = indirectValue(v); err != nil { + if indirection > 0 { + return ErrValueInvalid } } - slog.LOG_DEBUGFLN("test") - if !v.IsNil() { + for i := 0; i < indirection; i++ { + if v, err = indirectValue(v); err != nil { + return err + } + } + + if v.IsValid() && !v.IsNil() { v.Set(reflect.Zero(reflect.TypeOf(v.Interface()))) } @@ -613,33 +459,61 @@ func setTypeNil(e interface{}, indirection int) (err error) { } func setTypeVal(e interface{}, val interface{}, ntype *NType) (err error) { - v := reflect.ValueOf(e) + var v reflect.Value - if v.Kind() != reflect.Ptr || v.IsNil() { - return fmt.Errorf("ssob: Not a pointer: %w", ErrValueInvalid) + if v, err = getValPtr(e); err != nil { + return err + } + if v, err = indirectValue(v); err != nil { + return err } - - v = reflect.Indirect(v) for i := 0; i < ntype.Indirection; i++ { - if v.Kind() != reflect.Ptr || v.IsNil() { - return fmt.Errorf("ssob: Not a pointer: %w", ErrValueInvalid) + if v, err = indirectValue(v); err != nil { + return err } - v = reflect.Indirect(v) } v.Set(reflect.ValueOf(val)) return err } +func getValPtr(e interface{}) (ret reflect.Value, err error) { + v := reflect.ValueOf(e) + + if !v.IsValid() || v.Kind() != reflect.Ptr || v.IsNil() { + err = ErrValueInvalid + } + + return v, err +} + func getVal(e interface{}) (ret reflect.Value) { v := reflect.ValueOf(e) - if v.Kind() != reflect.Ptr || v.IsNil() { + if !v.IsValid() || v.Kind() != reflect.Ptr || v.IsNil() { return v } return reflect.Indirect(v) } +func indirectValue(v reflect.Value) (ret reflect.Value, err error) { + if !v.IsValid() || v.Kind() != reflect.Ptr { + return v, ErrValueInvalid + } + + ret = reflect.Indirect(v) + return ret, err +} + +func valueIsNil(v reflect.Value) (ret bool) { + ret = false + + if !v.IsValid() || v.Kind() == reflect.Invalid || (v.Kind() == reflect.Ptr && v.IsNil()) { + ret = true + } + return ret +} + func RegisterType(e interface{}) (err error) { t := reflect.TypeOf(e) if t == nil || t.Kind() != reflect.Ptr { diff --git a/unmarshal.go b/unmarshal.go index 46c450e..c64e466 100644 --- a/unmarshal.go +++ b/unmarshal.go @@ -3,756 +3,110 @@ package ssob import ( "encoding/binary" "fmt" - "io" "math" "reflect" ) -func UnmarshalString(in []byte) (ret string, n int, err error) { - if len(in) < 4 { - return "", 0, fmt.Errorf("ssob: Decoding string: %w", ErrTypeInvalid) +func unmarshalBool(e []byte) (ie []byte, ret bool, err error) { + if len(e) < 1 { + return e, ret, ErrValueInvalid } - l := int32(binary.BigEndian.Uint32(in)) - - if len(in[4:]) < int(l) { - return "", 0, fmt.Errorf("ssob: Invalid length of string: %w", ErrValueInvalid) - } - 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, fmt.Errorf("ssob: Decoding bool: %w", ErrTypeInvalid) - } - - 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, fmt.Errorf("ssob: Decoding int8: %w", ErrTypeInvalid) - } - - return int8(in[0]), 1, nil -} - -func UnmarshalUint8(in []byte) (ret uint8, n int, err error) { - if len(in) < 1 { - return 0, 0, fmt.Errorf("ssob: Decoding uint8: %w", ErrTypeInvalid) - } - - return uint8(in[0]), 1, nil -} - -func UnmarshalInt16(in []byte) (ret int16, n int, err error) { - if len(in) < 2 { - return 0, 0, fmt.Errorf("ssob: Decoding int16: %w", ErrTypeInvalid) - } - - return int16(binary.BigEndian.Uint16(in[0:2])), 2, nil -} - -func UnmarshalUint16(in []byte) (ret uint16, n int, err error) { - if len(in) < 2 { - return 0, 0, fmt.Errorf("ssob: Decoding uint16: %w", ErrTypeInvalid) - } - - return binary.BigEndian.Uint16(in[0:2]), 2, nil -} - -func UnmarshalInt32(in []byte) (ret int32, n int, err error) { - if len(in) < 4 { - return 0, 0, fmt.Errorf("ssob: Decoding int32: %w", ErrTypeInvalid) - } - - return int32(binary.BigEndian.Uint32(in[0:4])), 4, nil -} - -func UnmarshalUint32(in []byte) (ret uint32, n int, err error) { - if len(in) < 4 { - return 0, 0, fmt.Errorf("ssob: Decoding uint32: %w", ErrTypeInvalid) - } - - return binary.BigEndian.Uint32(in[0:4]), 4, nil -} - -func UnmarshalFloat32(in []byte) (ret float32, n int, err error) { - if len(in) < 4 { - return 0, 0, fmt.Errorf("ssob: Decoding float32: %w", ErrTypeInvalid) - } - - return float32(math.Float32frombits(binary.BigEndian.Uint32(in[0:4]))), 4, nil -} - -func UnmarshalInt64(in []byte) (ret int64, n int, err error) { - if len(in) < 8 { - return 0, 0, fmt.Errorf("ssob: Decoding int64: %w", ErrTypeInvalid) - } - - return int64(binary.BigEndian.Uint64(in[0:8])), 8, nil -} - -func UnmarshalUint64(in []byte) (ret uint64, n int, err error) { - if len(in) < 8 { - return 0, 0, fmt.Errorf("ssob: Decoding uint64: %w", ErrTypeInvalid) - } - - return binary.BigEndian.Uint64(in[0:8]), 8, nil -} - -func UnmarshalFloat64(in []byte) (ret float64, n int, err error) { - if len(in) < 8 { - return 0, 0, fmt.Errorf("ssob: Decoding float64: %w", ErrTypeInvalid) - } - - return float64(math.Float64frombits(binary.BigEndian.Uint64(in[0:8]))), 8, nil -} - -type unmarshalFunc func(e interface{}, in []byte) (n int, err error) - -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, err - } - return 0, fmt.Errorf("ssob: Incompatible type - expected bool: %w", ErrTypeMismatch) - }) - RegisterDecoder("int8", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*int8); ok { - *i, n, err = UnmarshalInt8(in) - return n, err - } - return 0, fmt.Errorf("ssob: Incompatible type - expected int8: %w", ErrTypeMismatch) - }) - RegisterDecoder("uint8", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*uint8); ok { - *i, n, err = UnmarshalUint8(in) - return n, err - } - return 0, fmt.Errorf("ssob: Incompatible type - expected uint8: %w", ErrTypeMismatch) - }) - RegisterDecoder("int16", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*int16); ok { - *i, n, err = UnmarshalInt16(in) - return n, err - } - return 0, fmt.Errorf("ssob: Incompatible type - expected int16: %w", ErrTypeMismatch) - }) - RegisterDecoder("uint16", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*uint16); ok { - *i, n, err = UnmarshalUint16(in) - return n, err - } - return 0, fmt.Errorf("ssob: Incompatible type - expected uint16: %w", ErrTypeMismatch) - }) - RegisterDecoder("int32", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*int32); ok { - *i, n, err = UnmarshalInt32(in) - return n, err - } - return 0, fmt.Errorf("ssob: Incompatible type - expected int32: %w", ErrTypeMismatch) - }) - RegisterDecoder("uint32", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*uint32); ok { - *i, n, err = UnmarshalUint32(in) - return n, err - } - return 0, fmt.Errorf("ssob: Incompatible type - expected uint32: %w", ErrTypeMismatch) - }) - RegisterDecoder("float32", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*float32); ok { - *i, n, err = UnmarshalFloat32(in) - return n, err - } - return 0, fmt.Errorf("ssob: Incompatible type - expected float32: %w", ErrTypeMismatch) - }) - RegisterDecoder("int64", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*int64); ok { - *i, n, err = UnmarshalInt64(in) - return n, err - } - return 0, fmt.Errorf("ssob: Incompatible type - expected int64: %w", ErrTypeMismatch) - }) - RegisterDecoder("uint64", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*uint64); ok { - *i, n, err = UnmarshalUint64(in) - return n, err - } - return 0, fmt.Errorf("ssob: Incompatible type - expected uint64: %w", ErrTypeMismatch) - }) - RegisterDecoder("float64", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*float64); ok { - *i, n, err = UnmarshalFloat64(in) - return n, err - } - return 0, fmt.Errorf("ssob: Incompatible type - expected float64: %w", ErrTypeMismatch) - }) - RegisterDecoder("string", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*string); ok { - *i, n, err = UnmarshalString(in) - return n, err - } - return 0, fmt.Errorf("ssob: Incompatible type - expected string: %w", ErrTypeMismatch) - }) -} - -func decRegister(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{}, 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, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) - } - - l, r, err := UnmarshalInt32(in) - pos += r - if err != nil { - return pos, err - } - - ti := v.Elem() - if int(l) != ti.Len() { - return pos, fmt.Errorf("ssob: Invalid array length. Expected %s got %s: %w", string(l), string(ti.Len()), ErrValueInvalid) - } - 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) - v := reflect.ValueOf(e) - pos := 0 - - if t.Kind() != reflect.Ptr || v.IsNil() { - return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) - } - - l, r, err := UnmarshalInt32(in) - pos += r - if err != nil { - return pos, err - } - - ti := v.Elem() - ti.Set(reflect.MakeSlice(reflect.TypeOf(ti.Interface()), 0, ti.Cap())) - 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.Set(reflect.Append(ti, reflect.Indirect(e))) - } - return pos, nil - } - decoderCache[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{}, 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, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) - } - - vi := reflect.Indirect(v) - for _, i := range mfields { - ni, err := unmarshal(vi.Field(i).Addr().Interface(), in[pos:]) - pos += ni - if err != nil { - return pos, err - } - } - - return pos, nil - } - decoderCache[t.Name()] = f - case reflect.Map: - 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, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) - } - - l, r, err := UnmarshalInt32(in) - pos += r - if err != nil { - return pos, err - } - - vi := reflect.Indirect(v) - vt := reflect.TypeOf(vi.Interface()) - tk := vt.Key() - tv := vt.Elem() - for i := int32(0); i < l; i++ { - ek := reflect.New(tk) - ev := reflect.New(tv) - r, err := unmarshal(ek.Interface(), in[pos:]) - pos += r - if err != nil { - return pos, err - } - r, err = unmarshal(ev.Interface(), in[pos:]) - pos += r - if err != nil { - return pos, err - } - vi.SetMapIndex(reflect.Indirect(ek), reflect.Indirect(ev)) - } - - return pos, nil - } - decoderCache[string(t.Kind())] = f - case reflect.Bool: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := bool(false) - pos := 0 - - r, err := unmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetBool(bool(i)) - - return pos, nil - } - decoderCache[t.Name()] = f - case reflect.Uint8: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := uint8(0) - pos := 0 - - r, err := unmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetUint(uint64(i)) - - return pos, nil - } - decoderCache[t.Name()] = f - case reflect.Uint16: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := uint16(0) - pos := 0 - - r, err := unmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetUint(uint64(i)) - - return pos, nil - } - decoderCache[t.Name()] = f - case reflect.Uint32: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := uint32(0) - pos := 0 - - r, err := unmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetUint(uint64(i)) - - return pos, nil - } - decoderCache[t.Name()] = f - case reflect.Uint64: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := uint64(0) - pos := 0 - - r, err := unmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetUint(uint64(i)) - - return pos, nil - } - decoderCache[t.Name()] = f - case reflect.Int8: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := int8(0) - pos := 0 - - r, err := unmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetInt(int64(i)) - - return pos, nil - } - decoderCache[t.Name()] = f - case reflect.Int16: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := int16(0) - pos := 0 - - r, err := unmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetInt(int64(i)) - - return pos, nil - } - decoderCache[t.Name()] = f - case reflect.Int32: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := int32(0) - pos := 0 - - r, err := unmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetInt(int64(i)) - - return pos, nil - } - decoderCache[t.Name()] = f - case reflect.Int64: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := int64(0) - pos := 0 - - r, err := unmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetInt(int64(i)) - - return pos, nil - } - decoderCache[t.Name()] = f - case reflect.String: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := string("") - pos := 0 - - r, err := unmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetString(i) - - return pos, nil - } - decoderCache[t.Name()] = f - default: - return fmt.Errorf("ssob: %s: %w", string(t.Name()), ErrTypeUnknown) - } - - return nil -} - -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: - return decoderCache["uint8"](t, in) - case *int16: - return decoderCache["int16"](t, in) - case *uint16: - return decoderCache["uint16"](t, in) - case *int32: - return decoderCache["int32"](t, in) - case *uint32: - return decoderCache["uint32"](t, in) - case *int64: - return decoderCache["int64"](t, in) - case *uint64: - return decoderCache["uint64"](t, in) - case *float32: - return decoderCache["float32"](t, in) - case *float64: - return decoderCache["float64"](t, in) - case *string: - return decoderCache["string"](t, in) - default: - return 0, fmt.Errorf("ssob: No base type: %w", ErrTypeUnknown) - } -} - -func unmarshal(e interface{}, in []byte) (n int, err error) { - n, err = unmarshalBaseType(e, in) - if err == nil { - return n, err - } - - var key string - t := reflect.TypeOf(e) - v := reflect.ValueOf(e) - if !v.IsValid() || t.Kind() != reflect.Ptr || v.IsNil() { - return 0, fmt.Errorf("ssob: Need a pointer that is fully allocated for unmarshalling: %w", ErrValueInvalid) - } - - p := reflect.Indirect(v) - if p.Kind() != reflect.Ptr && p.Kind() != reflect.Interface { - switch p.Kind() { - case reflect.Bool, reflect.Int8, reflect.Int16, reflect.Int32, - reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, - reflect.Uint64, reflect.String, reflect.Struct: - key = reflect.TypeOf(p.Interface()).Name() - default: - key = string(p.Kind()) - } - - if f, ok := decoderCache[key]; ok { - return f(v.Interface(), in) - } else { - err = decRegister(p.Interface()) - if err != nil { - return 0, err - } - return unmarshal(e, in) - } - } - if !p.Elem().IsValid() { - err = allocType(v) - if err != nil { - return 0, err - } - p = reflect.Indirect(v) - } - - return unmarshal(p.Interface(), in) -} - -func RegisterDecoder(name string, f func(e interface{}, in []byte) (n int, err error)) { - decoderCache[name] = f -} - -func baseTypeUnmarshaller(e uint32, r io.Reader) (ret interface{}, err error) { - switch e { - case ST_BOOL: - sb := make([]byte, 1) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode bool failed: %w: %s", ErrValueInvalid, err.Error()) - } - ret = cacheTypes.types[ST_BOOL].alloc() - if sb[0] == byte(0) { - *(ret.(*bool)) = true - } else { - *(ret.(*bool)) = false - } - case ST_UINT8: - sb := make([]byte, 1) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode uint8 failed: %w: %s", ErrValueInvalid, err.Error()) - } - ret = cacheTypes.types[ST_UINT8].alloc() - *(ret.(*uint8)) = uint8(sb[0]) - case ST_UINT16: - sb := make([]byte, 2) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode uint16 failed: %w: %s", ErrValueInvalid, err.Error()) - } - ret = cacheTypes.types[ST_UINT16].alloc() - *(ret.(*uint16)) = binary.BigEndian.Uint16(sb[0:2]) - case ST_UINT32: - sb := make([]byte, 4) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode uint32 failed: %w: %s", ErrValueInvalid, err.Error()) - } - ret = cacheTypes.types[ST_UINT32].alloc() - *(ret.(*uint32)) = binary.BigEndian.Uint32(sb[0:4]) - case ST_UINT64: - sb := make([]byte, 8) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode uint64 failed: %w: %s", ErrValueInvalid, err.Error()) - } - ret = cacheTypes.types[ST_UINT64].alloc() - *(ret.(*uint64)) = binary.BigEndian.Uint64(sb[0:8]) - case ST_INT8: - sb := make([]byte, 1) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode int8 failed: %w: %s", ErrValueInvalid, err.Error()) - } - ret = cacheTypes.types[ST_INT8].alloc() - *(ret.(*int8)) = int8(sb[0]) - case ST_INT16: - sb := make([]byte, 2) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode int16 failed: %w: %s", ErrValueInvalid, err.Error()) - } - ret = cacheTypes.types[ST_INT16].alloc() - *(ret.(*int16)) = int16(binary.BigEndian.Uint16(sb[0:2])) - case ST_INT32: - sb := make([]byte, 4) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode int32 failed: %w: %s", ErrValueInvalid, err.Error()) - } - ret = cacheTypes.types[ST_INT32].alloc() - *(ret.(*int32)) = int32(binary.BigEndian.Uint32(sb[0:4])) - case ST_INT64: - sb := make([]byte, 8) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode int64 failed: %w: %s", ErrValueInvalid, err.Error()) - } - ret = cacheTypes.types[ST_INT64].alloc() - *(ret.(*int64)) = int64(binary.BigEndian.Uint64(sb[0:8])) - case ST_FLOAT32: - sb := make([]byte, 4) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode float32 failed: %w: %s", ErrValueInvalid, err.Error()) - } - ret = cacheTypes.types[ST_FLOAT32].alloc() - *(ret.(*float32)) = float32(math.Float32frombits(binary.BigEndian.Uint32(sb[0:4]))) - case ST_FLOAT64: - sb := make([]byte, 8) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode float64 failed: %w: %s", ErrValueInvalid, err.Error()) - } - ret = cacheTypes.types[ST_FLOAT64].alloc() - *(ret.(*float64)) = float64(math.Float64frombits(binary.BigEndian.Uint64(sb[0:8]))) - case ST_STRING: - sb := make([]byte, 4) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode string failed: %w: %s", ErrValueInvalid, err.Error()) - } - slen := binary.BigEndian.Uint32(sb[0:4]) - ret = cacheTypes.types[ST_STRING].alloc() - - sb = make([]byte, slen) - if err = binary.Read(r, binary.BigEndian, sb); err != nil { - return nil, fmt.Errorf("ssob: Decode string failed: %w: %s", ErrValueInvalid, err.Error()) - } - *(ret.(*string)) = string(sb) - default: - return nil, fmt.Errorf("ssob: Unknown type: %d: %w", e, ErrTypeInvalid) - } - - return ret, err -} - -func unmarshalBool(e []byte) (ie []byte, ret bool) { if e[0] == 0 { ret = true } else { ret = false } - return e[1:], ret + return e[1:], ret, err } -func unmarshalUint8(e []byte) (ie []byte, ret uint8) { - return e[1:], uint8(byte(e[0])) +func unmarshalUint8(e []byte) (ie []byte, ret uint8, err error) { + if len(e) < 1 { + return e, ret, ErrValueInvalid + } + return e[1:], uint8(byte(e[0])), err } -func unmarshalUint16(e []byte) (ie []byte, ret uint16) { - return e[2:], binary.BigEndian.Uint16(e) +func unmarshalUint16(e []byte) (ie []byte, ret uint16, err error) { + if len(e) < 2 { + return e, ret, ErrValueInvalid + } + return e[2:], binary.BigEndian.Uint16(e), err } -func unmarshalUint32(e []byte) (ie []byte, ret uint32) { - return e[4:], binary.BigEndian.Uint32(e) +func unmarshalUint32(e []byte) (ie []byte, ret uint32, err error) { + if len(e) < 4 { + return e, ret, ErrValueInvalid + } + return e[4:], binary.BigEndian.Uint32(e), err } -func unmarshalUint64(e []byte) (ie []byte, ret uint64) { - return e[8:], binary.BigEndian.Uint64(e) +func unmarshalUint64(e []byte) (ie []byte, ret uint64, err error) { + if len(e) < 8 { + return e, ret, ErrValueInvalid + } + return e[8:], binary.BigEndian.Uint64(e), err } -func unmarshalInt8(e []byte) (ie []byte, ret int8) { - return e[1:], int8(byte(e[0])) +func unmarshalInt8(e []byte) (ie []byte, ret int8, err error) { + if len(e) < 1 { + return e, ret, ErrValueInvalid + } + return e[1:], int8(byte(e[0])), err } -func unmarshalInt16(e []byte) (ie []byte, ret int16) { - return e[2:], int16(binary.BigEndian.Uint16(e)) +func unmarshalInt16(e []byte) (ie []byte, ret int16, err error) { + if len(e) < 2 { + return e, ret, ErrValueInvalid + } + return e[2:], int16(binary.BigEndian.Uint16(e)), err } -func unmarshalInt32(e []byte) (ie []byte, ret int32) { - return e[4:], int32(binary.BigEndian.Uint32(e)) +func unmarshalInt32(e []byte) (ie []byte, ret int32, err error) { + if len(e) < 4 { + return e, ret, ErrValueInvalid + } + return e[4:], int32(binary.BigEndian.Uint32(e)), err } -func unmarshalInt64(e []byte) (ie []byte, ret int64) { - return e[8:], int64(binary.BigEndian.Uint64(e)) +func unmarshalInt64(e []byte) (ie []byte, ret int64, err error) { + if len(e) < 4 { + return e, ret, ErrValueInvalid + } + return e[8:], int64(binary.BigEndian.Uint64(e)), err } -func unmarshalFloat32(e []byte) (ie []byte, ret float32) { - return e[4:], float32(math.Float32frombits(binary.BigEndian.Uint32(e))) +func unmarshalFloat32(e []byte) (ie []byte, ret float32, err error) { + if len(e) < 4 { + return e, ret, ErrValueInvalid + } + return e[4:], float32(math.Float32frombits(binary.BigEndian.Uint32(e))), err } -func unmarshalFloat64(e []byte) (ie []byte, ret float64) { - return e[8:], float64(math.Float64frombits(binary.BigEndian.Uint64(e))) +func unmarshalFloat64(e []byte) (ie []byte, ret float64, err error) { + if len(e) < 8 { + return e, ret, ErrValueInvalid + } + return e[8:], float64(math.Float64frombits(binary.BigEndian.Uint64(e))), err } -func unmarshalString(e []byte) (ie []byte, ret string) { +func unmarshalString(e []byte) (ie []byte, ret string, err error) { + ie = e + + if len(ie) < 4 { + return ie, ret, ErrValueInvalid + } slen := binary.BigEndian.Uint32(e) - ret = string(e[4 : 4+slen]) - return e[4+slen:], ret + ie = ie[4:] + + if len(ie) < int(slen) { + return ie, ret, ErrValueInvalid + } + ret = string(ie[:slen]) + ie = ie[slen:] + return ie, ret, err } -func unmarshalNil(e []byte) (ie []byte, ret uint16) { +func unmarshalNil(e []byte) (ie []byte, ret uint16, err error) { return unmarshalUint16(e) } @@ -764,9 +118,15 @@ func unmarshalPtrIfNil(e []byte, ntype *NType) (ie []byte, ret interface{}, isNi ret = ntype.alloc() var nl uint16 - ie, eId := unmarshalTypeId(e) + ie, eId, err := unmarshalTypeId(e) + if err != nil { + return ie, ret, isNil, err + } if eId == ST_NIL { - ie, nl = unmarshalNil(ie) + ie, nl, err = unmarshalNil(ie) + if err != nil { + return ie, ret, isNil, err + } err = setTypeNil(ret, int(nl)) return ie, ret, true, err } @@ -776,7 +136,7 @@ func unmarshalPtrIfNil(e []byte, ntype *NType) (ie []byte, ret interface{}, isNi } if eId != ntype.ValType { - return ie, ret, false, fmt.Errorf("Type mismatch") + return ie, ret, false, ErrTypeInvalid } return ie, ret, false, err @@ -786,36 +146,45 @@ func unmarshalError(e []byte, ntype *NType) (ie []byte, ret interface{}, err err ret = ntype.alloc() var nl uint16 - ie, eId := unmarshalTypeId(e) + ie, eId, err := unmarshalTypeId(e) + if err != nil { + return ie, ret, err + } if eId == ST_NIL { - ie, nl = unmarshalNil(ie) + ie, nl, err = unmarshalNil(ie) + if err != nil { + return ie, ret, err + } err = setTypeNil(ret, int(nl)) return ie, ret, err } if eId != ST_STRING { - return ie, ret, fmt.Errorf("Type mismatch") + return ie, ret, ErrTypeInvalid + } + ie, v, err := unmarshalString(ie) + if err != nil { + return ie, ret, err } - ie, v := unmarshalString(ie) err = setTypeVal(ret, fmt.Errorf(v), ntype) return ie, ret, err } -func unmarshalTypeId(e []byte) (ie []byte, ret uint32) { +func unmarshalTypeId(e []byte) (ie []byte, ret uint32, err error) { return unmarshalUint32(e) } func unmarshalCommon(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) { ctype := getTypeById(ntype.ValType) if ctype == nil { - return e, ret, fmt.Errorf("ssob: Unknown common type '%d': %w", ntype.ValType, ErrTypeUnknown) + return e, ret, ErrTypeUnknown } // pointer could be nil ie, ptrNil, isNil, err := unmarshalPtrIfNil(e, ntype) if err != nil { - return ie, ret, fmt.Errorf("ssob: Cannot unmarshal common type '%s': %w", ntype.Name, err) + return ie, ret, err } if ptrNil != nil { @@ -831,79 +200,118 @@ func unmarshalCommon(e []byte, ntype *NType) (ie []byte, ret interface{}, err er switch ctype.Id { case ST_BOOL: var v bool - ie, v = unmarshalBool(ie) + ie, v, err = unmarshalBool(ie) + if err != nil { + return ie, ret, err + } setTypeVal(ret, v, ntype) return ie, ret, err case ST_UINT8: var v uint8 - ie, v = unmarshalUint8(ie) + ie, v, err = unmarshalUint8(ie) + if err != nil { + return ie, ret, err + } setTypeVal(ret, v, ntype) return ie, ret, err case ST_UINT16: var v uint16 - ie, v = unmarshalUint16(ie) + ie, v, err = unmarshalUint16(ie) + if err != nil { + return ie, ret, err + } setTypeVal(ret, v, ntype) return ie, ret, err case ST_UINT32: var v uint32 - ie, v = unmarshalUint32(ie) + ie, v, err = unmarshalUint32(ie) + if err != nil { + return ie, ret, err + } setTypeVal(ret, v, ntype) return ie, ret, err case ST_UINT64: var v uint64 - ie, v = unmarshalUint64(ie) + ie, v, err = unmarshalUint64(ie) + if err != nil { + return ie, ret, err + } setTypeVal(ret, v, ntype) return ie, ret, err case ST_INT8: var v int8 - ie, v = unmarshalInt8(ie) + ie, v, err = unmarshalInt8(ie) + if err != nil { + return ie, ret, err + } setTypeVal(ret, v, ntype) return ie, ret, err case ST_INT16: var v int16 - ie, v = unmarshalInt16(ie) + ie, v, err = unmarshalInt16(ie) + if err != nil { + return ie, ret, err + } setTypeVal(ret, v, ntype) return ie, ret, err case ST_INT32: var v int32 - ie, v = unmarshalInt32(ie) + ie, v, err = unmarshalInt32(ie) + if err != nil { + return ie, ret, err + } setTypeVal(ret, v, ntype) return ie, ret, err case ST_INT64: var v int64 - ie, v = unmarshalInt64(ie) + ie, v, err = unmarshalInt64(ie) + if err != nil { + return ie, ret, err + } setTypeVal(ret, v, ntype) return ie, ret, err case ST_FLOAT32: var v float32 - ie, v = unmarshalFloat32(ie) + ie, v, err = unmarshalFloat32(ie) + if err != nil { + return ie, ret, err + } setTypeVal(ret, v, ntype) return ie, ret, err case ST_FLOAT64: var v float64 - ie, v = unmarshalFloat64(ie) + ie, v, err = unmarshalFloat64(ie) + if err != nil { + return ie, ret, err + } setTypeVal(ret, v, ntype) return ie, ret, err case ST_STRING: var v string - ie, v = unmarshalString(ie) + ie, v, err = unmarshalString(ie) + if err != nil { + return ie, ret, err + } setTypeVal(ret, v, ntype) return ie, ret, err case ST_ERROR: return unmarshalError(ie, ntype) default: - return ie, ret, fmt.Errorf("ssob: Unknown common type '%d': %w", ctype.Id, ErrTypeUnknown) + return ie, ret, ErrTypeUnknown } } func unmarshalSlice(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) { ret = ntype.alloc() rv := getVal(ret) - ie, l := unmarshalUint32(e) + ie, l, err := unmarshalUint32(e) + if err != nil { + return ie, ret, err + } stype := getTypeById(ntype.ValType) if stype == nil { - return ie, ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + return ie, ret, ErrTypeUnknown } var v interface{} @@ -913,6 +321,7 @@ func unmarshalSlice(e []byte, ntype *NType) (ie []byte, ret interface{}, err err return ie, ret, err } + // TODO: checks? rv.Set(reflect.Append(rv, getVal(v))) } @@ -925,7 +334,7 @@ func unmarshalArray(e []byte, ntype *NType) (ie []byte, ret interface{}, err err stype := getTypeById(ntype.ValType) if stype == nil { - return ie, ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + return ie, ret, ErrTypeUnknown } var v interface{} @@ -935,6 +344,7 @@ func unmarshalArray(e []byte, ntype *NType) (ie []byte, ret interface{}, err err if err != nil { return ie, ret, err } + // TODO: checks? rv.Index(i).Set(getVal(v)) } @@ -948,25 +358,27 @@ func unmarshalStruct(e []byte, ntype *NType) (ie []byte, ret interface{}, err er stype := getTypeById(ntype.ValType) if stype == nil { - return ie, ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + return ie, ret, ErrTypeUnknown } var v interface{} for i, field := range stype.structFields { - for j := i; j < rv.NumField(); j++ { - if rv.Field(j).CanSet() { - ftype := getTypeById(field.Id) - if ftype == nil { - return ie, ret, fmt.Errorf("ssob: Unknown type '%d': %w", field.Id, ErrTypeUnknown) - } - - ie, v, err = unmarshalType(ie, ftype) - if err != nil { - return ie, ret, err - } - rv.Field(j).Set(getVal(v)) - break + if i > rv.NumField() { + return ie, ret, ErrTypeInvalid + } + if rv.Field(field.SId).CanSet() { + ftype := getTypeById(field.Id) + if ftype == nil { + return ie, ret, ErrTypeUnknown } + + ie, v, err = unmarshalType(ie, ftype) + if err != nil { + return ie, ret, err + } + // TODO: checks? + rv.Field(i).Set(getVal(v)) + break } } @@ -977,7 +389,7 @@ func unmarshalInterface(e []byte, ntype *NType) (ie []byte, ret interface{}, err ie = e stype := getTypeById(ntype.ValType) if stype == nil { - return ie, ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + return ie, ret, ErrTypeUnknown } return unmarshalCommon(ie, ntype) @@ -996,21 +408,24 @@ func unmarshalType(e []byte, ntype *NType) (ie []byte, ret interface{}, err erro case ST_INTERFACE: return unmarshalInterface(e, ntype) default: - return e, ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.MainTypeId, ErrTypeUnknown) + return e, ret, ErrTypeUnknown } } func unmarshalVal(e []byte) (ie []byte, ret interface{}, err error) { if len(e) < ST_ID_SIZE { - return ie, ret, fmt.Errorf("ssob: Cannot unmarshal: %w", ErrValueInvalid) + return ie, ret, ErrValueInvalid } // type id var tid uint32 - ie, tid = unmarshalTypeId(e) + ie, tid, err = unmarshalTypeId(e) + if err != nil { + return ie, ret, err + } vt := getTypeById(tid) if vt == nil { - return ie, ret, fmt.Errorf("ssob: Unknown type '%d': %w", tid, ErrTypeUnknown) + return ie, ret, ErrTypeUnknown } // alloc @@ -1018,16 +433,22 @@ func unmarshalVal(e []byte) (ie []byte, ret interface{}, err error) { // check for nil if len(ie) < 1 { - return ie, ret, fmt.Errorf("ssob: Cannot unmarshal: %w", ErrValueInvalid) + return ie, ret, ErrValueInvalid + } + ie, isNil, err := unmarshalBool(ie) + if err != nil { + return ie, ret, err } - ie, isNil := unmarshalBool(ie) if isNil { if len(ie) < 2 { - return ie, ret, fmt.Errorf("ssob: Cannot unmarshal: %w", ErrValueInvalid) + return ie, ret, ErrValueInvalid + } + ie, nl, err := unmarshalNil(ie) + if err != nil { + return ie, ret, err } - ie, nl := unmarshalNil(ie) if int(nl) > vt.Indirection { - return ie, ret, fmt.Errorf("ssob: Cannot unmarshal: %w", ErrValueInvalid) + return ie, ret, ErrValueInvalid } err = setTypeNil(ret, int(nl)) return ie, ret, err diff --git a/unsafe_decoder.go b/unsafe_decoder.go deleted file mode 100644 index 59a088e..0000000 --- a/unsafe_decoder.go +++ /dev/null @@ -1,56 +0,0 @@ -package ssob - -import ( - "encoding/binary" - "fmt" - "io" - "reflect" - "sync" -) - -type UnsafeDecoder struct { - mutex sync.Mutex - r io.Reader -} - -func NewUnsafeDecoder(r io.Reader) *UnsafeDecoder { - dec := new(UnsafeDecoder) - dec.r = r - return dec -} - -func (dec *UnsafeDecoder) Decode(e interface{}) (err error) { - return dec.DecodeValue(reflect.ValueOf(e)) -} - -func (dec *UnsafeDecoder) DecodeValue(value reflect.Value) (err error) { - if value.Kind() == reflect.Invalid { - return fmt.Errorf("ssob: Cannot decode nil: %w", ErrValueInvalid) - } - - if value.Kind() == reflect.Ptr && value.IsNil() { - return fmt.Errorf("ssob: Cannot decode nil of type %s: %w", value.Type().String(), ErrValueInvalid) - } - - dec.mutex.Lock() - defer dec.mutex.Unlock() - - lb := make([]byte, 4) - err = binary.Read(dec.r, binary.BigEndian, lb) - if err != nil { - return err - } - l, n, err := UnsafeUnmarshalInt32(lb) - if err != nil || n != 4 { - return err - } - - bb := make([]byte, l) - err = binary.Read(dec.r, binary.BigEndian, bb) - if err != nil { - return err - } - - _, err = unsafeUnmarshal(value.Interface(), bb) - return err -} diff --git a/unsafe_encoder.go b/unsafe_encoder.go deleted file mode 100644 index 920059d..0000000 --- a/unsafe_encoder.go +++ /dev/null @@ -1,49 +0,0 @@ -package ssob - -import ( - "encoding/binary" - "fmt" - "io" - "reflect" - "sync" -) - -type UnsafeEncoder struct { - mutex sync.Mutex - w io.Writer -} - -func NewUnsafeEncoder(w io.Writer) *UnsafeEncoder { - enc := new(UnsafeEncoder) - enc.w = w - return enc -} - -func (enc *UnsafeEncoder) Encode(e interface{}) (err error) { - return enc.EncodeValue(reflect.ValueOf(e)) -} - -func (enc *UnsafeEncoder) EncodeValue(value reflect.Value) (err error) { - if value.Kind() == reflect.Invalid { - return fmt.Errorf("ssob: Cannot encode nil: %w", ErrValueInvalid) - } - - if value.Kind() == reflect.Ptr && value.IsNil() { - return fmt.Errorf("ssob: Cannot encode nil of type %s: %w", value.Type().String(), ErrValueInvalid) - } - - bb, err := unsafeMarshal(value.Interface()) - if err != nil { - return err - } - bl := UnsafeMarshalInt32(int32(len(bb))) - - w := make([]byte, 4+len(bb)) - copy(w, bl) - copy(w[4:], bb) - - enc.mutex.Lock() - defer enc.mutex.Unlock() - - return binary.Write(enc.w, binary.BigEndian, w) -} diff --git a/unsafe_marshal.go b/unsafe_marshal.go deleted file mode 100644 index 04c3050..0000000 --- a/unsafe_marshal.go +++ /dev/null @@ -1,527 +0,0 @@ -package ssob - -import ( - "fmt" - "reflect" - "unsafe" -) - -func UnsafeMarshalString(in string) (ret []byte) { - l := int32(len(in)) - b := UnsafeMarshalInt32(l) - ret = make([]byte, int(l)+len(b)) - copy(ret, b) - copy(ret[4:], []byte(in)) - 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)} -} - -func UnsafeMarshalUint8(in uint8) (ret []byte) { - return []byte{byte(in)} -} - -func UnsafeMarshalInt16(in int16) (ret []byte) { - out := make([]byte, 2) - - start := unsafe.Pointer(&in) - if littleEndian { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - } else { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - } - - return out -} - -func UnsafeMarshalUint16(in uint16) (ret []byte) { - out := make([]byte, 2) - - start := unsafe.Pointer(&in) - if littleEndian { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - } else { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - } - - return out -} - -func UnsafeMarshalInt32(in int32) (ret []byte) { - out := make([]byte, 4) - - start := unsafe.Pointer(&in) - if littleEndian { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) - out[2] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[3] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - } else { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[2] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) - out[3] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) - } - - return out -} - -func UnsafeMarshalUint32(in uint32) (ret []byte) { - out := make([]byte, 4) - - start := unsafe.Pointer(&in) - if littleEndian { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) - out[2] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[3] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - } else { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[2] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) - out[3] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) - } - - return out -} - -func UnsafeMarshalFloat32(in float32) (ret []byte) { - out := make([]byte, 4) - - start := unsafe.Pointer(&in) - if littleEndian { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) - out[2] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[3] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - } else { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[2] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) - out[3] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) - } - - return out -} - -func UnsafeMarshalInt64(in int64) (ret []byte) { - out := make([]byte, 8) - - start := unsafe.Pointer(&in) - if littleEndian { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) - out[2] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) - out[3] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) - out[4] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) - out[5] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) - out[6] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[7] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - } else { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[2] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) - out[3] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) - out[4] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) - out[5] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) - out[6] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) - out[7] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) - } - - return out -} - -func UnsafeMarshalUint64(in uint64) (ret []byte) { - out := make([]byte, 8) - - start := unsafe.Pointer(&in) - if littleEndian { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) - out[2] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) - out[3] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) - out[4] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) - out[5] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) - out[6] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[7] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - } else { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[2] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) - out[3] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) - out[4] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) - out[5] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) - out[6] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) - out[7] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) - } - - return out -} - -func UnsafeMarshalFloat64(in float64) (ret []byte) { - out := make([]byte, 8) - - start := unsafe.Pointer(&in) - if littleEndian { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) - out[2] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) - out[3] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) - out[4] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) - out[5] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) - out[6] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[7] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - } else { - out[0] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) - out[1] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) - out[2] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) - out[3] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) - out[4] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) - out[5] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) - out[6] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) - out[7] = *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) - } - - return out -} - -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, fmt.Errorf("ssob: Incompatible type - expected bool: %w", ErrTypeMismatch) - }) - RegisterUnsafeEncoder("int8", func(e interface{}) (ret []byte, err error) { - if i, ok := e.(int8); ok { - return UnsafeMarshalInt8(i), nil - } - return nil, fmt.Errorf("ssob: Incompatible type - expected int8: %w", ErrTypeMismatch) - }) - RegisterUnsafeEncoder("uint8", func(e interface{}) (ret []byte, err error) { - if i, ok := e.(uint8); ok { - return UnsafeMarshalUint8(i), nil - } - return nil, fmt.Errorf("ssob: Incompatible type - expected uint8: %w", ErrTypeMismatch) - }) - RegisterUnsafeEncoder("int16", func(e interface{}) (ret []byte, err error) { - if i, ok := e.(int16); ok { - return UnsafeMarshalInt16(i), nil - } - return nil, fmt.Errorf("ssob: Incompatible type - expected int16: %w", ErrTypeMismatch) - }) - RegisterUnsafeEncoder("uint16", func(e interface{}) (ret []byte, err error) { - if i, ok := e.(uint16); ok { - return UnsafeMarshalUint16(i), nil - } - return nil, fmt.Errorf("ssob: Incompatible type - expected uint16: %w", ErrTypeMismatch) - }) - RegisterUnsafeEncoder("int32", func(e interface{}) (ret []byte, err error) { - if i, ok := e.(int32); ok { - return UnsafeMarshalInt32(i), nil - } - return nil, fmt.Errorf("ssob: Incompatible type - expected int32: %w", ErrTypeMismatch) - }) - RegisterUnsafeEncoder("uint32", func(e interface{}) (ret []byte, err error) { - if i, ok := e.(uint32); ok { - return UnsafeMarshalUint32(i), nil - } - return nil, fmt.Errorf("ssob: Incompatible type - expected uint32: %w", ErrTypeMismatch) - }) - RegisterUnsafeEncoder("float32", func(e interface{}) (ret []byte, err error) { - if i, ok := e.(float32); ok { - return UnsafeMarshalFloat32(i), nil - } - return nil, fmt.Errorf("ssob: Incompatible type - expected float32: %w", ErrTypeMismatch) - }) - RegisterUnsafeEncoder("int64", func(e interface{}) (ret []byte, err error) { - if i, ok := e.(int64); ok { - return UnsafeMarshalInt64(i), nil - } - return nil, fmt.Errorf("ssob: Incompatible type - expected int64: %w", ErrTypeMismatch) - }) - RegisterUnsafeEncoder("uint64", func(e interface{}) (ret []byte, err error) { - if i, ok := e.(uint64); ok { - return UnsafeMarshalUint64(i), nil - } - return nil, fmt.Errorf("ssob: Incompatible type - expected uint64: %w", ErrTypeMismatch) - }) - RegisterUnsafeEncoder("float64", func(e interface{}) (ret []byte, err error) { - if i, ok := e.(float64); ok { - return UnsafeMarshalFloat64(i), nil - } - return nil, fmt.Errorf("ssob: Incompatible type - expected float64: %w", ErrTypeMismatch) - }) - RegisterUnsafeEncoder("string", func(e interface{}) (ret []byte, err error) { - if i, ok := e.(string); ok { - return UnsafeMarshalString(i), nil - } - return nil, fmt.Errorf("ssob: Incompatible type - expected string: %w", ErrTypeMismatch) - }) -} - -func encRegisterUnsafe(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 := 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) - 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.Map: - f := func(e interface{}) (ret []byte, err error) { - v := reflect.ValueOf(e) - l := v.Len() - ret = UnsafeMarshalInt32(int32(l)) - for _, ek := range v.MapKeys() { - ee := v.MapIndex(ek) - b, err := unsafeMarshal(ek.Interface()) - if err != nil { - return nil, err - } - ret = append(ret, b...) - - b, err = unsafeMarshal(ee.Interface()) - if err != nil { - return nil, err - } - ret = append(ret, b...) - } - return ret, nil - } - unsafeEncoderCache[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 = unsafeMarshal(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 - } - unsafeEncoderCache[t.Name()] = f - case reflect.Bool: - f := func(e interface{}) (ret []byte, err error) { - v := reflect.ValueOf(e) - return unsafeMarshalBaseType(bool(v.Bool())) - } - unsafeEncoderCache[t.Name()] = f - case reflect.Uint8: - f := func(e interface{}) (ret []byte, err error) { - v := reflect.ValueOf(e) - return unsafeMarshalBaseType(string(v.String())) - } - unsafeEncoderCache[t.Name()] = f - case reflect.Uint16: - f := func(e interface{}) (ret []byte, err error) { - v := reflect.ValueOf(e) - return unsafeMarshalBaseType(string(v.String())) - } - unsafeEncoderCache[t.Name()] = f - case reflect.Uint32: - f := func(e interface{}) (ret []byte, err error) { - v := reflect.ValueOf(e) - return unsafeMarshalBaseType(string(v.String())) - } - unsafeEncoderCache[t.Name()] = f - case reflect.Uint64: - f := func(e interface{}) (ret []byte, err error) { - v := reflect.ValueOf(e) - return unsafeMarshalBaseType(string(v.String())) - } - unsafeEncoderCache[t.Name()] = f - case reflect.Int8: - f := func(e interface{}) (ret []byte, err error) { - v := reflect.ValueOf(e) - return unsafeMarshalBaseType(string(v.String())) - } - unsafeEncoderCache[t.Name()] = f - case reflect.Int16: - f := func(e interface{}) (ret []byte, err error) { - v := reflect.ValueOf(e) - return unsafeMarshalBaseType(string(v.String())) - } - unsafeEncoderCache[t.Name()] = f - case reflect.Int32: - f := func(e interface{}) (ret []byte, err error) { - v := reflect.ValueOf(e) - return unsafeMarshalBaseType(string(v.String())) - } - unsafeEncoderCache[t.Name()] = f - case reflect.Int64: - f := func(e interface{}) (ret []byte, err error) { - v := reflect.ValueOf(e) - return unsafeMarshalBaseType(string(v.String())) - } - unsafeEncoderCache[t.Name()] = f - case reflect.String: - f := func(e interface{}) (ret []byte, err error) { - v := reflect.ValueOf(e) - return unsafeMarshalBaseType(string(v.String())) - } - unsafeEncoderCache[t.Name()] = f - default: - return fmt.Errorf("ssob: %s: %w", string(t.Name()), ErrTypeUnknown) - } - - return nil -} - -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: - return unsafeEncoderCache["uint8"](t) - case int16: - return unsafeEncoderCache["int16"](t) - case uint16: - return unsafeEncoderCache["uint16"](t) - case int32: - return unsafeEncoderCache["int32"](t) - case uint32: - return unsafeEncoderCache["uint32"](t) - case int64: - return unsafeEncoderCache["int64"](t) - case uint64: - return unsafeEncoderCache["uint64"](t) - case float32: - return unsafeEncoderCache["float32"](t) - case float64: - return unsafeEncoderCache["float64"](t) - case string: - return unsafeEncoderCache["string"](t) - default: - return nil, fmt.Errorf("ssob: No base type: %w", ErrTypeUnknown) - } -} - -func unsafeMarshal(e interface{}) (ret []byte, err error) { - ret, err = unsafeMarshalBaseType(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 unsafeMarshal(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 := unsafeEncoderCache[key]; ok { - return f(e) - } else { - err = encRegisterUnsafe(e) - if err != nil { - return nil, err - } - } - - return unsafeMarshal(e) -} - -func RegisterUnsafeEncoder(name string, f MarshalFunc) { - unsafeEncoderCache[name] = f -} diff --git a/unsafe_unmarshal.go b/unsafe_unmarshal.go deleted file mode 100644 index a1b494b..0000000 --- a/unsafe_unmarshal.go +++ /dev/null @@ -1,720 +0,0 @@ -package ssob - -import ( - "encoding/binary" - "fmt" - "reflect" - "unsafe" -) - -func UnsafeUnmarshalString(in []byte) (ret string, n int, err error) { - if len(in) < 4 { - return "", 0, fmt.Errorf("ssob: Decoding string: %w", ErrTypeInvalid) - } - l := int32(binary.BigEndian.Uint32(in)) - - if len(in[4:]) < int(l) { - return "", 0, fmt.Errorf("ssob: Invalid length of string: %w", ErrValueInvalid) - } - 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, fmt.Errorf("ssob: Decoding bool: %w", ErrTypeInvalid) - } - - 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, fmt.Errorf("ssob: Decoding int8: %w", ErrTypeInvalid) - } - - return int8(in[0]), 1, nil -} - -func UnsafeUnmarshalUint8(in []byte) (ret uint8, n int, err error) { - if len(in) < 1 { - return 0, 0, fmt.Errorf("ssob: Decoding uint8: %w", ErrTypeInvalid) - } - - return uint8(in[0]), 1, nil -} - -func UnsafeUnmarshalInt16(in []byte) (ret int16, n int, err error) { - if len(in) < 2 { - return 0, 0, fmt.Errorf("ssob: Decoding int16: %w", ErrTypeInvalid) - } - - var out int16 - start := unsafe.Pointer(&out) - if littleEndian { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[0] - } else { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1] - } - - return out, 2, nil -} - -func UnsafeUnmarshalUint16(in []byte) (ret uint16, n int, err error) { - if len(in) < 2 { - return 0, 0, fmt.Errorf("ssob: Decoding uint16: %w", ErrTypeInvalid) - } - - var out uint16 - start := unsafe.Pointer(&out) - if littleEndian { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[0] - } else { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1] - } - - return out, 2, nil -} - -func UnsafeUnmarshalInt32(in []byte) (ret int32, n int, err error) { - if len(in) < 4 { - return 0, 0, fmt.Errorf("ssob: Decoding int32: %w", ErrTypeInvalid) - } - - var out int32 - start := unsafe.Pointer(&out) - if littleEndian { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[3] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[2] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[0] - } else { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[2] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[3] - } - - return out, 4, nil -} - -func UnsafeUnmarshalUint32(in []byte) (ret uint32, n int, err error) { - if len(in) < 4 { - return 0, 0, fmt.Errorf("ssob: Decoding uint32: %w", ErrTypeInvalid) - } - - var out uint32 - start := unsafe.Pointer(&out) - if littleEndian { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[3] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[2] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[0] - } else { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[2] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[3] - } - - return out, 4, nil -} - -func UnsafeUnmarshalFloat32(in []byte) (ret float32, n int, err error) { - if len(in) < 4 { - return 0, 0, fmt.Errorf("ssob: Decoding float32: %w", ErrTypeInvalid) - } - - var out float32 - start := unsafe.Pointer(&out) - if littleEndian { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[3] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[2] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[0] - } else { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[2] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[3] - } - - return out, 4, nil -} - -func UnsafeUnmarshalInt64(in []byte) (ret int64, n int, err error) { - if len(in) < 8 { - return 0, 0, fmt.Errorf("ssob: Decoding int64: %w", ErrTypeInvalid) - } - - var out int64 - start := unsafe.Pointer(&out) - if littleEndian { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[7] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[6] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[5] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[4] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) = in[3] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) = in[2] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) = in[0] - } else { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[2] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[3] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) = in[4] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) = in[5] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) = in[6] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) = in[7] - } - - return out, 8, nil -} - -func UnsafeUnmarshalUint64(in []byte) (ret uint64, n int, err error) { - if len(in) < 8 { - return 0, 0, fmt.Errorf("ssob: Decoding uint64: %w", ErrTypeInvalid) - } - - var out uint64 - start := unsafe.Pointer(&out) - if littleEndian { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[7] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[6] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[5] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[4] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) = in[3] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) = in[2] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) = in[0] - } else { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[2] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[3] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) = in[4] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) = in[5] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) = in[6] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) = in[7] - } - - return out, 8, nil -} - -func UnsafeUnmarshalFloat64(in []byte) (ret float64, n int, err error) { - if len(in) < 8 { - return 0, 0, fmt.Errorf("ssob: Decoding float64: %w", ErrTypeInvalid) - } - - var out float64 - start := unsafe.Pointer(&out) - if littleEndian { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[7] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[6] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[5] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[4] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) = in[3] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) = in[2] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) = in[0] - } else { - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[2] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[3] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) = in[4] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) = in[5] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) = in[6] - *(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) = in[7] - } - - return out, 8, nil -} - -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, fmt.Errorf("ssob: Incompatible type - expected bool: %w", ErrTypeMismatch) - }) - RegisterUnsafeDecoder("int8", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*int8); ok { - *i, n, err = UnsafeUnmarshalInt8(in) - return n, nil - } - return 0, fmt.Errorf("ssob: Incompatible type - expected int8: %w", ErrTypeMismatch) - }) - RegisterUnsafeDecoder("uint8", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*uint8); ok { - *i, n, err = UnsafeUnmarshalUint8(in) - return n, nil - } - return 0, fmt.Errorf("ssob: Incompatible type - expected uint8: %w", ErrTypeMismatch) - }) - RegisterUnsafeDecoder("int16", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*int16); ok { - *i, n, err = UnsafeUnmarshalInt16(in) - return n, nil - } - return 0, fmt.Errorf("ssob: Incompatible type - expected int16: %w", ErrTypeMismatch) - }) - RegisterUnsafeDecoder("uint16", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*uint16); ok { - *i, n, err = UnsafeUnmarshalUint16(in) - return n, nil - } - return 0, fmt.Errorf("ssob: Incompatible type - expected uint16: %w", ErrTypeMismatch) - }) - RegisterUnsafeDecoder("int32", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*int32); ok { - *i, n, err = UnsafeUnmarshalInt32(in) - return n, nil - } - return 0, fmt.Errorf("ssob: Incompatible type - expected int32: %w", ErrTypeMismatch) - }) - RegisterUnsafeDecoder("uint32", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*uint32); ok { - *i, n, err = UnsafeUnmarshalUint32(in) - return n, nil - } - return 0, fmt.Errorf("ssob: Incompatible type - expected uint32: %w", ErrTypeMismatch) - }) - RegisterUnsafeDecoder("float32", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*float32); ok { - *i, n, err = UnsafeUnmarshalFloat32(in) - return n, nil - } - return 0, fmt.Errorf("ssob: Incompatible type - expected float32: %w", ErrTypeMismatch) - }) - RegisterUnsafeDecoder("int64", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*int64); ok { - *i, n, err = UnsafeUnmarshalInt64(in) - return n, nil - } - return 0, fmt.Errorf("ssob: Incompatible type - expected int64: %w", ErrTypeMismatch) - }) - RegisterUnsafeDecoder("uint64", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*uint64); ok { - *i, n, err = UnsafeUnmarshalUint64(in) - return n, nil - } - return 0, fmt.Errorf("ssob: Incompatible type - expected uint64: %w", ErrTypeMismatch) - }) - RegisterUnsafeDecoder("float64", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*float64); ok { - *i, n, err = UnsafeUnmarshalFloat64(in) - return n, nil - } - return 0, fmt.Errorf("ssob: Incompatible type - expected float64: %w", ErrTypeMismatch) - }) - RegisterUnsafeDecoder("string", func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*string); ok { - *i, n, err = UnsafeUnmarshalString(in) - return n, nil - } - return 0, fmt.Errorf("ssob: Incompatible type - expected string: %w", ErrTypeMismatch) - }) -} - -func decRegisterUnsafe(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{}, 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, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) - } - - l, r, err := UnsafeUnmarshalInt32(in) - pos += r - if err != nil { - return pos, err - } - - ti := v.Elem() - if int(l) != ti.Len() { - return pos, fmt.Errorf("ssob: Invalid array length. Expected %s got %s: %w", string(l), string(ti.Len()), ErrValueInvalid) - } - 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) - v := reflect.ValueOf(e) - pos := 0 - - if t.Kind() != reflect.Ptr || v.IsNil() { - return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) - } - - l, r, err := UnsafeUnmarshalInt32(in) - pos += r - if err != nil { - return pos, err - } - - ti := v.Elem() - ti.Set(reflect.MakeSlice(reflect.TypeOf(ti.Interface()), 0, ti.Cap())) - 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.Set(reflect.Append(ti, reflect.Indirect(e))) - } - return pos, nil - } - unsafeDecoderCache[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{}, 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, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) - } - - vi := reflect.Indirect(v) - for _, i := range mfields { - ni, err := unsafeUnmarshal(vi.Field(i).Addr().Interface(), in[pos:]) - pos += ni - if err != nil { - return pos, err - } - } - - return pos, nil - } - unsafeDecoderCache[t.Name()] = f - case reflect.Map: - 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, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) - } - - l, r, err := UnsafeUnmarshalInt32(in) - pos += r - if err != nil { - return pos, err - } - - vi := reflect.Indirect(v) - vt := reflect.TypeOf(vi.Interface()) - tk := vt.Key() - tv := vt.Elem() - for i := int32(0); i < l; i++ { - ek := reflect.New(tk) - ev := reflect.New(tv) - r, err := unsafeUnmarshal(ek.Interface(), in[pos:]) - pos += r - if err != nil { - return pos, err - } - r, err = unsafeUnmarshal(ev.Interface(), in[pos:]) - pos += r - if err != nil { - return pos, err - } - vi.SetMapIndex(reflect.Indirect(ek), reflect.Indirect(ev)) - } - - return pos, nil - } - unsafeDecoderCache[string(t.Kind())] = f - case reflect.Bool: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := bool(false) - pos := 0 - - r, err := unsafeUnmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetBool(bool(i)) - - return pos, nil - } - unsafeDecoderCache[t.Name()] = f - case reflect.Uint8: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := uint8(0) - pos := 0 - - r, err := unsafeUnmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetUint(uint64(i)) - - return pos, nil - } - unsafeDecoderCache[t.Name()] = f - case reflect.Uint16: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := uint16(0) - pos := 0 - - r, err := unsafeUnmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetUint(uint64(i)) - - return pos, nil - } - unsafeDecoderCache[t.Name()] = f - case reflect.Uint32: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := uint32(0) - pos := 0 - - r, err := unsafeUnmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetUint(uint64(i)) - - return pos, nil - } - unsafeDecoderCache[t.Name()] = f - case reflect.Uint64: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := uint64(0) - pos := 0 - - r, err := unsafeUnmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetUint(uint64(i)) - - return pos, nil - } - unsafeDecoderCache[t.Name()] = f - case reflect.Int8: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := int8(0) - pos := 0 - - r, err := unsafeUnmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetInt(int64(i)) - - return pos, nil - } - unsafeDecoderCache[t.Name()] = f - case reflect.Int16: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := int16(0) - pos := 0 - - r, err := unsafeUnmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetInt(int64(i)) - - return pos, nil - } - unsafeDecoderCache[t.Name()] = f - case reflect.Int32: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := int32(0) - pos := 0 - - r, err := unsafeUnmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetInt(int64(i)) - - return pos, nil - } - unsafeDecoderCache[t.Name()] = f - case reflect.Int64: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := int64(0) - pos := 0 - - r, err := unsafeUnmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetInt(int64(i)) - - return pos, nil - } - unsafeDecoderCache[t.Name()] = f - case reflect.String: - f := func(e interface{}, in []byte) (n int, err error) { - v := reflect.ValueOf(e) - i := string("") - pos := 0 - - r, err := unsafeUnmarshalBaseType(&i, in[pos:]) - pos += r - if err != nil { - return pos, err - } - v.Elem().SetString(i) - - return pos, nil - } - unsafeDecoderCache[t.Name()] = f - default: - return fmt.Errorf("ssob: %s: %w", string(t.Name()), ErrTypeUnknown) - } - - return nil -} - -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: - return unsafeDecoderCache["uint8"](t, in) - case *int16: - return unsafeDecoderCache["int16"](t, in) - case *uint16: - return unsafeDecoderCache["uint16"](t, in) - case *int32: - return unsafeDecoderCache["int32"](t, in) - case *uint32: - return unsafeDecoderCache["uint32"](t, in) - case *int64: - return unsafeDecoderCache["int64"](t, in) - case *uint64: - return unsafeDecoderCache["uint64"](t, in) - case *float32: - return unsafeDecoderCache["float32"](t, in) - case *float64: - return unsafeDecoderCache["float64"](t, in) - case *string: - return unsafeDecoderCache["string"](t, in) - default: - return 0, fmt.Errorf("ssob: No base type: %w", ErrTypeUnknown) - } -} - -func unsafeUnmarshal(e interface{}, in []byte) (n int, err error) { - n, err = unsafeUnmarshalBaseType(e, in) - if err == nil { - return n, err - } - - var key string - t := reflect.TypeOf(e) - v := reflect.ValueOf(e) - if t.Kind() != reflect.Ptr || v.IsNil() { - return 0, fmt.Errorf("ssob: Need a pointer that is fully allocated for unmarshalling: %w", ErrValueInvalid) - } - - p := reflect.Indirect(v) - if p.Kind() != reflect.Ptr { - switch p.Kind() { - case reflect.Bool, reflect.Int8, reflect.Int16, reflect.Int32, - reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, - reflect.Uint64, reflect.String, reflect.Struct: - key = reflect.TypeOf(p.Interface()).Name() - default: - key = string(p.Kind()) - } - - if f, ok := unsafeDecoderCache[key]; ok { - return f(v.Interface(), in) - } else { - err = decRegisterUnsafe(p.Interface()) - if err != nil { - return 0, err - } - return unsafeUnmarshal(e, in) - } - } - if !p.Elem().IsValid() { - err = allocType(v) - if err != nil { - return 0, err - } - p = reflect.Indirect(v) - } - - return unsafeUnmarshal(p.Interface(), in) -} - -func RegisterUnsafeDecoder(name string, f func(e interface{}, in []byte) (n int, err error)) { - unsafeDecoderCache[name] = f -}