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 } 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, uint32(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, uint64(in)) return out } type MarshalFunc func(e interface{}) (ret []byte, err error) 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("")) } func encRegister(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() ret, err = marshal(int64(l)) if err != nil { return nil, err } for i := 0; i < l; i++ { b, err := marshal(v.Index(i).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{} for i := 0; i < n; i++ { b, err := marshal(v.Field(i).Interface()) if err != nil { return nil, err } ret = append(ret, b...) } 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())) } return nil } func marshal(e interface{}) (ret []byte, err error) { 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 marshal(p.Interface()) } if t.Kind() == reflect.Struct { key = reflect.TypeOf(e).Name() } else { key = string(t.Kind()) } if f, ok := encoderCache[key]; ok { return f(e) } else { fmt.Println("Not found") err = encRegister(e) if err != nil { return nil, err } } return marshal(e) } func RegisterEncoder(name string, f MarshalFunc) { encoderCache[name] = f }