Skip to content

Commit 10add75

Browse files
committed
value: introduce CqlVarintBorrowed
This is a native representation of varint that holds borrowed bytes. Implemented SerializeValue and DeserializeValue for new type.
1 parent d541339 commit 10add75

File tree

5 files changed

+121
-6
lines changed

5 files changed

+121
-6
lines changed

docs/source/data-types/varint.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ To make use of `num_bigint::BigInt` type, user should enable one of the availabl
77

88
## value::CqlVarint
99

10-
Without any feature flags, the user can interact with `Varint` type by making use of `value::CqlVarint` which
11-
is a very simple wrapper representing the value as signed binary number in big-endian order.
10+
Without any feature flags, the user can interact with `Varint` type by making use of `value::CqlVarint` or `value::CqlVarintBorrowed` which are very simple wrappers representing the value as signed binary number in big-endian order.
1211

1312
## Example
1413

scylla-cql/src/frame/value.rs

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,9 @@ impl std::hash::Hash for CqlTimeuuid {
220220
/// The library support (e.g. conversion from [`CqlValue`]) for these types is
221221
/// enabled via `num-bigint-03` and `num-bigint-04` crate features.
222222
///
223+
/// This struct holds owned bytes. If you wish to borrow the bytes instead,
224+
/// see [`CqlVarintBorrowed`] documentation.
225+
///
223226
/// # DB data format
224227
/// Notice that [constructors](CqlVarint#impl-CqlVarint)
225228
/// don't perform any normalization on the provided data.
@@ -233,6 +236,13 @@ impl std::hash::Hash for CqlTimeuuid {
233236
#[derive(Clone, Eq, Debug)]
234237
pub struct CqlVarint(Vec<u8>);
235238

239+
/// A borrowed version of native CQL `varint` representation.
240+
///
241+
/// Refer to the documentation of [`CqlVarint`].
242+
/// Especially, see the disclaimer about [non-normalized values](CqlVarint#db-data-format).
243+
#[derive(Clone, Eq, Debug)]
244+
pub struct CqlVarintBorrowed<'b>(&'b [u8]);
245+
236246
/// Constructors from bytes
237247
impl CqlVarint {
238248
/// Creates a [`CqlVarint`] from an array of bytes in
@@ -252,6 +262,17 @@ impl CqlVarint {
252262
}
253263
}
254264

265+
/// Constructors from bytes
266+
impl<'b> CqlVarintBorrowed<'b> {
267+
/// Creates a [`CqlVarintBorrowed`] from a slice of bytes in
268+
/// two's complement binary big-endian representation.
269+
///
270+
/// See: disclaimer about [non-normalized values](CqlVarint#db-data-format).
271+
pub fn from_signed_bytes_be_slice(digits: &'b [u8]) -> Self {
272+
Self(digits)
273+
}
274+
}
275+
255276
/// Conversion to bytes
256277
impl CqlVarint {
257278
/// Converts [`CqlVarint`] to an array of bytes in two's
@@ -267,9 +288,39 @@ impl CqlVarint {
267288
}
268289
}
269290

270-
impl CqlVarint {
291+
/// Conversion to bytes
292+
impl CqlVarintBorrowed<'_> {
293+
/// Returns a slice of bytes in two's complement
294+
/// binary big-endian representation.
295+
pub fn as_signed_bytes_be_slice(&self) -> &[u8] {
296+
self.0
297+
}
298+
}
299+
300+
/// An internal utility trait used to implement [`AsNormalizedVarintSlice`]
301+
/// for both [`CqlVarint`] and [`CqlVarintBorrowed`].
302+
trait AsVarintSlice {
303+
fn as_slice(&self) -> &[u8];
304+
}
305+
impl AsVarintSlice for CqlVarint {
306+
fn as_slice(&self) -> &[u8] {
307+
self.as_signed_bytes_be_slice()
308+
}
309+
}
310+
impl AsVarintSlice for CqlVarintBorrowed<'_> {
311+
fn as_slice(&self) -> &[u8] {
312+
self.as_signed_bytes_be_slice()
313+
}
314+
}
315+
316+
/// An internal utility trait used to implement [`PartialEq`] and [`std::hash::Hash`]
317+
/// for [`CqlVarint`] and [`CqlVarintBorrowed`].
318+
trait AsNormalizedVarintSlice {
319+
fn as_normalized_slice(&self) -> &[u8];
320+
}
321+
impl<V: AsVarintSlice> AsNormalizedVarintSlice for V {
271322
fn as_normalized_slice(&self) -> &[u8] {
272-
let digits = self.0.as_slice();
323+
let digits = self.as_slice();
273324
if digits.is_empty() {
274325
// num-bigint crate normalizes empty vector to 0.
275326
// We will follow the same approach.
@@ -329,6 +380,32 @@ impl std::hash::Hash for CqlVarint {
329380
}
330381
}
331382

383+
/// Compares two [`CqlVarintBorrowed`] values after normalization.
384+
///
385+
/// # Example
386+
///
387+
/// ```rust
388+
/// # use scylla_cql::frame::value::CqlVarintBorrowed;
389+
/// let non_normalized_bytes = &[0x00, 0x01];
390+
/// let normalized_bytes = &[0x01];
391+
/// assert_eq!(
392+
/// CqlVarintBorrowed::from_signed_bytes_be_slice(non_normalized_bytes),
393+
/// CqlVarintBorrowed::from_signed_bytes_be_slice(normalized_bytes)
394+
/// );
395+
/// ```
396+
impl PartialEq for CqlVarintBorrowed<'_> {
397+
fn eq(&self, other: &Self) -> bool {
398+
self.as_normalized_slice() == other.as_normalized_slice()
399+
}
400+
}
401+
402+
/// Computes the hash of normalized [`CqlVarintBorrowed`].
403+
impl std::hash::Hash for CqlVarintBorrowed<'_> {
404+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
405+
self.as_normalized_slice().hash(state)
406+
}
407+
}
408+
332409
#[cfg(feature = "num-bigint-03")]
333410
impl From<num_bigint_03::BigInt> for CqlVarint {
334411
fn from(value: num_bigint_03::BigInt) -> Self {
@@ -343,6 +420,13 @@ impl From<CqlVarint> for num_bigint_03::BigInt {
343420
}
344421
}
345422

423+
#[cfg(feature = "num-bigint-03")]
424+
impl From<CqlVarintBorrowed<'_>> for num_bigint_03::BigInt {
425+
fn from(val: CqlVarintBorrowed<'_>) -> Self {
426+
num_bigint_03::BigInt::from_signed_bytes_be(val.0)
427+
}
428+
}
429+
346430
#[cfg(feature = "num-bigint-04")]
347431
impl From<num_bigint_04::BigInt> for CqlVarint {
348432
fn from(value: num_bigint_04::BigInt) -> Self {
@@ -357,6 +441,13 @@ impl From<CqlVarint> for num_bigint_04::BigInt {
357441
}
358442
}
359443

444+
#[cfg(feature = "num-bigint-04")]
445+
impl From<CqlVarintBorrowed<'_>> for num_bigint_04::BigInt {
446+
fn from(val: CqlVarintBorrowed<'_>) -> Self {
447+
num_bigint_04::BigInt::from_signed_bytes_be(val.0)
448+
}
449+
}
450+
360451
/// Native CQL `decimal` representation.
361452
///
362453
/// Represented as a pair:

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ use std::fmt::Display;
1515
use thiserror::Error;
1616

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

2525
/// A type that can be deserialized from a column value inside a row that was
2626
/// returned from a query.
@@ -222,6 +222,16 @@ impl_emptiable_strict_type!(
222222
}
223223
);
224224

225+
impl_emptiable_strict_type!(
226+
CqlVarintBorrowed<'b>,
227+
Varint,
228+
|typ: &'metadata ColumnType<'metadata>, v: Option<FrameSlice<'frame>>| {
229+
let val = ensure_not_null_slice::<Self>(typ, v)?;
230+
Ok(CqlVarintBorrowed::from_signed_bytes_be_slice(val))
231+
},
232+
'b
233+
);
234+
225235
#[cfg(feature = "num-bigint-03")]
226236
impl_emptiable_strict_type!(
227237
num_bigint_03::BigInt,

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
1111
use crate::frame::response::result::{ColumnType, CqlValue};
1212
use crate::frame::value::{
1313
Counter, CqlDate, CqlDecimal, CqlDuration, CqlTime, CqlTimestamp, CqlTimeuuid, CqlVarint,
14+
CqlVarintBorrowed,
1415
};
1516
use crate::types::deserialize::value::{TupleDeserializationErrorKind, TupleTypeCheckErrorKind};
1617
use crate::types::deserialize::{DeserializationError, FrameSlice, TypeCheckError};
@@ -159,6 +160,12 @@ fn test_varlen_numbers() {
159160
&mut Bytes::new(),
160161
);
161162

163+
assert_ser_de_identity(
164+
&ColumnType::Varint,
165+
&CqlVarintBorrowed::from_signed_bytes_be_slice(b"Ala ma kota"),
166+
&mut Bytes::new(),
167+
);
168+
162169
#[cfg(feature = "num-bigint-03")]
163170
assert_ser_de_identity(
164171
&ColumnType::Varint,

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::frame::response::result::{ColumnType, CqlValue};
1717
use crate::frame::types::vint_encode;
1818
use crate::frame::value::{
1919
Counter, CqlDate, CqlDecimal, CqlDuration, CqlTime, CqlTimestamp, CqlTimeuuid, CqlVarint,
20-
MaybeUnset, Unset, Value,
20+
CqlVarintBorrowed, MaybeUnset, Unset, Value,
2121
};
2222

2323
#[cfg(feature = "chrono-04")]
@@ -252,6 +252,14 @@ impl SerializeValue for CqlVarint {
252252
.map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
253253
});
254254
}
255+
impl SerializeValue for CqlVarintBorrowed<'_> {
256+
impl_serialize_via_writer!(|me, typ, writer| {
257+
exact_type_check!(typ, Varint);
258+
writer
259+
.set_value(me.as_signed_bytes_be_slice())
260+
.map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
261+
});
262+
}
255263
#[cfg(feature = "num-bigint-03")]
256264
impl SerializeValue for num_bigint_03::BigInt {
257265
impl_serialize_via_writer!(|me, typ, writer| {

0 commit comments

Comments
 (0)