Skip to content

Commit

Permalink
refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
illia-li committed Sep 17, 2024
1 parent d6c8249 commit ced833c
Show file tree
Hide file tree
Showing 7 changed files with 680 additions and 297 deletions.
110 changes: 11 additions & 99 deletions marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"github.com/gocql/gocql/marshal"
"github.com/gocql/gocql/marshal/erro"
"github.com/gocql/gocql/marshal/types/tinyint"
"math"
Expand Down Expand Up @@ -93,14 +94,13 @@ type Unmarshaler interface {
// duration | gocql.Duration |
// duration | string | parsed with time.ParseDuration
func Marshal(info TypeInfo, value interface{}) ([]byte, error) {
if v, ok := value.(marshal.Marshaller); ok {
return v.MarshalCQLv2()
}
if info.Version() < protoVersion1 {
panic("protocol version not set")
}

if _, ok := value.(unsetColumn); ok {
return nil, nil
}

if valueRef := reflect.ValueOf(value); valueRef.Kind() == reflect.Ptr {
if valueRef.IsNil() {
return nil, nil
Expand Down Expand Up @@ -212,6 +212,9 @@ func Unmarshal(info TypeInfo, data []byte, value interface{}) error {
if v, ok := value.(Unmarshaler); ok {
return v.UnmarshalCQL(info, data)
}
if v, ok := value.(marshal.Unmarshaller); ok {
return v.UnmarshalCQLv2(data)
}

if isNullableValue(value) {
return unmarshalNullable(info, data, value)
Expand Down Expand Up @@ -444,90 +447,6 @@ func marshalSmallInt(info TypeInfo, value interface{}) ([]byte, error) {
return nil, marshalErrorf("can not marshal %T into %s", value, info)
}

func marshalTinyInt(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case int8:
return []byte{byte(v)}, nil
case uint8:
return []byte{byte(v)}, nil
case int16:
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case uint16:
if v > math.MaxUint8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case int:
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case int32:
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case int64:
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case uint:
if v > math.MaxUint8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case uint32:
if v > math.MaxUint8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case uint64:
if v > math.MaxUint8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case string:
n, err := strconv.ParseInt(v, 10, 8)
if err != nil {
return nil, marshalErrorf("can not marshal %T into %s: %v", value, info, err)
}
return []byte{byte(n)}, nil
}

if value == nil {
return nil, nil
}

switch rv := reflect.ValueOf(value); rv.Type().Kind() {
case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
v := rv.Int()
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
v := rv.Uint()
if v > math.MaxUint8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case reflect.Ptr:
if rv.IsNil() {
return nil, nil
}
}

return nil, marshalErrorf("can not marshal %T into %s", value, info)
}

func marshalInt(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
Expand Down Expand Up @@ -625,13 +544,6 @@ func decShort(p []byte) int16 {
return int16(p[0])<<8 | int16(p[1])
}

func decTiny(p []byte) int8 {
if len(p) != 1 {
return 0
}
return int8(p[0])
}

func marshalBigInt(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
Expand Down Expand Up @@ -721,10 +633,6 @@ func unmarshalSmallInt(info TypeInfo, data []byte, value interface{}) error {
return unmarshalIntlike(info, int64(decShort(data)), data, value)
}

func unmarshalTinyInt(info TypeInfo, data []byte, value interface{}) error {
return tinyint.Unmarshal(data, value)
}

func unmarshalVarint(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case *big.Int:
Expand Down Expand Up @@ -2744,6 +2652,8 @@ func mutateMarshal(info TypeInfo, value interface{}, f func(interface{}) ([]byte
return nil, nil
case Marshaler:
return v.MarshalCQL(info)
case marshal.Marshaller:
return v.MarshalCQLv2()
default:
data, err := f(value)
if err != nil {
Expand All @@ -2757,6 +2667,8 @@ func mutateUnmarshal(info TypeInfo, data []byte, value interface{}, f func([]byt
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case marshal.Unmarshaller:
return v.UnmarshalCQLv2(data)
default:
if err := f(data, value); err != nil {
return UnmarshalError(err.(erro.Error))
Expand Down
31 changes: 31 additions & 0 deletions marshal/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package marshal

// Marshaller is an interface for marshalling objects according to the CQL binary protocol.
// Initially, each value of the 'CQL binary protocol' consist of <value_len> and <value_data>.
// <value_len> can be 'unset'(-2), 'nil'(-1), 'zero'(0) or any value up to 2147483647.
// In 'unset', 'nil' and 'zero' cases <value_data> is not present.
// Basically, 'unset' is applicable only to columns, but there may be exceptions.
// The current version of 'gocql' writes <value_len> through logic after marshaling functions,
// so you need to tell this logic about these cases:
// 1. In 'unset' case - you need to put gocql.UnsetValue instead of value.
// 2. In 'nil' case - your Marshaller implementation should return []byte==nil.
// 3. In 'zero' case - your Marshaller implementation should return initiated []byte with len==0.
//
// All CQL DB`s have proprietary value coding features, which you need to consider.
// CQL binary protocol info:https://github.com/apache/cassandra/tree/trunk/doc
type Marshaller interface {
MarshalCQLv2() ([]byte, error)
}

// Unmarshaller is an interface for unmarshalling objects according to the CQL binary protocol.
// Initially, each value of the 'CQL binary protocol' consist of <value_len> and <value_data>.
// <value_len> can be 'nil'(-1), 'zero'(0) or any value up to 2147483647.
// In 'nil' and 'zero' cases <value_data> is not present.
// The current version of 'gocql' reads <value_len> through logic before unmarshalling functions,
// so your Unmarshaller implementation will receive:
// in the 'nil' case - []byte==nil,
// in the 'zero' case - initiated []byte with len==0.
// CQL binary protocol info:https://github.com/apache/cassandra/tree/trunk/doc
type Unmarshaller interface {
UnmarshalCQLv2(data []byte) error
}
128 changes: 60 additions & 68 deletions marshal/types/tinyint/marshal.go
Original file line number Diff line number Diff line change
@@ -1,88 +1,80 @@
package tinyint

import (
"math"
"math/big"
"reflect"
"strconv"

"github.com/gocql/gocql/marshal/erro"
"github.com/gocql/gocql/marshal"
)

func Marshal(value interface{}) ([]byte, error) {
switch v := value.(type) {
case nil:
return nil, nil
case marshal.Marshaller:
return v.MarshalCQLv2()

case int8:
return []byte{byte(v)}, nil
case uint8:
return []byte{byte(v)}, nil
case int16:
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, erro.Newf("marshal tinyint: value %#v out of range", v)
}
return []byte{byte(v)}, nil
case uint16:
if v > math.MaxUint8 {
return nil, erro.Newf("marshal tinyint: value %#v out of range", v)
}
return []byte{byte(v)}, nil
case int:
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, erro.Newf("marshal tinyint: value %#v out of range", v)
}
return []byte{byte(v)}, nil
return EncInt8(v)
case int32:
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, erro.Newf("marshal tinyint: value %#v out of range", v)
}
return []byte{byte(v)}, nil
return EncInt32(v)
case int16:
return EncInt16(v)
case int64:
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, erro.Newf("marshal tinyint: value %#v out of range", v)
}
return []byte{byte(v)}, nil
case uint:
if v > math.MaxUint8 {
return nil, erro.Newf("marshal tinyint: value %#v out of range", v)
}
return []byte{byte(v)}, nil
return EncInt64(v)
case int:
return EncInt(v)

case uint8:
return EncUint8(v)
case uint16:
return EncUint16(v)
case uint32:
if v > math.MaxUint8 {
return nil, erro.Newf("marshal tinyint: value %#v out of range", v)
}
return []byte{byte(v)}, nil
return EncUint32(v)
case uint64:
if v > math.MaxUint8 {
return nil, erro.Newf("marshal tinyint: value %#v out of range", v)
}
return []byte{byte(v)}, nil
return EncUint64(v)
case uint:
return EncUint(v)

case big.Int:
return EncBigInt(v)
case string:
n, err := strconv.ParseInt(v, 10, 8)
if err != nil {
return nil, erro.Newf("marshal tinyint: can not marshal %#v %s", value, err)
}
return []byte{byte(n)}, nil
}
return EncString(v)

if value == nil {
return nil, nil
}
case *int8:
return EncInt8R(v)
case *int16:
return EncInt16R(v)
case *int32:
return EncInt32R(v)
case *int64:
return EncInt64R(v)
case *int:
return EncIntR(v)

switch rv := reflect.ValueOf(value); rv.Type().Kind() {
case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
v := rv.Int()
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, erro.Newf("marshal tinyint: value %#v out of range", v)
}
return []byte{byte(v)}, nil
case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
v := rv.Uint()
if v > math.MaxUint8 {
return nil, erro.Newf("marshal tinyint: value %#v out of range", v)
}
return []byte{byte(v)}, nil
case reflect.Ptr:
if rv.IsNil() {
return nil, nil
case *uint8:
return EncUint8R(v)
case *uint16:
return EncUint16R(v)
case *uint32:
return EncUint32R(v)
case *uint64:
return EncUint64R(v)
case *uint:
return EncUintR(v)

case *big.Int:
return EncBigIntR(v)
case *string:
return EncStringR(v)
default:
rv := reflect.TypeOf(value)
if rv.Kind() == reflect.Ptr {
if rv.Elem().Kind() != reflect.Ptr {
return EncReflect(reflect.ValueOf(v))
}
return EncReflectR(reflect.ValueOf(v))
}
return nil, errMarshal.Addf("unsupported value type %#v", value)
}
return nil, erro.Newf("marshal tinyint: can not marshal %#v", value)
}
Loading

0 comments on commit ced833c

Please sign in to comment.