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 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, errors.New("ssob: Incompatible type - expected bool") }) RegisterUnsafeEncoder("int8", func(e interface{}) (ret []byte, err error) { if i, ok := e.(int8); ok { return UnsafeMarshalInt8(i), nil } 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.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: 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 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, 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 }