diff --git a/decoder.go b/decoder.go index e8eb078..886631e 100644 --- a/decoder.go +++ b/decoder.go @@ -35,13 +35,13 @@ func (dec *Decoder) DecodeValue(value reflect.Value) (err error) { dec.mutex.Lock() defer dec.mutex.Unlock() - lb := make([]byte, 8) + lb := make([]byte, 4) err = binary.Read(dec.r, binary.BigEndian, lb) if err != nil { return err } - l, n, err := UnmarshalInt64(lb) - if err != nil || n != 8 { + l, n, err := UnmarshalInt32(lb) + if err != nil || n != 4 { return err } diff --git a/encoder.go b/encoder.go index 31c0e9d..b0b0b0d 100644 --- a/encoder.go +++ b/encoder.go @@ -32,15 +32,18 @@ func (enc *Encoder) EncodeValue(value reflect.Value) (err error) { return errors.New("ssob: Cannot encode nil of type " + value.Type().String()) } - b, err := marshal(value.Interface()) + bb, err := marshal(value.Interface()) if err != nil { return err } - bb := MarshalInt64(int64(len(b))) - bb = append(bb, b...) + 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, bb) + return binary.Write(enc.w, binary.BigEndian, w) } diff --git a/endianess.go b/endianess.go new file mode 100644 index 0000000..d1ee03b --- /dev/null +++ b/endianess.go @@ -0,0 +1,22 @@ +package ssob + +import ( + "unsafe" +) + +func isLittleEndian() bool { + var i int = 0x0100 + ptr := unsafe.Pointer(&i) + if 0x00 == *(*byte)(ptr) { + return true + } + return false +} + +var sPtr uintptr +var littleEndian bool + +func init() { + sPtr = unsafe.Sizeof(byte(0)) + littleEndian = isLittleEndian() +} diff --git a/marshal.go b/marshal.go index 69602b0..01d7a55 100644 --- a/marshal.go +++ b/marshal.go @@ -3,15 +3,16 @@ package ssob import ( "encoding/binary" "errors" - "fmt" "reflect" ) func MarshalString(in string) (ret []byte) { - l := int64(len(in)) - b := MarshalInt64(l) - b = append(b, []byte(in)...) - return b + 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 MarshalInt8(in int8) (ret []byte) { @@ -84,17 +85,72 @@ var encoderCache map[string]MarshalFunc func init() { encoderCache = make(map[string]MarshalFunc) - encRegister(int8(0)) - encRegister(uint8(0)) - encRegister(int16(0)) - encRegister(uint16(0)) - encRegister(int32(0)) - encRegister(uint32(0)) - encRegister(float32(0)) - encRegister(int64(0)) - encRegister(uint64(0)) - encRegister(float64(0)) - encRegister(string("")) + RegisterEncoder("int8", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(int8); ok { + return MarshalInt8(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected int8") + }) + RegisterEncoder("uint8", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(uint8); ok { + return MarshalUint8(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected uint8") + }) + RegisterEncoder("int16", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(int16); ok { + return MarshalInt16(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected int16") + }) + RegisterEncoder("uint16", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(uint16); ok { + return MarshalUint16(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected uint16") + }) + RegisterEncoder("int32", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(int32); ok { + return MarshalInt32(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected int32") + }) + RegisterEncoder("uint32", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(uint32); ok { + return MarshalUint32(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected uint32") + }) + RegisterEncoder("float32", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(float32); ok { + return MarshalFloat32(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected float32") + }) + RegisterEncoder("int64", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(int64); ok { + return MarshalInt64(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected int64") + }) + RegisterEncoder("uint64", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(uint64); ok { + return MarshalUint64(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected uint64") + }) + RegisterEncoder("float64", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(float64); ok { + return MarshalFloat64(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected float64") + }) + RegisterEncoder("string", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(string); ok { + return MarshalString(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected string") + }) } func encRegister(e interface{}) (err error) { @@ -107,123 +163,68 @@ func encRegister(e interface{}) (err error) { f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) l := v.Len() - ret, err = marshal(int64(l)) - if err != nil { - return nil, err - } + slen := MarshalInt32(int32(l)) + blen := 4 + bs := make([][]byte, l) for i := 0; i < l; i++ { - b, err := marshal(v.Index(i).Interface()) + 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: f := func(e interface{}) (ret []byte, err error) { n := v.NumField() - ret = []byte{} + bs := make([][]byte, n) + blen := 0 for i := 0; i < n; i++ { - b, err := marshal(v.Field(i).Interface()) + bs[i], err = marshal(v.Field(i).Interface()) if err != nil { return nil, err } - ret = append(ret, b...) + 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.Int8: - f := func(e interface{}) (ret []byte, err error) { - if i, ok := e.(int8); ok { - return MarshalInt8(i), nil - } - return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected int8") - } - encoderCache[string(v.Kind())] = f - case reflect.Uint8: - f := func(e interface{}) (ret []byte, err error) { - if i, ok := e.(uint8); ok { - return MarshalUint8(i), nil - } - return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected uint8") - } - encoderCache[string(v.Kind())] = f - case reflect.Int16: - f := func(e interface{}) (ret []byte, err error) { - if i, ok := e.(int16); ok { - return MarshalInt16(i), nil - } - return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected int16") - } - encoderCache[string(v.Kind())] = f - case reflect.Uint16: - f := func(e interface{}) (ret []byte, err error) { - if i, ok := e.(uint16); ok { - return MarshalUint16(i), nil - } - return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected uint16") - } - encoderCache[string(v.Kind())] = f - case reflect.Int32: - f := func(e interface{}) (ret []byte, err error) { - if i, ok := e.(int32); ok { - return MarshalInt32(i), nil - } - return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected int32") - } - encoderCache[string(v.Kind())] = f - case reflect.Uint32: - f := func(e interface{}) (ret []byte, err error) { - if i, ok := e.(uint32); ok { - return MarshalUint32(i), nil - } - return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected uint32") - } - encoderCache[string(v.Kind())] = f - case reflect.Float32: - f := func(e interface{}) (ret []byte, err error) { - if i, ok := e.(float32); ok { - return MarshalFloat32(i), nil - } - return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected float32") - } - encoderCache[string(v.Kind())] = f - case reflect.Int64: - f := func(e interface{}) (ret []byte, err error) { - if i, ok := e.(int64); ok { - return MarshalInt64(i), nil - } - return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected int64") - } - encoderCache[string(v.Kind())] = f - case reflect.Uint64: - f := func(e interface{}) (ret []byte, err error) { - if i, ok := e.(uint64); ok { - return MarshalUint64(i), nil - } - return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected uint64") - } - encoderCache[string(v.Kind())] = f - case reflect.Float64: - f := func(e interface{}) (ret []byte, err error) { - if i, ok := e.(float64); ok { - return MarshalFloat64(i), nil - } - return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected float64") - } - encoderCache[string(v.Kind())] = f - case reflect.String: - f := func(e interface{}) (ret []byte, err error) { - if i, ok := e.(string); ok { - return MarshalString(i), nil - } - return nil, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected string") - } - encoderCache[string(v.Kind())] = f default: return errors.New("ssob: Unknown type " + string(v.Kind())) } @@ -231,7 +232,41 @@ func encRegister(e interface{}) (err error) { return nil } +func marshalBaseType(e interface{}) (ret []byte, err error) { + switch t := e.(type) { + 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, errors.New("ssob: No base type") + } +} + 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) @@ -251,7 +286,6 @@ func marshal(e interface{}) (ret []byte, err error) { if f, ok := encoderCache[key]; ok { return f(e) } else { - fmt.Println("Not found") err = encRegister(e) if err != nil { return nil, err diff --git a/unmarshal.go b/unmarshal.go index 41ebb93..10536f3 100644 --- a/unmarshal.go +++ b/unmarshal.go @@ -3,20 +3,19 @@ package ssob import ( "encoding/binary" "errors" - "fmt" "reflect" ) func UnmarshalString(in []byte) (ret string, n int, err error) { - if len(in) < 8 { + if len(in) < 4 { return "", 0, errors.New("ssob: Invalid input to decode string") } - l := int64(binary.BigEndian.Uint64(in)) + l := int32(binary.BigEndian.Uint32(in)) - if len(in[8:]) < int(l) { + if len(in[4:]) < int(l) { return "", 0, errors.New("ssob: Invalid length of string") } - return string(in[8 : l+8]), int(l) + 8, nil + return string(in[4 : l+4]), int(l) + 4, nil } func UnmarshalInt8(in []byte) (ret int8, n int, err error) { @@ -105,17 +104,83 @@ var decoderCache map[string]unmarshalFunc func init() { decoderCache = make(map[string]unmarshalFunc) - decRegister(int8(0)) - decRegister(uint8(0)) - decRegister(int16(0)) - decRegister(uint16(0)) - decRegister(int32(0)) - decRegister(uint32(0)) - decRegister(float32(0)) - decRegister(int64(0)) - decRegister(uint64(0)) - decRegister(float64(0)) - decRegister(string("")) + RegisterDecoder("int8", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*int8); ok { + *i, n, err = UnmarshalInt8(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected int8") + }) + RegisterDecoder("uint8", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*uint8); ok { + *i, n, err = UnmarshalUint8(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected uint8") + }) + RegisterDecoder("int16", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*int16); ok { + *i, n, err = UnmarshalInt16(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected int16") + }) + RegisterDecoder("uint16", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*uint16); ok { + *i, n, err = UnmarshalUint16(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected uint16") + }) + RegisterDecoder("int32", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*int32); ok { + *i, n, err = UnmarshalInt32(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected int32") + }) + RegisterDecoder("uint32", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*uint32); ok { + *i, n, err = UnmarshalUint32(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected uint32") + }) + RegisterDecoder("float32", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*float32); ok { + *i, n, err = UnmarshalFloat32(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected float32") + }) + RegisterDecoder("int64", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*int64); ok { + *i, n, err = UnmarshalInt64(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected int64") + }) + RegisterDecoder("uint64", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*uint64); ok { + *i, n, err = UnmarshalUint64(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected uint64") + }) + RegisterDecoder("float64", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*float64); ok { + *i, n, err = UnmarshalFloat64(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected float64") + }) + RegisterDecoder("string", func(e interface{}, in []byte) (n int, err error) { + if i, ok := e.(*string); ok { + *i, n, err = UnmarshalString(in) + return n, nil + } + return 0, errors.New("ssob: Incompatible type - expected string") + }) } func decRegister(e interface{}) (err error) { @@ -125,7 +190,35 @@ func decRegister(e interface{}) (err error) { case reflect.Invalid: return errors.New("ssob: Invalid type") case reflect.Slice: - return errors.New("ssob: Unsupported type") + f := func(e interface{}, in []byte) (n int, err error) { + t := reflect.TypeOf(e) + v := reflect.ValueOf(e) + pos := 0 + + if t.Kind() != reflect.Ptr || v.IsNil() { + return 0, errors.New("ssob: Cannot unmarshal to nil pointer") + } + + l, r, err := UnmarshalInt32(in) + pos += r + if err != nil { + return pos, err + } + + ti := v.Elem() + 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: f := func(e interface{}, in []byte) (n int, err error) { t := reflect.TypeOf(e) @@ -149,171 +242,20 @@ func decRegister(e interface{}) (err error) { return pos, nil } decoderCache[t.Name()] = f - case reflect.Int8: - f := func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*int8); ok { - if i == nil { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") - } - *i, n, err = UnmarshalInt8(in) - if err != nil { - return 0, err - } - return n, err - } - return 0, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected *int8") - } - decoderCache[string(v.Kind())] = f - case reflect.Uint8: - f := func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*uint8); ok { - if i == nil { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") - } - *i, n, err = UnmarshalUint8(in) - if err != nil { - return 0, err - } - return n, err - } - return 0, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected *uint8") - } - decoderCache[string(v.Kind())] = f - case reflect.Int16: - f := func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*int16); ok { - if i == nil { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") - } - *i, n, err = UnmarshalInt16(in) - if err != nil { - return 0, err - } - return n, err - } - return 0, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected *int16") - } - decoderCache[string(v.Kind())] = f - case reflect.Uint16: - f := func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*uint16); ok { - if i == nil { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") - } - *i, n, err = UnmarshalUint16(in) - if err != nil { - return 0, err - } - return n, err - } - return 0, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected *uint16") - } - decoderCache[string(v.Kind())] = f - case reflect.Int32: - f := func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*int32); ok { - if i == nil { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") - } - *i, n, err = UnmarshalInt32(in) - if err != nil { - return 0, err - } - return n, err - } - return 0, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected *int32") - } - decoderCache[string(v.Kind())] = f - case reflect.Uint32: - f := func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*uint32); ok { - if i == nil { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") - } - *i, n, err = UnmarshalUint32(in) - if err != nil { - return 0, err - } - return n, err - } - return 0, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected *uint32") - } - decoderCache[string(v.Kind())] = f - case reflect.Float32: - f := func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*float32); ok { - if i == nil { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") - } - *i, n, err = UnmarshalFloat32(in) - if err != nil { - return 0, err - } - return n, err - } - return 0, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected *float32") - } - decoderCache[string(v.Kind())] = f - case reflect.Int64: - f := func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*int64); ok { - if i == nil { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") - } - *i, n, err = UnmarshalInt64(in) - if err != nil { - return 0, err - } - return n, err - } - return 0, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected *int64") - } - decoderCache[string(v.Kind())] = f - case reflect.Uint64: - f := func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*uint64); ok { - if i == nil { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") - } - *i, n, err = UnmarshalUint64(in) - if err != nil { - return 0, err - } - return n, err - } - return 0, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected *uint64") - } - decoderCache[string(v.Kind())] = f - case reflect.Float64: - f := func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*float64); ok { - if i == nil { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") - } - *i, n, err = UnmarshalFloat64(in) - if err != nil { - return 0, err - } - return n, err - } - return 0, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected *float64") - } - decoderCache[string(v.Kind())] = f - case reflect.String: - f := func(e interface{}, in []byte) (n int, err error) { - if i, ok := e.(*string); ok { - if i == nil { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") - } - *i, n, err = UnmarshalString(in) - if err != nil { - return 0, err - } - return n, err - } - return 0, errors.New("ssob: Incompatible type " + string(v.Kind()) + " - expected *string") - } - decoderCache[string(v.Kind())] = f + case reflect.Map: + return errors.New("ssob: Unsupported type") + //f := func(e interface{}, in []byte) (n int, err error) { + //t := reflect.TypeOf(e) + //v := reflect.ValueOf(e) + //pos := 0 + + //if t.Kind() != reflect.Ptr || v.IsNil() { + //return 0, errors.New("ssob: Cannot unmarshal to nil pointer") + //} + + //vi := reflect.Indirect(v) + + //} default: return errors.New("ssob: Unknown type " + string(v.Kind())) } @@ -321,7 +263,41 @@ func decRegister(e interface{}) (err error) { return nil } +func unmarshalBaseType(e interface{}, in []byte) (n int, err error) { + switch t := e.(type) { + 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, errors.New("ssob: No base type") + } +} + 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) @@ -340,7 +316,6 @@ func unmarshal(e interface{}, in []byte) (n int, err error) { if f, ok := decoderCache[key]; ok { return f(v.Interface(), in) } else { - fmt.Println("Not found") err = decRegister(p.Interface()) if err != nil { return 0, err diff --git a/unsafe_encoder.go b/unsafe_encoder.go new file mode 100644 index 0000000..f9ac916 --- /dev/null +++ b/unsafe_encoder.go @@ -0,0 +1,49 @@ +package ssob + +import ( + "encoding/binary" + "errors" + "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 errors.New("ssob: Cannot encode nil value") + } + + if value.Kind() == reflect.Ptr && value.IsNil() { + return errors.New("ssob: Cannot encode nil of type " + value.Type().String()) + } + + 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 new file mode 100644 index 0000000..3782aa1 --- /dev/null +++ b/unsafe_marshal.go @@ -0,0 +1,410 @@ +package ssob + +import ( + "errors" + "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 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("int8", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(int8); ok { + return UnsafeMarshalInt8(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected int8") + }) + RegisterUnsafeEncoder("uint8", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(uint8); ok { + return UnsafeMarshalUint8(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected uint8") + }) + RegisterUnsafeEncoder("int16", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(int16); ok { + return UnsafeMarshalInt16(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected int16") + }) + RegisterUnsafeEncoder("uint16", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(uint16); ok { + return UnsafeMarshalUint16(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected uint16") + }) + RegisterUnsafeEncoder("int32", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(int32); ok { + return UnsafeMarshalInt32(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected int32") + }) + RegisterUnsafeEncoder("uint32", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(uint32); ok { + return UnsafeMarshalUint32(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected uint32") + }) + RegisterUnsafeEncoder("float32", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(float32); ok { + return UnsafeMarshalFloat32(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected float32") + }) + RegisterUnsafeEncoder("int64", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(int64); ok { + return UnsafeMarshalInt64(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected int64") + }) + RegisterUnsafeEncoder("uint64", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(uint64); ok { + return UnsafeMarshalUint64(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected uint64") + }) + RegisterUnsafeEncoder("float64", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(float64); ok { + return UnsafeMarshalFloat64(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected float64") + }) + RegisterUnsafeEncoder("string", func(e interface{}) (ret []byte, err error) { + if i, ok := e.(string); ok { + return UnsafeMarshalString(i), nil + } + return nil, errors.New("ssob: Incompatible type - expected string") + }) +} + +func encRegisterUnsafe(e interface{}) (err error) { + v := reflect.ValueOf(e) + t := reflect.TypeOf(e) + switch t.Kind() { + case reflect.Invalid: + return errors.New("ssob: Invalid type") + 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: + f := func(e interface{}) (ret []byte, err error) { + n := v.NumField() + bs := make([][]byte, n) + blen := 0 + for i := 0; i < n; i++ { + 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 + default: + return errors.New("ssob: Unknown type " + string(v.Kind())) + } + + return nil +} + +func unsafeMarshalBaseType(e interface{}) (ret []byte, err error) { + switch t := e.(type) { + 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, errors.New("ssob: No base type") + } +} + +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) + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return nil, errors.New("ssob: Cannot marshal nil pointer") + } + p := reflect.Indirect(v) + return unsafeMarshal(p.Interface()) + } + if t.Kind() == reflect.Struct { + key = reflect.TypeOf(e).Name() + } else { + 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 +}