package ssob import ( "encoding/binary" "errors" "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 { err = encRegister(e) if err != nil { return nil, err } } return marshal(e) }