package ssob import ( "encoding/binary" "errors" "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 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) 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) { 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 := 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: 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 = 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 default: return errors.New("ssob: Unknown type " + string(v.Kind())) } 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) 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) } func RegisterEncoder(name string, f MarshalFunc) { encoderCache[name] = f }