package ssob import ( "encoding/binary" "errors" "math" "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 MarshalBool(in bool) (ret []byte) { if in { return []byte{byte(0)} } return []byte{byte(1)} } 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, math.Float32bits(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, math.Float64bits(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("bool", func(e interface{}) (ret []byte, err error) { if i, ok := e.(bool); ok { return MarshalBool(i), nil } return nil, errors.New("ssob: Incompatible type - expected bool") }) 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) { t := reflect.TypeOf(e) if t == nil { return errors.New("ssob: Invalid type") } 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 := 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.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: zt := reflect.New(t) n := zt.Elem().NumField() mfields := []int{} for i := 0; i < n; i++ { if zt.Elem().Field(i).CanSet() { mfields = append(mfields, i) } } if len(mfields) == 0 { return errors.New("ssob: No exported fields for " + string(t.Name())) } f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) bs := make([][]byte, n) blen := 0 for _, i := range mfields { 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 case reflect.Bool: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) return marshalBaseType(bool(v.Bool())) } encoderCache[t.Name()] = f case reflect.Uint8: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) return marshalBaseType(uint8(v.Uint())) } encoderCache[t.Name()] = f case reflect.Uint16: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) return marshalBaseType(uint16(v.Uint())) } encoderCache[t.Name()] = f case reflect.Uint32: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) return marshalBaseType(uint32(v.Uint())) } encoderCache[t.Name()] = f case reflect.Uint64: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) return marshalBaseType(uint64(v.Uint())) } encoderCache[t.Name()] = f case reflect.Int8: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) return marshalBaseType(int8(v.Uint())) } encoderCache[t.Name()] = f case reflect.Int16: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) return marshalBaseType(int16(v.Uint())) } encoderCache[t.Name()] = f case reflect.Int32: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) return marshalBaseType(int32(v.Uint())) } encoderCache[t.Name()] = f case reflect.Int64: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) return marshalBaseType(int64(v.Uint())) } encoderCache[t.Name()] = f case reflect.String: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) return marshalBaseType(string(v.String())) } encoderCache[t.Name()] = f default: return errors.New("ssob: Unknown type " + string(t.Name())) } return nil } func marshalBaseType(e interface{}) (ret []byte, err error) { switch t := e.(type) { case bool: return encoderCache["bool"](t) 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) switch t.Kind() { case reflect.Ptr: if v.IsNil() { return nil, errors.New("ssob: Cannot marshal nil pointer") } p := reflect.Indirect(v) return marshal(p.Interface()) case reflect.Bool, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.String, reflect.Struct: key = t.Name() default: 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 }