Skip to content

Commit f3fc875

Browse files
committed
value: introduce CqlDecimalBorrowed
Has the same semantics as CqlDecimal, but borrows the bytes.
1 parent c53a8d4 commit f3fc875

File tree

5 files changed

+97
-6
lines changed

5 files changed

+97
-6
lines changed

docs/source/data-types/decimal.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
## value::CqlDecimal
55

6-
Without any feature flags, the user can interact with `decimal` type by making use of `value::CqlDecimal` which is a very simple wrapper representing the value as signed binary number in big-endian order with a 32-bit scale.
6+
Without any feature flags, the user can interact with `decimal` type by making use of `value::CqlDecimal` or `value::CqlDecimalBorrowed` which are very simple wrappers representing the value as signed binary number in big-endian order with a 32-bit scale.
77

88
```rust
99
# extern crate scylla;

scylla-cql/src/frame/value.rs

+52
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,9 @@ impl From<CqlVarintBorrowed<'_>> for num_bigint_04::BigInt {
454454
/// - a [`CqlVarint`] value
455455
/// - 32-bit integer which determines the position of the decimal point
456456
///
457+
/// This struct holds owned bytes. If you wish to borrow the bytes instead,
458+
/// see [`CqlDecimalBorrowed`] documentation.
459+
///
457460
/// The type is not very useful in most use cases.
458461
/// However, users can make use of more complex types
459462
/// such as `bigdecimal::BigDecimal` (v0.4).
@@ -470,6 +473,20 @@ pub struct CqlDecimal {
470473
scale: i32,
471474
}
472475

476+
/// Borrowed version of native CQL `decimal` representation.
477+
///
478+
/// Represented as a pair:
479+
/// - a [`CqlVarintBorrowed`] value
480+
/// - 32-bit integer which determines the position of the decimal point
481+
///
482+
/// Refer to the documentation of [`CqlDecimal`].
483+
/// Especially, see the disclaimer about [non-normalized values](CqlDecimal#db-data-format).
484+
#[derive(Clone, PartialEq, Eq, Debug)]
485+
pub struct CqlDecimalBorrowed<'b> {
486+
int_val: CqlVarintBorrowed<'b>,
487+
scale: i32,
488+
}
489+
473490
/// Constructors
474491
impl CqlDecimal {
475492
/// Creates a [`CqlDecimal`] from an array of bytes
@@ -492,6 +509,20 @@ impl CqlDecimal {
492509
}
493510
}
494511

512+
/// Constructors
513+
impl<'b> CqlDecimalBorrowed<'b> {
514+
/// Creates a [`CqlDecimalBorrowed`] from a slice of bytes
515+
/// representing [`CqlVarintBorrowed`] and a 32-bit scale.
516+
///
517+
/// See: disclaimer about [non-normalized values](CqlVarint#db-data-format).
518+
pub fn from_signed_be_bytes_slice_and_exponent(bytes: &'b [u8], scale: i32) -> Self {
519+
Self {
520+
int_val: CqlVarintBorrowed::from_signed_bytes_be_slice(bytes),
521+
scale,
522+
}
523+
}
524+
}
525+
495526
/// Conversion to raw bytes
496527
impl CqlDecimal {
497528
/// Returns a slice of bytes in two's complement
@@ -507,6 +538,15 @@ impl CqlDecimal {
507538
}
508539
}
509540

541+
/// Conversion to raw bytes
542+
impl CqlDecimalBorrowed<'_> {
543+
/// Returns a slice of bytes in two's complement
544+
/// binary big-endian representation and a scale.
545+
pub fn as_signed_be_bytes_slice_and_exponent(&self) -> (&[u8], i32) {
546+
(self.int_val.as_signed_bytes_be_slice(), self.scale)
547+
}
548+
}
549+
510550
#[cfg(feature = "bigdecimal-04")]
511551
impl From<CqlDecimal> for bigdecimal_04::BigDecimal {
512552
fn from(value: CqlDecimal) -> Self {
@@ -519,6 +559,18 @@ impl From<CqlDecimal> for bigdecimal_04::BigDecimal {
519559
}
520560
}
521561

562+
#[cfg(feature = "bigdecimal-04")]
563+
impl From<CqlDecimalBorrowed<'_>> for bigdecimal_04::BigDecimal {
564+
fn from(value: CqlDecimalBorrowed) -> Self {
565+
Self::from((
566+
bigdecimal_04::num_bigint::BigInt::from_signed_bytes_be(
567+
value.int_val.as_signed_bytes_be_slice(),
568+
),
569+
value.scale as i64,
570+
))
571+
}
572+
}
573+
522574
#[cfg(feature = "bigdecimal-04")]
523575
impl TryFrom<bigdecimal_04::BigDecimal> for CqlDecimal {
524576
type Error = <i64 as TryInto<i32>>::Error;

scylla-cql/src/types/deserialize/value.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ use std::fmt::Display;
1515
use thiserror::Error;
1616

1717
use super::{make_error_replace_rust_name, DeserializationError, FrameSlice, TypeCheckError};
18-
use crate::frame::response::result::{deser_cql_value, ColumnType, CqlValue};
1918
use crate::frame::types;
2019
use crate::frame::value::{
2120
Counter, CqlDate, CqlDecimal, CqlDuration, CqlTime, CqlTimestamp, CqlTimeuuid, CqlVarint,
2221
};
2322
use crate::frame::{frame_errors::LowLevelDeserializationError, value::CqlVarintBorrowed};
23+
use crate::frame::{
24+
response::result::{deser_cql_value, ColumnType, CqlValue},
25+
value::CqlDecimalBorrowed,
26+
};
2427

2528
/// A type that can be deserialized from a column value inside a row that was
2629
/// returned from a query.
@@ -269,6 +272,24 @@ impl_emptiable_strict_type!(
269272
}
270273
);
271274

275+
impl_emptiable_strict_type!(
276+
CqlDecimalBorrowed<'b>,
277+
Decimal,
278+
|typ: &'metadata ColumnType<'metadata>, v: Option<FrameSlice<'frame>>| {
279+
let mut val = ensure_not_null_slice::<Self>(typ, v)?;
280+
let scale = types::read_int(&mut val).map_err(|err| {
281+
mk_deser_err::<Self>(
282+
typ,
283+
BuiltinDeserializationErrorKind::BadDecimalScale(err.into()),
284+
)
285+
})?;
286+
Ok(CqlDecimalBorrowed::from_signed_be_bytes_slice_and_exponent(
287+
val, scale,
288+
))
289+
},
290+
'b
291+
);
292+
272293
#[cfg(feature = "bigdecimal-04")]
273294
impl_emptiable_strict_type!(
274295
bigdecimal_04::BigDecimal,

scylla-cql/src/types/deserialize/value_tests.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
1010

1111
use crate::frame::response::result::{ColumnType, CqlValue};
1212
use crate::frame::value::{
13-
Counter, CqlDate, CqlDecimal, CqlDuration, CqlTime, CqlTimestamp, CqlTimeuuid, CqlVarint,
14-
CqlVarintBorrowed,
13+
Counter, CqlDate, CqlDecimal, CqlDecimalBorrowed, CqlDuration, CqlTime, CqlTimestamp,
14+
CqlTimeuuid, CqlVarint, CqlVarintBorrowed,
1515
};
1616
use crate::types::deserialize::value::{TupleDeserializationErrorKind, TupleTypeCheckErrorKind};
1717
use crate::types::deserialize::{DeserializationError, FrameSlice, TypeCheckError};
@@ -187,6 +187,12 @@ fn test_varlen_numbers() {
187187
&mut Bytes::new(),
188188
);
189189

190+
assert_ser_de_identity(
191+
&ColumnType::Decimal,
192+
&CqlDecimalBorrowed::from_signed_be_bytes_slice_and_exponent(b"Ala ma kota", 42),
193+
&mut Bytes::new(),
194+
);
195+
190196
#[cfg(feature = "bigdecimal-04")]
191197
assert_ser_de_identity(
192198
&ColumnType::Decimal,

scylla-cql/src/types/serialize/value.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use uuid::Uuid;
1616
use crate::frame::response::result::{ColumnType, CqlValue};
1717
use crate::frame::types::vint_encode;
1818
use crate::frame::value::{
19-
Counter, CqlDate, CqlDecimal, CqlDuration, CqlTime, CqlTimestamp, CqlTimeuuid, CqlVarint,
20-
CqlVarintBorrowed, MaybeUnset, Unset, Value,
19+
Counter, CqlDate, CqlDecimal, CqlDecimalBorrowed, CqlDuration, CqlTime, CqlTimestamp,
20+
CqlTimeuuid, CqlVarint, CqlVarintBorrowed, MaybeUnset, Unset, Value,
2121
};
2222

2323
#[cfg(feature = "chrono-04")]
@@ -124,6 +124,18 @@ impl SerializeValue for CqlDecimal {
124124
.map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
125125
});
126126
}
127+
impl SerializeValue for CqlDecimalBorrowed<'_> {
128+
impl_serialize_via_writer!(|me, typ, writer| {
129+
exact_type_check!(typ, Decimal);
130+
let mut builder = writer.into_value_builder();
131+
let (bytes, scale) = me.as_signed_be_bytes_slice_and_exponent();
132+
builder.append_bytes(&scale.to_be_bytes());
133+
builder.append_bytes(bytes);
134+
builder
135+
.finish()
136+
.map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
137+
});
138+
}
127139
#[cfg(feature = "bigdecimal-04")]
128140
impl SerializeValue for bigdecimal_04::BigDecimal {
129141
impl_serialize_via_writer!(|me, typ, writer| {

0 commit comments

Comments
 (0)