From 9e378909a8abcaaa7298ba44745150393896d424 Mon Sep 17 00:00:00 2001 From: illia-li Date: Thu, 5 Dec 2024 13:07:00 -0400 Subject: [PATCH 1/4] fix `serialization`, makes the equaling of `inf.Dec` faster --- internal/tests/serialization/utils_equal.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/tests/serialization/utils_equal.go b/internal/tests/serialization/utils_equal.go index 9acf5035a..2561b3598 100644 --- a/internal/tests/serialization/utils_equal.go +++ b/internal/tests/serialization/utils_equal.go @@ -60,10 +60,16 @@ func equalVals(in1, in2 interface{}) bool { return vin1.Cmp(vin2) == 0 case inf.Dec: vin2 := in2.(inf.Dec) - return vin1.Cmp(&vin2) == 0 + if vin1.Scale() != vin2.Scale() { + return false + } + return vin1.UnscaledBig().Cmp(vin2.UnscaledBig()) == 0 case *inf.Dec: vin2 := in2.(*inf.Dec) - return vin1.Cmp(vin2) == 0 + if vin1.Scale() != vin2.Scale() { + return false + } + return vin1.UnscaledBig().Cmp(vin2.UnscaledBig()) == 0 case fmt.Stringer: vin2 := in2.(fmt.Stringer) return vin1.String() == vin2.String() From 7493086871ab92fc67630248b32f3c78e38ce9a2 Mon Sep 17 00:00:00 2001 From: illia-li Date: Thu, 5 Dec 2024 13:16:46 -0400 Subject: [PATCH 2/4] fix `varint`, makes `encInt64` function exportable --- serialization/varint/marshal_bigint_test.go | 4 ++-- serialization/varint/marshal_custom.go | 4 ++-- serialization/varint/marshal_ints.go | 6 +++--- serialization/varint/marshal_utils.go | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/serialization/varint/marshal_bigint_test.go b/serialization/varint/marshal_bigint_test.go index a89c0891a..bc15c1bea 100644 --- a/serialization/varint/marshal_bigint_test.go +++ b/serialization/varint/marshal_bigint_test.go @@ -47,7 +47,7 @@ func TestEnc2BigInt(t *testing.T) { t.Fatalf("%d\nexpected:%x\nreceived:%x", i, expected, received) } - received = encInt64(i) + received = EncInt64Ext(i) if !bytes.Equal(expected, received) { t.Fatalf("%d\nexpected:%x\nreceived:%x", i, expected, received) } @@ -64,7 +64,7 @@ func TestEnc2BigInt(t *testing.T) { t.Fatalf("%d\nexpected:%x\nreceived:%x", i, expected, received) } - received = encInt64(i) + received = EncInt64Ext(i) if !bytes.Equal(expected, received) { t.Fatalf("%d\nexpected:%x\nreceived:%x", i, expected, received) } diff --git a/serialization/varint/marshal_custom.go b/serialization/varint/marshal_custom.go index 62d58b319..bb852840f 100644 --- a/serialization/varint/marshal_custom.go +++ b/serialization/varint/marshal_custom.go @@ -55,11 +55,11 @@ func encReflectString(v reflect.Value) ([]byte, error) { if err != nil { return nil, fmt.Errorf("failed to marshal varint: can not marshal (%T)(%[1]v), %s", v.Interface(), err) } - return encInt64(n), nil + return EncInt64Ext(n), nil case len(val) <= 20: n, err := strconv.ParseInt(val, 10, 64) if err == nil { - return encInt64(n), nil + return EncInt64Ext(n), nil } t, ok := new(big.Int).SetString(val, 10) diff --git a/serialization/varint/marshal_ints.go b/serialization/varint/marshal_ints.go index c6cb354ad..e13bf7754 100644 --- a/serialization/varint/marshal_ints.go +++ b/serialization/varint/marshal_ints.go @@ -34,14 +34,14 @@ func EncInt32R(v *int32) ([]byte, error) { } func EncInt64(v int64) ([]byte, error) { - return encInt64(v), nil + return EncInt64Ext(v), nil } func EncInt64R(v *int64) ([]byte, error) { if v == nil { return nil, nil } - return encInt64(*v), nil + return EncInt64Ext(*v), nil } func EncInt(v int) ([]byte, error) { @@ -79,7 +79,7 @@ func encInt32(v int32) []byte { return []byte{byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)} } -func encInt64(v int64) []byte { +func EncInt64Ext(v int64) []byte { if v <= maxInt8 && v >= minInt8 { return []byte{byte(v)} } diff --git a/serialization/varint/marshal_utils.go b/serialization/varint/marshal_utils.go index 2769b3056..b21827f9a 100644 --- a/serialization/varint/marshal_utils.go +++ b/serialization/varint/marshal_utils.go @@ -46,11 +46,11 @@ func EncString(v string) ([]byte, error) { if err != nil { return nil, fmt.Errorf("failed to marshal varint: can not marshal %#v, %s", v, err) } - return encInt64(n), nil + return EncInt64Ext(n), nil case len(v) <= 20: n, err := strconv.ParseInt(v, 10, 64) if err == nil { - return encInt64(n), nil + return EncInt64Ext(n), nil } t, ok := new(big.Int).SetString(v, 10) From 5a6a0fc0e31ee6c7bd1300f86982b3eaddf2a1c7 Mon Sep 17 00:00:00 2001 From: illia-li Date: Fri, 18 Oct 2024 14:50:21 -0400 Subject: [PATCH 3/4] fix `decimal` marshal, unmarshal functions --- marshal.go | 49 +--- serialization/decimal/marshal.go | 29 ++ serialization/decimal/marshal_utils.go | 141 ++++++++++ serialization/decimal/unmarshal.go | 34 +++ serialization/decimal/unmarshal_ints.go | 80 ++++++ serialization/decimal/unmarshal_utils.go | 323 +++++++++++++++++++++++ 6 files changed, 619 insertions(+), 37 deletions(-) create mode 100644 serialization/decimal/marshal.go create mode 100644 serialization/decimal/marshal_utils.go create mode 100644 serialization/decimal/unmarshal.go create mode 100644 serialization/decimal/unmarshal_ints.go create mode 100644 serialization/decimal/unmarshal_utils.go diff --git a/marshal.go b/marshal.go index ac8a30b9c..1b21251fb 100644 --- a/marshal.go +++ b/marshal.go @@ -9,7 +9,6 @@ import ( "encoding/binary" "errors" "fmt" - "gopkg.in/inf.v0" "math" "math/big" "math/bits" @@ -23,6 +22,7 @@ import ( "github.com/gocql/gocql/serialization/blob" "github.com/gocql/gocql/serialization/counter" "github.com/gocql/gocql/serialization/cqlint" + "github.com/gocql/gocql/serialization/decimal" "github.com/gocql/gocql/serialization/double" "github.com/gocql/gocql/serialization/float" "github.com/gocql/gocql/serialization/inet" @@ -168,7 +168,7 @@ func Marshal(info TypeInfo, value interface{}) ([]byte, error) { case TypeDouble: return marshalDouble(value) case TypeDecimal: - return marshalDecimal(info, value) + return marshalDecimal(value) case TypeTime: return marshalTime(info, value) case TypeTimestamp: @@ -282,7 +282,7 @@ func Unmarshal(info TypeInfo, data []byte, value interface{}) error { case TypeDouble: return unmarshalDouble(data, value) case TypeDecimal: - return unmarshalDecimal(info, data, value) + return unmarshalDecimal(data, value) case TypeTime: return unmarshalTime(info, data, value) case TypeTimestamp: @@ -611,44 +611,19 @@ func unmarshalDouble(data []byte, value interface{}) error { return nil } -func marshalDecimal(info TypeInfo, value interface{}) ([]byte, error) { - if value == nil { - return nil, nil - } - - switch v := value.(type) { - case Marshaler: - return v.MarshalCQL(info) - case unsetColumn: - return nil, nil - case inf.Dec: - unscaled := encBigInt2C(v.UnscaledBig()) - if unscaled == nil { - return nil, marshalErrorf("can not marshal %T into %s", value, info) - } - - buf := make([]byte, 4+len(unscaled)) - copy(buf[0:4], encInt(int32(v.Scale()))) - copy(buf[4:], unscaled) - return buf, nil +func marshalDecimal(value interface{}) ([]byte, error) { + data, err := decimal.Marshal(value) + if err != nil { + return nil, wrapMarshalError(err, "marshal error") } - return nil, marshalErrorf("can not marshal %T into %s", value, info) + return data, nil } -func unmarshalDecimal(info TypeInfo, data []byte, value interface{}) error { - switch v := value.(type) { - case Unmarshaler: - return v.UnmarshalCQL(info, data) - case *inf.Dec: - if len(data) < 4 { - return unmarshalErrorf("inf.Dec needs at least 4 bytes, while value has only %d", len(data)) - } - scale := decInt(data[0:4]) - unscaled := decBigInt2C(data[4:], nil) - *v = *inf.NewDecBig(unscaled, inf.Scale(scale)) - return nil +func unmarshalDecimal(data []byte, value interface{}) error { + if err := decimal.Unmarshal(data, value); err != nil { + return wrapUnmarshalError(err, "unmarshal error") } - return unmarshalErrorf("can not unmarshal %s into %T", info, value) + return nil } // decBigInt2C sets the value of n to the big-endian two's complement diff --git a/serialization/decimal/marshal.go b/serialization/decimal/marshal.go new file mode 100644 index 000000000..dbf95a249 --- /dev/null +++ b/serialization/decimal/marshal.go @@ -0,0 +1,29 @@ +package decimal + +import ( + "gopkg.in/inf.v0" + "reflect" +) + +func Marshal(value interface{}) ([]byte, error) { + switch v := value.(type) { + case nil: + return nil, nil + case inf.Dec: + return EncInfDec(v) + case *inf.Dec: + return EncInfDecR(v) + case string: + return EncString(v) + case *string: + return EncStringR(v) + default: + // Custom types (type MyString string) can be serialized only via `reflect` package. + // Later, when generic-based serialization is introduced we can do that via generics. + rv := reflect.TypeOf(value) + if rv.Kind() != reflect.Ptr { + return EncReflect(reflect.ValueOf(v)) + } + return EncReflectR(reflect.ValueOf(v)) + } +} diff --git a/serialization/decimal/marshal_utils.go b/serialization/decimal/marshal_utils.go new file mode 100644 index 000000000..6384af79f --- /dev/null +++ b/serialization/decimal/marshal_utils.go @@ -0,0 +1,141 @@ +package decimal + +import ( + "fmt" + "gopkg.in/inf.v0" + "math/big" + "reflect" + "strconv" + "strings" + + "github.com/gocql/gocql/serialization/varint" +) + +func EncInfDec(v inf.Dec) ([]byte, error) { + sign := v.Sign() + if sign == 0 { + return []byte{0, 0, 0, 0, 0}, nil + } + return append(encScale(v.Scale()), varint.EncBigIntRS(v.UnscaledBig())...), nil +} + +func EncInfDecR(v *inf.Dec) ([]byte, error) { + if v == nil { + return nil, nil + } + return encInfDecR(v), nil +} + +// EncString encodes decimal string which should contains `scale` and `unscaled` strings separated by `;`. +func EncString(v string) ([]byte, error) { + if v == "" { + return nil, nil + } + vs := strings.Split(v, ";") + if len(vs) != 2 { + return nil, fmt.Errorf("failed to marshal decimal: invalid decimal string %s", v) + } + scale, err := strconv.ParseInt(vs[0], 10, 32) + if err != nil { + return nil, fmt.Errorf("failed to marshal decimal: invalid decimal scale string %s", vs[0]) + } + unscaleData, err := encUnscaledString(vs[1]) + if err != nil { + return nil, err + } + return append(encScale64(scale), unscaleData...), nil +} + +func EncStringR(v *string) ([]byte, error) { + if v == nil { + return nil, nil + } + return EncString(*v) +} + +func EncReflect(v reflect.Value) ([]byte, error) { + switch v.Type().Kind() { + case reflect.String: + return encReflectString(v) + case reflect.Struct: + if v.Type().String() == "gocql.unsetColumn" { + return nil, nil + } + return nil, fmt.Errorf("failed to marshal decimal: unsupported value type (%T)(%[1]v)", v.Interface()) + default: + return nil, fmt.Errorf("failed to marshal decimal: unsupported value type (%T)(%[1]v)", v.Interface()) + } +} + +func EncReflectR(v reflect.Value) ([]byte, error) { + if v.IsNil() { + return nil, nil + } + return EncReflect(v.Elem()) +} + +func encReflectString(v reflect.Value) ([]byte, error) { + val := v.String() + if val == "" { + return nil, nil + } + vs := strings.Split(val, ";") + if len(vs) != 2 { + return nil, fmt.Errorf("failed to marshal decimal: invalid decimal string (%T)(%[1]v)", v.Interface()) + } + scale, err := strconv.ParseInt(vs[0], 10, 32) + if err != nil { + return nil, fmt.Errorf("failed to marshal decimal: invalid decimal scale string (%T)(%s)", v.Interface(), vs[0]) + } + unscaledData, err := encUnscaledString(vs[1]) + if err != nil { + return nil, err + } + return append(encScale64(scale), unscaledData...), nil +} + +func encInfDecR(v *inf.Dec) []byte { + sign := v.Sign() + if sign == 0 { + return []byte{0, 0, 0, 0, 0} + } + return append(encScale(v.Scale()), varint.EncBigIntRS(v.UnscaledBig())...) +} + +func encScale(v inf.Scale) []byte { + return []byte{byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)} +} + +func encScale64(v int64) []byte { + return []byte{byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)} +} + +func encUnscaledString(v string) ([]byte, error) { + switch { + case len(v) == 0: + return nil, nil + case len(v) <= 18: + n, err := strconv.ParseInt(v, 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to marshal decimal: invalid unscaled string %s, %s", v, err) + } + return varint.EncInt64Ext(n), nil + case len(v) <= 20: + n, err := strconv.ParseInt(v, 10, 64) + if err == nil { + return varint.EncInt64Ext(n), nil + } + + t, ok := new(big.Int).SetString(v, 10) + if !ok { + return nil, fmt.Errorf("failed to marshal decimal: invalid unscaled string %s", v) + } + return varint.EncBigIntRS(t), nil + default: + t, ok := new(big.Int).SetString(v, 10) + if !ok { + return nil, fmt.Errorf("failed to marshal decimal: invalid unscaled string %s", v) + } + return varint.EncBigIntRS(t), nil + } +} diff --git a/serialization/decimal/unmarshal.go b/serialization/decimal/unmarshal.go new file mode 100644 index 000000000..6433f0dd2 --- /dev/null +++ b/serialization/decimal/unmarshal.go @@ -0,0 +1,34 @@ +package decimal + +import ( + "fmt" + "gopkg.in/inf.v0" + "reflect" +) + +func Unmarshal(data []byte, value interface{}) error { + switch v := value.(type) { + case nil: + return nil + case *inf.Dec: + return DecInfDec(data, v) + case **inf.Dec: + return DecInfDecR(data, v) + case *string: + return DecString(data, v) + case **string: + return DecStringR(data, v) + default: + // Custom types (type MyString string) can be deserialized only via `reflect` package. + // Later, when generic-based serialization is introduced we can do that via generics. + rv := reflect.ValueOf(value) + rt := rv.Type() + if rt.Kind() != reflect.Ptr { + return fmt.Errorf("failed to unmarshal decimal: unsupported value type (%T)(%#[1]v)", value) + } + if rt.Elem().Kind() != reflect.Ptr { + return DecReflect(data, rv) + } + return DecReflectR(data, rv) + } +} diff --git a/serialization/decimal/unmarshal_ints.go b/serialization/decimal/unmarshal_ints.go new file mode 100644 index 000000000..f21910047 --- /dev/null +++ b/serialization/decimal/unmarshal_ints.go @@ -0,0 +1,80 @@ +package decimal + +import ( + "gopkg.in/inf.v0" +) + +const ( + neg8 = int64(-1) << 8 + neg16 = int64(-1) << 16 + neg24 = int64(-1) << 24 + neg32 = int64(-1) << 32 + neg40 = int64(-1) << 40 + neg48 = int64(-1) << 48 + neg56 = int64(-1) << 56 + neg32Int = int(-1) << 32 +) + +func decScale(p []byte) inf.Scale { + return inf.Scale(p[0])<<24 | inf.Scale(p[1])<<16 | inf.Scale(p[2])<<8 | inf.Scale(p[3]) +} + +func decScaleInt64(p []byte) int64 { + if p[0] > 127 { + return neg32 | int64(p[0])<<24 | int64(p[1])<<16 | int64(p[2])<<8 | int64(p[3]) + } + return int64(p[0])<<24 | int64(p[1])<<16 | int64(p[2])<<8 | int64(p[3]) +} + +func dec1toInt64(p []byte) int64 { + if p[4] > 127 { + return neg8 | int64(p[4]) + } + return int64(p[4]) +} + +func dec2toInt64(p []byte) int64 { + if p[4] > 127 { + return neg16 | int64(p[4])<<8 | int64(p[5]) + } + return int64(p[4])<<8 | int64(p[5]) +} + +func dec3toInt64(p []byte) int64 { + if p[4] > 127 { + return neg24 | int64(p[4])<<16 | int64(p[5])<<8 | int64(p[6]) + } + return int64(p[4])<<16 | int64(p[5])<<8 | int64(p[6]) +} + +func dec4toInt64(p []byte) int64 { + if p[4] > 127 { + return neg32 | int64(p[4])<<24 | int64(p[5])<<16 | int64(p[6])<<8 | int64(p[7]) + } + return int64(p[4])<<24 | int64(p[5])<<16 | int64(p[6])<<8 | int64(p[7]) +} + +func dec5toInt64(p []byte) int64 { + if p[4] > 127 { + return neg40 | int64(p[4])<<32 | int64(p[5])<<24 | int64(p[6])<<16 | int64(p[7])<<8 | int64(p[8]) + } + return int64(p[4])<<32 | int64(p[5])<<24 | int64(p[6])<<16 | int64(p[7])<<8 | int64(p[8]) +} + +func dec6toInt64(p []byte) int64 { + if p[4] > 127 { + return neg48 | int64(p[4])<<40 | int64(p[5])<<32 | int64(p[6])<<24 | int64(p[7])<<16 | int64(p[8])<<8 | int64(p[9]) + } + return int64(p[4])<<40 | int64(p[5])<<32 | int64(p[6])<<24 | int64(p[7])<<16 | int64(p[8])<<8 | int64(p[9]) +} + +func dec7toInt64(p []byte) int64 { + if p[4] > 127 { + return neg56 | int64(p[4])<<48 | int64(p[5])<<40 | int64(p[6])<<32 | int64(p[7])<<24 | int64(p[8])<<16 | int64(p[9])<<8 | int64(p[10]) + } + return int64(p[4])<<48 | int64(p[5])<<40 | int64(p[6])<<32 | int64(p[7])<<24 | int64(p[8])<<16 | int64(p[9])<<8 | int64(p[10]) +} + +func dec8toInt64(p []byte) int64 { + return int64(p[4])<<56 | int64(p[5])<<48 | int64(p[6])<<40 | int64(p[7])<<32 | int64(p[8])<<24 | int64(p[9])<<16 | int64(p[10])<<8 | int64(p[11]) +} diff --git a/serialization/decimal/unmarshal_utils.go b/serialization/decimal/unmarshal_utils.go new file mode 100644 index 000000000..557f6cec3 --- /dev/null +++ b/serialization/decimal/unmarshal_utils.go @@ -0,0 +1,323 @@ +package decimal + +import ( + "fmt" + "gopkg.in/inf.v0" + "reflect" + "strconv" + + "github.com/gocql/gocql/serialization/varint" +) + +var errWrongDataLen = fmt.Errorf("failed to unmarshal decimal: the length of the data should be 0 or more than 5") + +func errBrokenData(p []byte) error { + if p[4] == 0 && p[5] <= 127 || p[4] == 255 && p[5] > 127 { + return fmt.Errorf("failed to unmarshal decimal: the data is broken") + } + return nil +} + +func errNilReference(v interface{}) error { + return fmt.Errorf("failed to unmarshal decimal: can not unmarshal into nil reference(%T)(%[1]v)", v) +} + +func DecInfDec(p []byte, v *inf.Dec) error { + if v == nil { + return errNilReference(v) + } + switch len(p) { + case 0: + v.SetScale(0).SetUnscaled(0) + return nil + case 1, 2, 3, 4: + return errWrongDataLen + case 5: + v.SetScale(decScale(p)).SetUnscaled(dec1toInt64(p)) + return nil + case 6: + v.SetScale(decScale(p)).SetUnscaled(dec2toInt64(p)) + case 7: + v.SetScale(decScale(p)).SetUnscaled(dec3toInt64(p)) + case 8: + v.SetScale(decScale(p)).SetUnscaled(dec4toInt64(p)) + case 9: + v.SetScale(decScale(p)).SetUnscaled(dec5toInt64(p)) + case 10: + v.SetScale(decScale(p)).SetUnscaled(dec6toInt64(p)) + case 11: + v.SetScale(decScale(p)).SetUnscaled(dec7toInt64(p)) + case 12: + v.SetScale(decScale(p)).SetUnscaled(dec8toInt64(p)) + default: + v.SetScale(decScale(p)).SetUnscaledBig(varint.Dec2BigInt(p[4:])) + } + return errBrokenData(p) +} + +func DecInfDecR(p []byte, v **inf.Dec) error { + if v == nil { + return errNilReference(v) + } + switch len(p) { + case 0: + if p == nil { + *v = nil + } else { + *v = inf.NewDec(0, 0) + } + return nil + case 1, 2, 3, 4: + return errWrongDataLen + case 5: + *v = inf.NewDec(dec1toInt64(p), decScale(p)) + return nil + case 6: + *v = inf.NewDec(dec2toInt64(p), decScale(p)) + case 7: + *v = inf.NewDec(dec3toInt64(p), decScale(p)) + case 8: + *v = inf.NewDec(dec4toInt64(p), decScale(p)) + case 9: + *v = inf.NewDec(dec5toInt64(p), decScale(p)) + case 10: + *v = inf.NewDec(dec6toInt64(p), decScale(p)) + case 11: + *v = inf.NewDec(dec7toInt64(p), decScale(p)) + case 12: + *v = inf.NewDec(dec8toInt64(p), decScale(p)) + default: + *v = inf.NewDecBig(varint.Dec2BigInt(p[4:]), decScale(p)) + } + return errBrokenData(p) +} + +func DecString(p []byte, v *string) error { + if v == nil { + return errNilReference(v) + } + switch len(p) { + case 0: + if p == nil { + *v = "" + } else { + *v = "0;0" + } + return nil + case 1, 2, 3, 4: + return errWrongDataLen + case 5: + *v = decString5(p) + return nil + case 6: + *v = decString6(p) + case 7: + *v = decString7(p) + case 8: + *v = decString8(p) + case 9: + *v = decString9(p) + case 10: + *v = decString10(p) + case 11: + *v = decString11(p) + case 12: + *v = decString12(p) + default: + *v = decString(p) + } + return errBrokenData(p) +} + +func DecStringR(p []byte, v **string) error { + if v == nil { + return errNilReference(v) + } + switch len(p) { + case 0: + if p == nil { + *v = nil + } else { + tmp := "0;0" + *v = &tmp + } + return nil + case 1, 2, 3, 4: + return errWrongDataLen + case 5: + tmp := decString5(p) + *v = &tmp + return nil + case 6: + tmp := decString6(p) + *v = &tmp + case 7: + tmp := decString7(p) + *v = &tmp + case 8: + tmp := decString8(p) + *v = &tmp + case 9: + tmp := decString9(p) + *v = &tmp + case 10: + tmp := decString10(p) + *v = &tmp + case 11: + tmp := decString11(p) + *v = &tmp + case 12: + tmp := decString12(p) + *v = &tmp + default: + tmp := decString(p) + *v = &tmp + } + return errBrokenData(p) +} + +func DecReflect(p []byte, v reflect.Value) error { + if v.IsNil() { + return fmt.Errorf("failed to unmarshal decimal: can not unmarshal into nil reference (%T)(%#[1]v)", v.Interface()) + } + + switch v = v.Elem(); v.Kind() { + case reflect.String: + return decReflectString(p, v) + default: + return fmt.Errorf("failed to unmarshal decimal: unsupported value type (%T)(%#[1]v)", v.Interface()) + } +} + +func DecReflectR(p []byte, v reflect.Value) error { + if v.IsNil() { + return fmt.Errorf("failed to unmarshal decimal: can not unmarshal into nil reference (%T)(%[1]v)", v.Interface()) + } + + switch v.Type().Elem().Elem().Kind() { + case reflect.String: + return decReflectStringR(p, v) + default: + return fmt.Errorf("failed to unmarshal decimal: unsupported value type (%T)(%[1]v)", v.Interface()) + } +} + +func decReflectString(p []byte, v reflect.Value) error { + switch len(p) { + case 0: + if p == nil { + v.SetString("") + } else { + v.SetString("0;0") + } + return nil + case 1, 2, 3, 4: + return errWrongDataLen + case 5: + v.SetString(decString5(p)) + return nil + case 6: + v.SetString(decString6(p)) + case 7: + v.SetString(decString7(p)) + case 8: + v.SetString(decString8(p)) + case 9: + v.SetString(decString9(p)) + case 10: + v.SetString(decString10(p)) + case 11: + v.SetString(decString11(p)) + case 12: + v.SetString(decString12(p)) + default: + v.SetString(decString(p)) + } + return errBrokenData(p) +} + +func decReflectStringR(p []byte, v reflect.Value) error { + switch len(p) { + case 0: + var val reflect.Value + if p == nil { + val = reflect.Zero(v.Type().Elem()) + } else { + val = reflect.New(v.Type().Elem().Elem()) + val.Elem().SetString("0;0") + } + v.Elem().Set(val) + return nil + case 1, 2, 3, 4: + return errWrongDataLen + case 5: + newVal := reflect.New(v.Type().Elem().Elem()) + newVal.Elem().SetString(decString5(p)) + v.Elem().Set(newVal) + return nil + case 6: + newVal := reflect.New(v.Type().Elem().Elem()) + newVal.Elem().SetString(decString6(p)) + v.Elem().Set(newVal) + case 7: + newVal := reflect.New(v.Type().Elem().Elem()) + newVal.Elem().SetString(decString7(p)) + v.Elem().Set(newVal) + case 8: + newVal := reflect.New(v.Type().Elem().Elem()) + newVal.Elem().SetString(decString8(p)) + v.Elem().Set(newVal) + case 9: + newVal := reflect.New(v.Type().Elem().Elem()) + newVal.Elem().SetString(decString9(p)) + v.Elem().Set(newVal) + case 10: + newVal := reflect.New(v.Type().Elem().Elem()) + newVal.Elem().SetString(decString10(p)) + v.Elem().Set(newVal) + case 11: + newVal := reflect.New(v.Type().Elem().Elem()) + newVal.Elem().SetString(decString11(p)) + v.Elem().Set(newVal) + case 12: + newVal := reflect.New(v.Type().Elem().Elem()) + newVal.Elem().SetString(decString12(p)) + v.Elem().Set(newVal) + default: + newVal := reflect.New(v.Type().Elem().Elem()) + newVal.Elem().SetString(decString(p)) + v.Elem().Set(newVal) + } + return errBrokenData(p) +} + +func decString5(p []byte) string { + return strconv.FormatInt(decScaleInt64(p), 10) + ";" + strconv.FormatInt(dec1toInt64(p), 10) +} + +func decString6(p []byte) string { + return strconv.FormatInt(decScaleInt64(p), 10) + ";" + strconv.FormatInt(dec2toInt64(p), 10) +} + +func decString7(p []byte) string { + return strconv.FormatInt(decScaleInt64(p), 10) + ";" + strconv.FormatInt(dec3toInt64(p), 10) +} +func decString8(p []byte) string { + return strconv.FormatInt(decScaleInt64(p), 10) + ";" + strconv.FormatInt(dec4toInt64(p), 10) +} +func decString9(p []byte) string { + return strconv.FormatInt(decScaleInt64(p), 10) + ";" + strconv.FormatInt(dec5toInt64(p), 10) +} +func decString10(p []byte) string { + return strconv.FormatInt(decScaleInt64(p), 10) + ";" + strconv.FormatInt(dec6toInt64(p), 10) +} +func decString11(p []byte) string { + return strconv.FormatInt(decScaleInt64(p), 10) + ";" + strconv.FormatInt(dec7toInt64(p), 10) +} +func decString12(p []byte) string { + return strconv.FormatInt(decScaleInt64(p), 10) + ";" + strconv.FormatInt(dec8toInt64(p), 10) +} + +func decString(p []byte) string { + return strconv.FormatInt(decScaleInt64(p), 10) + ";" + varint.Dec2BigInt(p[4:]).String() +} From f01034044f479da76a01dc6c9303f0560ea6ce0c Mon Sep 17 00:00:00 2001 From: illia-li Date: Fri, 18 Oct 2024 14:51:09 -0400 Subject: [PATCH 4/4] fix `decimal` tests --- marshal_test.go | 6 - .../marshal_10_decimal_corrupt_test.go | 69 ++++ .../serialization/marshal_10_decimal_test.go | 385 ++++++++++++++++-- 3 files changed, 417 insertions(+), 43 deletions(-) create mode 100644 tests/serialization/marshal_10_decimal_corrupt_test.go diff --git a/marshal_test.go b/marshal_test.go index ed077ec1d..94b0f0aad 100644 --- a/marshal_test.go +++ b/marshal_test.go @@ -598,12 +598,6 @@ var unmarshalTests = []struct { map[string]int{"foo": 1}, unmarshalErrorf("unmarshal map: unexpected eof"), }, - { - NativeType{proto: 2, typ: TypeDecimal}, - []byte("\xff\xff\xff"), - inf.NewDec(0, 0), // From the datastax/python-driver test suite - unmarshalErrorf("inf.Dec needs at least 4 bytes, while value has only 3"), - }, { NativeType{proto: 5, typ: TypeDuration}, []byte("\x89\xa2\xc3\xc2\x9a\xe0F\x91"), diff --git a/tests/serialization/marshal_10_decimal_corrupt_test.go b/tests/serialization/marshal_10_decimal_corrupt_test.go new file mode 100644 index 000000000..0f3efab87 --- /dev/null +++ b/tests/serialization/marshal_10_decimal_corrupt_test.go @@ -0,0 +1,69 @@ +package serialization_test + +import ( + "gopkg.in/inf.v0" + "testing" + + "github.com/gocql/gocql" + "github.com/gocql/gocql/internal/tests/serialization" + "github.com/gocql/gocql/internal/tests/serialization/mod" + "github.com/gocql/gocql/serialization/decimal" +) + +func TestMarshalDecimalCorrupt(t *testing.T) { + type testSuite struct { + name string + marshal func(interface{}) ([]byte, error) + unmarshal func(bytes []byte, i interface{}) error + } + + tType := gocql.NewNativeType(4, gocql.TypeDecimal, "") + + testSuites := [2]testSuite{ + { + name: "serialization.decimal", + marshal: decimal.Marshal, + unmarshal: decimal.Unmarshal, + }, + { + name: "glob", + marshal: func(i interface{}) ([]byte, error) { + return gocql.Marshal(tType, i) + }, + unmarshal: func(bytes []byte, i interface{}) error { + return gocql.Unmarshal(tType, bytes, i) + }, + }, + } + + for _, tSuite := range testSuites { + marshal := tSuite.marshal + unmarshal := tSuite.unmarshal + + t.Run(tSuite.name, func(t *testing.T) { + serialization.NegativeMarshalSet{ + Values: mod.Values{"1s2", "1s", "-1s", ",1", "0,1"}.AddVariants(mod.All...), + }.Run("corrupt_vals", t, marshal) + + serialization.NegativeUnmarshalSet{ + Data: []byte("\x00\x00\x00\x00\x00\x7f"), + Values: mod.Values{*inf.NewDec(0, 0), ""}.AddVariants(mod.All...), + }.Run("corrupt_data+", t, unmarshal) + + serialization.NegativeUnmarshalSet{ + Data: []byte("\x00\x00\x00\x00\xff\x80"), + Values: mod.Values{*inf.NewDec(0, 0), ""}.AddVariants(mod.All...), + }.Run("corrupt_data-", t, unmarshal) + + serialization.NegativeUnmarshalSet{ + Data: []byte("\x00\x00\x00\x00"), + Values: mod.Values{*inf.NewDec(0, 0), ""}.AddVariants(mod.All...), + }.Run("small_data1", t, unmarshal) + + serialization.NegativeUnmarshalSet{ + Data: []byte("\x00"), + Values: mod.Values{*inf.NewDec(0, 0), ""}.AddVariants(mod.All...), + }.Run("small_data2", t, unmarshal) + }) + } +} diff --git a/tests/serialization/marshal_10_decimal_test.go b/tests/serialization/marshal_10_decimal_test.go index 8787eb1ce..514cbecfc 100644 --- a/tests/serialization/marshal_10_decimal_test.go +++ b/tests/serialization/marshal_10_decimal_test.go @@ -4,55 +4,366 @@ package serialization_test import ( + "fmt" "gopkg.in/inf.v0" "math" + "math/big" "testing" "github.com/gocql/gocql" "github.com/gocql/gocql/internal/tests/serialization" "github.com/gocql/gocql/internal/tests/serialization/mod" + "github.com/gocql/gocql/serialization/decimal" ) func TestMarshalDecimal(t *testing.T) { tType := gocql.NewNativeType(4, gocql.TypeDecimal, "") - marshal := func(i interface{}) ([]byte, error) { return gocql.Marshal(tType, i) } - unmarshal := func(bytes []byte, i interface{}) error { - return gocql.Unmarshal(tType, bytes, i) + type testSuite struct { + name string + marshal func(interface{}) ([]byte, error) + unmarshal func(bytes []byte, i interface{}) error } - // Unmarshal does not support deserialization of `decimal` with `nil` and `zero` `value len` 'into `inf.Dec`. - brokenUnmarshalTypes := serialization.GetTypes(inf.Dec{}, (*inf.Dec)(nil)) - - serialization.PositiveSet{ - Data: nil, - Values: mod.Values{(*inf.Dec)(nil)}, - }.Run("[nil]nullable", t, marshal, unmarshal) - - serialization.PositiveSet{ - Data: nil, - Values: mod.Values{inf.Dec{}}, - BrokenUnmarshalTypes: brokenUnmarshalTypes, - }.Run("[nil]unmarshal", t, nil, unmarshal) - - serialization.PositiveSet{ - Data: make([]byte, 0), - Values: mod.Values{*inf.NewDec(0, 0)}.AddVariants(mod.Reference), - BrokenUnmarshalTypes: brokenUnmarshalTypes, - }.Run("[]unmarshal", t, nil, unmarshal) - - serialization.PositiveSet{ - Data: []byte("\x00\x00\x00\x00\x00"), - Values: mod.Values{*inf.NewDec(0, 0)}.AddVariants(mod.Reference), - }.Run("zeros", t, marshal, unmarshal) - - serialization.PositiveSet{ - Data: []byte("\x7f\xff\xff\xff\x7f\xff\xff\xff\xff\xff\xff\xff"), - Values: mod.Values{*inf.NewDec(int64(math.MaxInt64), inf.Scale(int32(math.MaxInt32)))}.AddVariants(mod.Reference), - }.Run("max_ints", t, marshal, unmarshal) - - serialization.PositiveSet{ - Data: []byte("\x80\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00"), - Values: mod.Values{*inf.NewDec(int64(math.MinInt64), inf.Scale(int32(math.MinInt32)))}.AddVariants(mod.Reference), - }.Run("min_ints", t, marshal, unmarshal) + testSuites := [2]testSuite{ + { + name: "serialization.decimal", + marshal: decimal.Marshal, + unmarshal: decimal.Unmarshal, + }, + { + name: "glob", + marshal: func(i interface{}) ([]byte, error) { + return gocql.Marshal(tType, i) + }, + unmarshal: func(bytes []byte, i interface{}) error { + return gocql.Unmarshal(tType, bytes, i) + }, + }, + } + + getValues := func(scale inf.Scale, unscaled ...int64) mod.Values { + out := make(mod.Values, 2) + switch len(unscaled) { + case 0: + panic("unscaled should be") + case 1: + out[0] = *inf.NewDec(unscaled[0], scale) + out[1] = fmt.Sprintf("%d;%d", scale, unscaled[0]) + default: + bg := new(big.Int) + for _, u := range unscaled { + bg = bg.Add(bg, big.NewInt(u)) + } + out[0] = *inf.NewDecBig(bg, scale) + out[1] = fmt.Sprintf("%d;%s", scale, bg.String()) + } + return out + } + + for _, tSuite := range testSuites { + marshal := tSuite.marshal + unmarshal := tSuite.unmarshal + + t.Run(tSuite.name, func(t *testing.T) { + + serialization.PositiveSet{ + Data: nil, + Values: mod.Values{(*inf.Dec)(nil), ""}.AddVariants(mod.CustomType), + }.Run("[nil]nullable", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: nil, + Values: mod.Values{*inf.NewDec(0, 0), ""}.AddVariants(mod.CustomType), + }.Run("[nil]unmarshal", t, nil, unmarshal) + + serialization.PositiveSet{ + Data: make([]byte, 0), + Values: getValues(0, 0).AddVariants(mod.All...), + }.Run("[]unmarshal", t, nil, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x00\x00\x00"), + Values: getValues(0, 0).AddVariants(mod.All...), + }.Run("zeros", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff"), + Values: getValues(0, math.MaxInt64).AddVariants(mod.All...), + }.Run("scale0_maxInt64", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x00\x01\x7f\xff\xff\xff\xff\xff\xff\xff"), + Values: getValues(1, math.MaxInt64).AddVariants(mod.All...), + }.Run("scale+1_maxInt64", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\xff\xff\xff\xff\x7f\xff\xff\xff\xff\xff\xff\xff"), + Values: getValues(-1, math.MaxInt64).AddVariants(mod.All...), + }.Run("scale-1_maxInt64", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x7f\xff\xff\xff\x7f\xff\xff\xff\xff\xff\xff\xff"), + Values: getValues(math.MaxInt32, math.MaxInt64).AddVariants(mod.All...), + }.Run("maxInt32_maxInt64", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff"), + Values: getValues(math.MinInt32, math.MaxInt64).AddVariants(mod.All...), + }.Run("minInt32_maxInt64", t, marshal, unmarshal) + + scale := inf.Scale(math.MaxInt16) + t.Run("scaleMaxInt16", func(t *testing.T) { + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x01"), + Values: getValues(scale, 1).AddVariants(mod.All...), + }.Run("+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\xff"), + Values: getValues(scale, -1).AddVariants(mod.All...), + }.Run("-1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x7f"), + Values: getValues(scale, 127).AddVariants(mod.All...), + }.Run("maxInt8", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x80"), + Values: getValues(scale, -128).AddVariants(mod.All...), + }.Run("minInt8", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\x80"), + Values: getValues(scale, 128).AddVariants(mod.All...), + }.Run("maxInt8+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\xff\x7f"), + Values: getValues(scale, -129).AddVariants(mod.All...), + }.Run("minInt8-1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x7f\xff"), + Values: getValues(scale, 32767).AddVariants(mod.All...), + }.Run("maxInt16", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x80\x00"), + Values: getValues(scale, -32768).AddVariants(mod.All...), + }.Run("minInt16", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\x80\x00"), + Values: getValues(scale, 32768).AddVariants(mod.All...), + }.Run("maxInt16+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\xff\x7f\xff"), + Values: getValues(scale, -32769).AddVariants(mod.All...), + }.Run("minInt16-1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x7f\xff\xff"), + Values: getValues(scale, 8388607).AddVariants(mod.All...), + }.Run("maxInt24", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x80\x00\x00"), + Values: getValues(scale, -8388608).AddVariants(mod.All...), + }.Run("minInt24", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\x80\x00\x00"), + Values: getValues(scale, 8388608).AddVariants(mod.All...), + }.Run("maxInt24+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\xff\x7f\xff\xff"), + Values: getValues(scale, -8388609).AddVariants(mod.All...), + }.Run("minInt24-1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x7f\xff\xff\xff"), + Values: getValues(scale, 2147483647).AddVariants(mod.All...), + }.Run("maxInt32", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x80\x00\x00\x00"), + Values: getValues(scale, -2147483648).AddVariants(mod.All...), + }.Run("minInt32", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\x80\x00\x00\x00"), + Values: getValues(scale, 2147483648).AddVariants(mod.All...), + }.Run("maxInt32+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\xff\x7f\xff\xff\xff"), + Values: getValues(scale, -2147483649).AddVariants(mod.All...), + }.Run("minInt32-1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x7f\xff\xff\xff\xff"), + Values: getValues(scale, 549755813887).AddVariants(mod.All...), + }.Run("maxInt40", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x80\x00\x00\x00\x00"), + Values: getValues(scale, -549755813888).AddVariants(mod.All...), + }.Run("minInt40", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\x80\x00\x00\x00\x00"), + Values: getValues(scale, 549755813888).AddVariants(mod.All...), + }.Run("maxInt40+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\xff\x7f\xff\xff\xff\xff"), + Values: getValues(scale, -549755813889).AddVariants(mod.All...), + }.Run("minInt40-1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x7f\xff\xff\xff\xff\xff"), + Values: getValues(scale, 140737488355327).AddVariants(mod.All...), + }.Run("maxInt48", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x80\x00\x00\x00\x00\x00"), + Values: getValues(scale, -140737488355328).AddVariants(mod.All...), + }.Run("minInt48", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\x80\x00\x00\x00\x00\x00"), + Values: getValues(scale, 140737488355328).AddVariants(mod.All...), + }.Run("maxInt48+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\xff\x7f\xff\xff\xff\xff\xff"), + Values: getValues(scale, -140737488355329).AddVariants(mod.All...), + }.Run("minInt48-1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x7f\xff\xff\xff\xff\xff\xff"), + Values: getValues(scale, 36028797018963967).AddVariants(mod.All...), + }.Run("maxInt56", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x80\x00\x00\x00\x00\x00\x00"), + Values: getValues(scale, -36028797018963968).AddVariants(mod.All...), + }.Run("minInt56", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\x80\x00\x00\x00\x00\x00\x00"), + Values: getValues(scale, 36028797018963968).AddVariants(mod.All...), + }.Run("maxInt56+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\xff\x7f\xff\xff\xff\xff\xff\xff"), + Values: getValues(scale, -36028797018963969).AddVariants(mod.All...), + }.Run("minInt56-1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x7f\xff\xff\xff\xff\xff\xff\xff"), + Values: getValues(scale, 9223372036854775807).AddVariants(mod.All...), + }.Run("maxInt64", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x80\x00\x00\x00\x00\x00\x00\x00"), + Values: getValues(scale, -9223372036854775808).AddVariants(mod.All...), + }.Run("minInt64", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\x80\x00\x00\x00\x00\x00\x00\x00"), + Values: getValues(scale, 9223372036854775807, 1).AddVariants(mod.All...), + }.Run("maxInt64+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\xff\x7f\xff\xff\xff\xff\xff\xff\xff"), + Values: getValues(scale, -9223372036854775808, -1).AddVariants(mod.All...), + }.Run("minInt64-1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\xff"), + Values: getValues(scale, 255).AddVariants(mod.All...), + }.Run("maxUint8", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x01\x00"), + Values: getValues(scale, 256).AddVariants(mod.All...), + }.Run("maxUint8+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\xff\xff"), + Values: getValues(scale, 65535).AddVariants(mod.All...), + }.Run("maxUint16", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x01\x00\x00"), + Values: getValues(scale, 65536).AddVariants(mod.All...), + }.Run("maxUint16+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\xff\xff\xff"), + Values: getValues(scale, 16777215).AddVariants(mod.All...), + }.Run("maxUint24", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x01\x00\x00\x00"), + Values: getValues(scale, 16777216).AddVariants(mod.All...), + }.Run("maxUint24+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\xff\xff\xff\xff"), + Values: getValues(scale, 4294967295).AddVariants(mod.All...), + }.Run("maxUint32", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x01\x00\x00\x00\x00"), + Values: getValues(scale, 4294967296).AddVariants(mod.All...), + }.Run("maxUint32+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\xff\xff\xff\xff\xff"), + Values: getValues(scale, 1099511627775).AddVariants(mod.All...), + }.Run("maxUint40", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x01\x00\x00\x00\x00\x00"), + Values: getValues(scale, 1099511627776).AddVariants(mod.All...), + }.Run("maxUint40+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\xff\xff\xff\xff\xff\xff"), + Values: getValues(scale, 281474976710655).AddVariants(mod.All...), + }.Run("maxUint48", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x01\x00\x00\x00\x00\x00\x00"), + Values: getValues(scale, 281474976710656).AddVariants(mod.All...), + }.Run("maxUint48+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\xff\xff\xff\xff\xff\xff\xff"), + Values: getValues(scale, 72057594037927935).AddVariants(mod.All...), + }.Run("maxUint56", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x01\x00\x00\x00\x00\x00\x00\x00"), + Values: getValues(scale, 72057594037927936).AddVariants(mod.All...), + }.Run("maxUint56+1", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff"), + Values: getValues(scale, 9223372036854775807, 9223372036854775807, 1).AddVariants(mod.All...), + }.Run("maxUint64", t, marshal, unmarshal) + + serialization.PositiveSet{ + Data: []byte("\x00\x00\x7f\xff\x01\x00\x00\x00\x00\x00\x00\x00\x00"), + Values: getValues(scale, 9223372036854775807, 9223372036854775807, 2).AddVariants(mod.All...), + }.Run("maxUint64+1", t, marshal, unmarshal) + }) + }) + } }