package ssob import ( "encoding/binary" "fmt" "math" "reflect" ) func marshalBool(e bool) (ret []byte) { ret = make([]byte, 1) if e == true { ret[0] = 0 } else { ret[0] = 1 } return ret } func marshalUint8(e uint8) (ret []byte) { ret = make([]byte, 1) ret[0] = byte(e) return ret } func marshalUint16(e uint16) (ret []byte) { ret = make([]byte, 2) binary.BigEndian.PutUint16(ret, e) return ret } func marshalUint32(e uint32) (ret []byte) { ret = make([]byte, 4) binary.BigEndian.PutUint32(ret, e) return ret } func marshalUint64(e uint64) (ret []byte) { ret = make([]byte, 8) binary.BigEndian.PutUint64(ret, e) return ret } func marshalInt8(e int8) (ret []byte) { ret = make([]byte, 1) ret[0] = byte(e) return ret } func marshalInt16(e int16) (ret []byte) { ret = make([]byte, 2) binary.BigEndian.PutUint16(ret, uint16(e)) return ret } func marshalInt32(e int32) (ret []byte) { ret = make([]byte, 4) binary.BigEndian.PutUint32(ret, uint32(e)) return ret } func marshalInt64(e int64) (ret []byte) { ret = make([]byte, 8) binary.BigEndian.PutUint64(ret, uint64(e)) return ret } func marshalFloat32(e float32) (ret []byte) { ret = make([]byte, 4) binary.BigEndian.PutUint32(ret, math.Float32bits(e)) return ret } func marshalFloat64(e float64) (ret []byte) { ret = make([]byte, 8) binary.BigEndian.PutUint64(ret, math.Float64bits(e)) return ret } func marshalString(e string) (ret []byte) { slen := len(e) ret = make([]byte, slen+4) binary.BigEndian.PutUint32(ret, uint32(slen)) copy(ret[4:], []byte(e)) return ret } func marshalNil(e uint16) (ret []byte) { return marshalUint16(e) } func marshalPtrIfNil(e interface{}, ntype *NType) (ie interface{}, ret []byte, isNil bool, err error) { if ntype.Indirection == 0 { return e, nil, false, err } nl := uint16(0) v := reflect.ValueOf(e) if valueIsNil(v) { ret = append(ret, marshalTypeId(ST_NIL)...) ret = append(ret, marshalNil(nl)...) return e, ret, true, err } for i := 0; i < ntype.Indirection; i++ { if v, err = indirectValue(v); err != nil { return e, ret, false, err } if valueIsNil(v) { ret = append(ret, marshalTypeId(ST_NIL)...) ret = append(ret, marshalNil(uint16(nl))...) return e, ret, true, err } nl++ } ret = append(ret, marshalTypeId(ntype.ValType)...) return v.Interface(), ret, false, err } func marshalError(e interface{}, ntype *NType) (ret []byte, err error) { nl := uint16(0) v := reflect.ValueOf(e) if valueIsNil(v) { ret = append(ret, marshalTypeId(ST_NIL)...) ret = append(ret, marshalNil(nl)...) return ret, err } errorString := false for i := 0; i < ntype.Indirection; i++ { t := reflect.TypeOf(v.Interface()) // TODO: Dirty!? Better way? if t.String() == "errors.errorString" { errorString = true break } if v, err = indirectValue(v); err != nil { return ret, err } if valueIsNil(v) { ret = append(ret, marshalTypeId(ST_NIL)...) ret = append(ret, marshalNil(uint16(nl))...) return ret, err } nl++ } if errorString { ret = append(ret, marshalTypeId(ST_STRING)...) ret = append(ret, marshalString(fmt.Sprintf("%v", v.Interface()))...) return ret, err } ierr, ok := v.Interface().(error) if !ok { return ret, ErrValueInvalid } ret = append(ret, marshalTypeId(ST_STRING)...) ret = append(ret, marshalString(ierr.Error())...) return ret, err } func marshalTypeId(e uint32) (ret []byte) { return marshalUint32(e) } func marshalCommon(e interface{}, ntype *NType) (ret []byte, err error) { ctype := getTypeById(ntype.ValType) if ctype == nil { return ret, ErrTypeUnknown } // pointer could be nil e, ptrNil, isNil, err := marshalPtrIfNil(e, ntype) if err != nil { return ptrNil, err } if ptrNil != nil { if isNil { return ptrNil, err } ret = append(ret, ptrNil...) } switch ctype.Id { case ST_BOOL: if ie, ok := e.(bool); !ok { return ret, ErrTypeInvalid } else { ret = append(ret, marshalBool(ie)...) return ret, err } case ST_UINT8: if ie, ok := e.(uint8); !ok { return ret, ErrTypeInvalid } else { ret = append(ret, marshalUint8(ie)...) return ret, err } case ST_UINT16: if ie, ok := e.(uint16); !ok { return ret, ErrTypeInvalid } else { ret = append(ret, marshalUint16(ie)...) return ret, err } case ST_UINT32: if ie, ok := e.(uint32); !ok { return ret, ErrTypeInvalid } else { ret = append(ret, marshalUint32(ie)...) return ret, err } case ST_UINT64: if ie, ok := e.(uint64); !ok { return ret, ErrTypeInvalid } else { ret = append(ret, marshalUint64(ie)...) return ret, err } case ST_INT8: if ie, ok := e.(int8); !ok { return ret, ErrTypeInvalid } else { ret = append(ret, marshalInt8(ie)...) return ret, err } case ST_INT16: if ie, ok := e.(int16); !ok { return ret, ErrTypeInvalid } else { ret = append(ret, marshalInt16(ie)...) return ret, err } case ST_INT32: if ie, ok := e.(int32); !ok { return ret, ErrTypeInvalid } else { ret = append(ret, marshalInt32(ie)...) return ret, err } case ST_INT64: if ie, ok := e.(int64); !ok { return ret, ErrTypeInvalid } else { ret = append(ret, marshalInt64(ie)...) return ret, err } case ST_FLOAT32: if ie, ok := e.(float32); !ok { return ret, ErrTypeInvalid } else { ret = append(ret, marshalFloat32(ie)...) return ret, err } case ST_FLOAT64: if ie, ok := e.(float64); !ok { return ret, ErrTypeInvalid } else { ret = append(ret, marshalFloat64(ie)...) return ret, err } case ST_STRING: if ie, ok := e.(string); !ok { return ret, ErrTypeInvalid } else { ret = append(ret, marshalString(ie)...) return ret, err } case ST_ERROR: return marshalError(e, ntype) default: return ret, ErrTypeUnknown } } func marshalSlice(e interface{}, ntype *NType) (ret []byte, err error) { v := reflect.ValueOf(e) if !v.IsValid() || v.Kind() != reflect.Slice { return ret, ErrValueInvalid } stype := getTypeById(ntype.ValType) if stype == nil { return ret, ErrTypeUnknown } l := v.Len() ret = append(ret, marshalUint32(uint32(l))...) for i := 0; i < l; i++ { tbytes, err := marshalType(v.Index(i).Interface(), stype) if err != nil { return ret, err } ret = append(ret, tbytes...) } return ret, err } func marshalArray(e interface{}, ntype *NType) (ret []byte, err error) { v := reflect.ValueOf(e) if !v.IsValid() || v.Kind() != reflect.Array { return ret, ErrValueInvalid } stype := getTypeById(ntype.ValType) if stype == nil { return ret, ErrTypeUnknown } for i := 0; i < ntype.arrayLen; i++ { tbytes, err := marshalType(v.Index(i).Interface(), stype) if err != nil { return ret, err } ret = append(ret, tbytes...) } return ret, err } func marshalStruct(e interface{}, ntype *NType) (ret []byte, err error) { v := reflect.ValueOf(e) if !v.IsValid() || v.Kind() != reflect.Struct { return ret, ErrValueInvalid } stype := getTypeById(ntype.ValType) if stype == nil { return ret, ErrTypeUnknown } for i, field := range stype.structFields { ftype := getTypeById(field.Id) if ftype == nil { return ret, ErrTypeUnknown } tbytes, err := marshalType(v.Field(i).Interface(), ftype) if err != nil { return ret, err } ret = append(ret, tbytes...) } return ret, err } func marshalInterface(e interface{}, ntype *NType) (ret []byte, err error) { return marshalVal(e) } func marshalType(e interface{}, ntype *NType) (ret []byte, err error) { switch ntype.MainTypeId { case ST_COMMON: return marshalCommon(e, ntype) case ST_SLICE: return marshalSlice(e, ntype) case ST_ARRAY: return marshalArray(e, ntype) case ST_STRUCT: return marshalStruct(e, ntype) case ST_INTERFACE: return marshalInterface(e, ntype) default: return ret, ErrTypeUnknown } } func marshalVal(e interface{}) (ret []byte, err error) { if err = RegisterType(e); err != nil { return ret, err } i, n, nl, err := indirectType(e) if err != nil { return ret, ErrValueInvalid } // type id ret = marshalTypeId(n.Id) // nil pointer if i == nil { ret = append(ret, marshalBool(true)...) ret = append(ret, marshalNil(nl)...) } else { ret = append(ret, marshalBool(false)...) if tbytes, err := marshalType(i, n); err != nil { return ret, err } else { ret = append(ret, tbytes...) } } return ret, err }