Skip to content

Commit 65146eb

Browse files
committed
varint: implement PartialEq for CqlVarint
1 parent e94b89e commit 65146eb

File tree

1 file changed

+59
-1
lines changed

1 file changed

+59
-1
lines changed

scylla-cql/src/frame/value.rs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,10 @@ impl std::hash::Hash for CqlTimeuuid {
230230
///
231231
/// Currently, Scylla and Cassandra support non-normalized `varint` values.
232232
/// Bytes provided by the user via constructor are passed to DB as is.
233-
#[derive(Clone, Debug)]
233+
///
234+
/// The implementation of [`PartialEq`], however, normalizes the underlying bytes
235+
/// before comparison. For details, check [examples](#impl-PartialEq-for-CqlVarint).
236+
#[derive(Clone, Eq, Debug)]
234237
pub struct CqlVarint(Vec<u8>);
235238

236239
/// Constructors from bytes
@@ -267,6 +270,42 @@ impl CqlVarint {
267270
}
268271
}
269272

273+
impl CqlVarint {
274+
fn as_normalized_slice(&self) -> &[u8] {
275+
let digits = self.0.as_slice();
276+
if digits.is_empty() {
277+
// num-bigint crate normalizes empty vector to 0.
278+
// We will follow the same approach.
279+
return &[0];
280+
}
281+
282+
let non_zero_position = match digits.iter().position(|b| *b != 0) {
283+
Some(pos) => pos,
284+
None => {
285+
// Vector is filled with zeros. Represent it as 0.
286+
return &[0];
287+
}
288+
};
289+
290+
if non_zero_position > 0 {
291+
// There were some leading zeros.
292+
// Now, there are two cases:
293+
let zeros_to_remove = if digits[non_zero_position] > 0x7f {
294+
// Most significant bit is 1, so we need to include one of the leading
295+
// zeros as originally it represented a positive number.
296+
non_zero_position - 1
297+
} else {
298+
// Most significant bit is 0 - positive number with no leading zeros.
299+
non_zero_position
300+
};
301+
return &digits[zeros_to_remove..];
302+
}
303+
304+
// There were no leading zeros at all - leave as is.
305+
digits
306+
}
307+
}
308+
270309
impl From<BigInt> for CqlVarint {
271310
fn from(value: BigInt) -> Self {
272311
Self(value.to_signed_bytes_be())
@@ -279,6 +318,25 @@ impl From<CqlVarint> for BigInt {
279318
}
280319
}
281320

321+
/// Compares two [`CqlVarint`] values after normalization.
322+
///
323+
/// # Example
324+
///
325+
/// ```rust
326+
/// # use scylla_cql::frame::value::CqlVarint;
327+
/// let non_normalized_bytes = vec![0x00, 0x01];
328+
/// let normalized_bytes = vec![0x01];
329+
/// assert_eq!(
330+
/// CqlVarint::from_signed_bytes_be(non_normalized_bytes),
331+
/// CqlVarint::from_signed_bytes_be(normalized_bytes)
332+
/// );
333+
/// ```
334+
impl PartialEq for CqlVarint {
335+
fn eq(&self, other: &Self) -> bool {
336+
self.as_normalized_slice() == other.as_normalized_slice()
337+
}
338+
}
339+
282340
/// Native CQL date representation that allows for a bigger range of dates (-262145-1-1 to 262143-12-31).
283341
///
284342
/// Represented as number of days since -5877641-06-23 i.e. 2^31 days before unix epoch.

0 commit comments

Comments
 (0)