Skip to main content

scylla_cql_core/
value.rs

1//! Defines CQL values of various types and their representations,
2//! as well as conversion between them and other types.
3
4use std::net::IpAddr;
5use std::time::{SystemTime, UNIX_EPOCH};
6
7use thiserror::Error;
8use uuid::Uuid;
9
10use crate::utils::safe_format::IteratorSafeFormatExt;
11
12/// Error type indicating that the value is too large to fit in the destination type.
13///
14/// Intended to be used when converting between CQL types and other types
15/// in case the source type is larger than the destination type.
16#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
17#[error(
18    "Conversion between CQL type and another type is not possible because\
19    value of one of them is too large to fit in the other"
20)]
21pub struct ValueOverflow;
22
23/// Represents an unset value
24#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
25pub struct Unset;
26
27/// Represents an counter value
28#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
29pub struct Counter(pub i64);
30
31/// Enum providing a way to represent a value that might be unset
32#[derive(Debug, Clone, Copy, Default)]
33pub enum MaybeUnset<V> {
34    /// The value is unset, so the server's state about this value will not be changed.
35    #[default]
36    Unset,
37    /// The value is set, so the server's state will be changed to this value.
38    Set(V),
39}
40
41impl<V> MaybeUnset<V> {
42    /// Converts an `Option<V>` into a `MaybeUnset<V>`.
43    #[inline]
44    pub fn from_option(opt: Option<V>) -> Self {
45        match opt {
46            Some(v) => Self::Set(v),
47            None => Self::Unset,
48        }
49    }
50}
51
52/// Values that may be empty or not.
53///
54/// In CQL, some types can have a special value of "empty", represented as
55/// a serialized value of length 0. An example of this are integral types:
56/// the "int" type can actually hold 2^32 + 1 possible values because of this
57/// quirk. Note that this is distinct from being NULL.
58///
59/// Rust types that cannot represent an empty value (e.g. i32) should implement
60/// this trait in order to be deserialized as [`MaybeEmpty`] or serialized
61/// from it.
62pub trait Emptiable {}
63
64// Implementations of Emptiable for types that support empty CQL values.
65
66impl Emptiable for bool {}
67impl Emptiable for i8 {}
68impl Emptiable for i16 {}
69impl Emptiable for i32 {}
70impl Emptiable for i64 {}
71impl Emptiable for f32 {}
72impl Emptiable for f64 {}
73
74impl Emptiable for CqlVarint {}
75impl<'b> Emptiable for CqlVarintBorrowed<'b> {}
76impl Emptiable for CqlDecimal {}
77impl<'b> Emptiable for CqlDecimalBorrowed<'b> {}
78impl Emptiable for CqlDate {}
79impl Emptiable for CqlTime {}
80impl Emptiable for CqlTimestamp {}
81impl Emptiable for CqlTimeuuid {}
82
83impl Emptiable for std::net::IpAddr {}
84impl Emptiable for uuid::Uuid {}
85
86#[cfg(feature = "num-bigint-03")]
87impl Emptiable for num_bigint_03::BigInt {}
88#[cfg(feature = "num-bigint-04")]
89impl Emptiable for num_bigint_04::BigInt {}
90#[cfg(feature = "bigdecimal-04")]
91impl Emptiable for bigdecimal_04::BigDecimal {}
92
93#[cfg(feature = "chrono-04")]
94impl Emptiable for chrono_04::NaiveDate {}
95#[cfg(feature = "chrono-04")]
96impl Emptiable for chrono_04::NaiveTime {}
97#[cfg(feature = "chrono-04")]
98impl Emptiable for chrono_04::DateTime<chrono_04::Utc> {}
99
100#[cfg(feature = "time-03")]
101impl Emptiable for time_03::Date {}
102#[cfg(feature = "time-03")]
103impl Emptiable for time_03::Time {}
104#[cfg(feature = "time-03")]
105impl Emptiable for time_03::OffsetDateTime {}
106
107/// A value that may be empty or not.
108///
109/// `MaybeEmpty` was introduced to help support the quirk described in [`Emptiable`]
110/// for Rust types which can't represent the empty, additional value.
111///
112/// This type can be both serialized and deserialized. When serializing,
113/// [`MaybeEmpty::Empty`] will produce an empty value (0 bytes) for emptiable types.
114/// When deserializing, an empty value will be represented as [`MaybeEmpty::Empty`].
115#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
116pub enum MaybeEmpty<T: Emptiable> {
117    /// Represents an empty value (0 bytes in the serialized form).
118    Empty,
119    /// Represents a non-empty value.
120    Value(T),
121}
122
123/// Represents timeuuid (uuid V1) value
124///
125/// This type has custom comparison logic which follows ScyllaDB/Cassandra semantics.
126/// For details, see [`Ord` implementation](#impl-Ord-for-CqlTimeuuid).
127#[derive(Debug, Clone, Copy, Eq)]
128pub struct CqlTimeuuid(Uuid);
129
130/// [`Uuid`] delegate methods
131impl CqlTimeuuid {
132    /// Creates a new nil `CqlTimeuuid`.
133    /// See [`Uuid::nil`] for details.
134    pub fn nil() -> Self {
135        Self(Uuid::nil())
136    }
137
138    /// Returns byte representation of the `CqlTimeuuid`.
139    /// See [`Uuid::as_bytes`] for details.
140    pub fn as_bytes(&self) -> &[u8; 16] {
141        self.0.as_bytes()
142    }
143
144    /// Returns a `u128` representation of the `CqlTimeuuid`.
145    /// See [`Uuid::as_u128`] for details.
146    pub fn as_u128(&self) -> u128 {
147        self.0.as_u128()
148    }
149
150    /// Returns a representation of the `CqlTimeuuid` as a list of its logical fields.
151    /// See [`Uuid::as_fields`] for details.
152    pub fn as_fields(&self) -> (u32, u16, u16, &[u8; 8]) {
153        self.0.as_fields()
154    }
155
156    /// Returns a representation of the `CqlTimeuuid` as a pair of `u64` values.
157    /// See [`Uuid::as_u64_pair`] for details.
158    pub fn as_u64_pair(&self) -> (u64, u64) {
159        self.0.as_u64_pair()
160    }
161
162    /// Creates a new `CqlTimeuuid` from a big-endian byte representation.
163    /// See [`Uuid::from_slice`] for details.
164    pub fn from_slice(b: &[u8]) -> Result<Self, uuid::Error> {
165        Ok(Self(Uuid::from_slice(b)?))
166    }
167
168    /// Creates a new `CqlTimeuuid` from a little-endian byte representation.
169    /// See [`Uuid::from_slice_le`] for details.
170    pub fn from_slice_le(b: &[u8]) -> Result<Self, uuid::Error> {
171        Ok(Self(Uuid::from_slice_le(b)?))
172    }
173
174    /// Creates a new `CqlTimeuuid` from a big-endian byte representation.
175    /// See [`Uuid::from_bytes`] for details.
176    pub fn from_bytes(bytes: [u8; 16]) -> Self {
177        Self(Uuid::from_bytes(bytes))
178    }
179
180    /// Creates a new `CqlTimeuuid` from a little-endian byte representation.
181    /// See [`Uuid::from_bytes_le`] for details.
182    pub fn from_bytes_le(bytes: [u8; 16]) -> Self {
183        Self(Uuid::from_bytes_le(bytes))
184    }
185
186    /// Creates a new `CqlTimeuuid` from a big-endian byte representation of its fields.
187    /// See [`Uuid::from_fields`] for details.
188    pub fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Self {
189        Self(Uuid::from_fields(d1, d2, d3, d4))
190    }
191
192    /// Creates a new `CqlTimeuuid` from a little-endian byte representation of its fields.
193    /// See [`Uuid::from_fields_le`] for details.
194    pub fn from_fields_le(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Self {
195        Self(Uuid::from_fields_le(d1, d2, d3, d4))
196    }
197
198    /// Creates a new `CqlTimeuuid` from a big-endian `u128` value.
199    /// See [`Uuid::from_u128`] for details.
200    pub fn from_u128(v: u128) -> Self {
201        Self(Uuid::from_u128(v))
202    }
203
204    /// Creates a new `CqlTimeuuid` from a little-endian `u128` value.
205    /// See [`Uuid::from_u128_le`] for details.
206    pub fn from_u128_le(v: u128) -> Self {
207        Self(Uuid::from_u128_le(v))
208    }
209
210    /// Creates a new `CqlTimeuuid` from a pair of `u64` values.
211    /// See [`Uuid::from_u64_pair`] for details.
212    pub fn from_u64_pair(high_bits: u64, low_bits: u64) -> Self {
213        Self(Uuid::from_u64_pair(high_bits, low_bits))
214    }
215}
216
217impl CqlTimeuuid {
218    /// Read 8 most significant bytes of timeuuid from serialized bytes
219    fn msb(&self) -> u64 {
220        // Scylla and Cassandra use a standard UUID memory layout for MSB:
221        // 4 bytes    2 bytes    2 bytes
222        // time_low - time_mid - time_hi_and_version
223        let bytes = self.0.as_bytes();
224        u64::from_be_bytes([
225            bytes[6] & 0x0f,
226            bytes[7],
227            bytes[4],
228            bytes[5],
229            bytes[0],
230            bytes[1],
231            bytes[2],
232            bytes[3],
233        ])
234    }
235
236    fn lsb(&self) -> u64 {
237        let bytes = self.0.as_bytes();
238        u64::from_be_bytes([
239            bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
240        ])
241    }
242
243    /// Returns the least significant bytes transformed so that an unsigned
244    /// comparison of the result reproduces Scylla/Cassandra's ordering of those
245    /// bytes for two timeuuids with equal `msb` (used by the [`Ord`] impl).
246    ///
247    /// Cassandra legacy compares the 8 low bytes as *signed bytes* — each byte
248    /// independently, most-significant byte first — not as one signed 64-bit
249    /// integer. Scylla implements this in `timeuuid_tri_compare` (utils/UUID.hh)
250    /// as `lsb ^ 0x8080808080808080` followed by an unsigned compare: flipping
251    /// the top bit of every byte maps each byte's signed order onto its unsigned
252    /// order, so a big-endian `u64` comparison of the XORed value matches the
253    /// byte-wise signed ordering.
254    fn lsb_signed(&self) -> u64 {
255        self.lsb() ^ 0x8080808080808080
256    }
257}
258
259impl std::str::FromStr for CqlTimeuuid {
260    type Err = uuid::Error;
261
262    fn from_str(s: &str) -> Result<Self, Self::Err> {
263        Ok(Self(Uuid::from_str(s)?))
264    }
265}
266
267impl std::fmt::Display for CqlTimeuuid {
268    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269        write!(f, "{}", self.0)
270    }
271}
272
273impl AsRef<Uuid> for CqlTimeuuid {
274    fn as_ref(&self) -> &Uuid {
275        &self.0
276    }
277}
278
279impl From<CqlTimeuuid> for Uuid {
280    fn from(value: CqlTimeuuid) -> Self {
281        value.0
282    }
283}
284
285impl From<Uuid> for CqlTimeuuid {
286    fn from(value: Uuid) -> Self {
287        Self(value)
288    }
289}
290
291/// Compare two values of timeuuid type.
292///
293/// Cassandra legacy requires:
294/// - converting 8 most significant bytes to date, which is then compared.
295/// - masking off UUID version from the 8 ms-bytes during compare, to
296///   treat possible non-version-1 UUID the same way as UUID.
297/// - using signed compare for least significant bits.
298impl Ord for CqlTimeuuid {
299    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
300        let mut res = self.msb().cmp(&other.msb());
301        if let std::cmp::Ordering::Equal = res {
302            res = self.lsb_signed().cmp(&other.lsb_signed());
303        }
304        res
305    }
306}
307
308impl PartialOrd for CqlTimeuuid {
309    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
310        Some(self.cmp(other))
311    }
312}
313
314impl PartialEq for CqlTimeuuid {
315    fn eq(&self, other: &Self) -> bool {
316        self.cmp(other) == std::cmp::Ordering::Equal
317    }
318}
319
320impl std::hash::Hash for CqlTimeuuid {
321    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
322        self.lsb_signed().hash(state);
323        self.msb().hash(state);
324    }
325}
326
327/// Native CQL `varint` representation.
328///
329/// Represented as two's-complement binary in big-endian order.
330///
331/// This type is a raw representation in bytes. It's the default
332/// implementation of `varint` type - independent of any
333/// external crates and crate features.
334///
335/// The type is not very useful in most use cases.
336/// However, users can make use of more complex types
337/// such as `num_bigint::BigInt` (v0.3/v0.4).
338/// The library support (e.g. conversion from [`CqlValue`]) for these types is
339/// enabled via `num-bigint-03` and `num-bigint-04` crate features.
340///
341/// This struct holds owned bytes. If you wish to borrow the bytes instead,
342/// see [`CqlVarintBorrowed`] documentation.
343///
344/// # DB data format
345/// Notice that [constructors](CqlVarint#impl-CqlVarint)
346/// don't perform any normalization on the provided data.
347/// This means that underlying bytes may contain leading zeros.
348///
349/// Currently, Scylla and Cassandra support non-normalized `varint` values.
350/// Bytes provided by the user via constructor are passed to DB as is.
351///
352/// The implementation of [`PartialEq`], however, normalizes the underlying bytes
353/// before comparison. For details, check [examples](#impl-PartialEq-for-CqlVarint).
354#[derive(Clone, Eq, Debug)]
355pub struct CqlVarint(Vec<u8>);
356
357/// A borrowed version of native CQL `varint` representation.
358///
359/// Refer to the documentation of [`CqlVarint`].
360/// Especially, see the disclaimer about [non-normalized values](CqlVarint#db-data-format).
361#[derive(Clone, Eq, Debug)]
362pub struct CqlVarintBorrowed<'b>(&'b [u8]);
363
364/// Constructors from bytes
365impl CqlVarint {
366    /// Creates a [`CqlVarint`] from an array of bytes in
367    /// two's complement big-endian binary representation.
368    ///
369    /// See: disclaimer about [non-normalized values](CqlVarint#db-data-format).
370    pub fn from_signed_bytes_be(digits: Vec<u8>) -> Self {
371        Self(digits)
372    }
373
374    /// Creates a [`CqlVarint`] from a slice of bytes in
375    /// two's complement binary big-endian representation.
376    ///
377    /// See: disclaimer about [non-normalized values](CqlVarint#db-data-format).
378    pub fn from_signed_bytes_be_slice(digits: &[u8]) -> Self {
379        Self::from_signed_bytes_be(digits.to_vec())
380    }
381}
382
383/// Constructors from bytes
384impl<'b> CqlVarintBorrowed<'b> {
385    /// Creates a [`CqlVarintBorrowed`] from a slice of bytes in
386    /// two's complement binary big-endian representation.
387    ///
388    /// See: disclaimer about [non-normalized values](CqlVarint#db-data-format).
389    pub fn from_signed_bytes_be_slice(digits: &'b [u8]) -> Self {
390        Self(digits)
391    }
392}
393
394/// Conversion to bytes
395impl CqlVarint {
396    /// Converts [`CqlVarint`] to an array of bytes in two's
397    /// complement binary big-endian representation.
398    pub fn into_signed_bytes_be(self) -> Vec<u8> {
399        self.0
400    }
401
402    /// Returns a slice of bytes in two's complement
403    /// binary big-endian representation.
404    pub fn as_signed_bytes_be_slice(&self) -> &[u8] {
405        &self.0
406    }
407}
408
409/// Conversion to bytes
410impl CqlVarintBorrowed<'_> {
411    /// Returns a slice of bytes in two's complement
412    /// binary big-endian representation.
413    pub fn as_signed_bytes_be_slice(&self) -> &[u8] {
414        self.0
415    }
416}
417
418/// An internal utility trait used to implement [`AsNormalizedVarintSlice`]
419/// for both [`CqlVarint`] and [`CqlVarintBorrowed`].
420trait AsVarintSlice {
421    fn as_slice(&self) -> &[u8];
422}
423impl AsVarintSlice for CqlVarint {
424    fn as_slice(&self) -> &[u8] {
425        self.as_signed_bytes_be_slice()
426    }
427}
428impl AsVarintSlice for CqlVarintBorrowed<'_> {
429    fn as_slice(&self) -> &[u8] {
430        self.as_signed_bytes_be_slice()
431    }
432}
433
434/// An internal utility trait used to implement [`PartialEq`] and [`std::hash::Hash`]
435/// for [`CqlVarint`] and [`CqlVarintBorrowed`].
436trait AsNormalizedVarintSlice {
437    fn as_normalized_slice(&self) -> &[u8];
438}
439impl<V: AsVarintSlice> AsNormalizedVarintSlice for V {
440    fn as_normalized_slice(&self) -> &[u8] {
441        let digits = self.as_slice();
442        if digits.is_empty() {
443            // num-bigint crate normalizes empty vector to 0.
444            // We will follow the same approach.
445            return &[0];
446        }
447
448        let non_zero_position = match digits.iter().position(|b| *b != 0) {
449            Some(pos) => pos,
450            None => {
451                // Vector is filled with zeros. Represent it as 0.
452                return &[0];
453            }
454        };
455
456        if non_zero_position > 0 {
457            // There were some leading zeros.
458            // Now, there are two cases:
459            let zeros_to_remove = if digits[non_zero_position] > 0x7f {
460                // Most significant bit is 1, so we need to include one of the leading
461                // zeros as originally it represented a positive number.
462                non_zero_position - 1
463            } else {
464                // Most significant bit is 0 - positive number with no leading zeros.
465                non_zero_position
466            };
467            return &digits[zeros_to_remove..];
468        }
469
470        // There were no leading zeros at all - leave as is.
471        digits
472    }
473}
474
475/// Compares two [`CqlVarint`] values after normalization.
476///
477/// # Example
478///
479/// ```rust
480/// # use scylla_cql_core::value::CqlVarint;
481/// let non_normalized_bytes = vec![0x00, 0x01];
482/// let normalized_bytes = vec![0x01];
483/// assert_eq!(
484///     CqlVarint::from_signed_bytes_be(non_normalized_bytes),
485///     CqlVarint::from_signed_bytes_be(normalized_bytes)
486/// );
487/// ```
488impl PartialEq for CqlVarint {
489    fn eq(&self, other: &Self) -> bool {
490        self.as_normalized_slice() == other.as_normalized_slice()
491    }
492}
493
494/// Computes the hash of normalized [`CqlVarint`].
495impl std::hash::Hash for CqlVarint {
496    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
497        self.as_normalized_slice().hash(state)
498    }
499}
500
501/// Compares two [`CqlVarintBorrowed`] values after normalization.
502///
503/// # Example
504///
505/// ```rust
506/// # use scylla_cql_core::value::CqlVarintBorrowed;
507/// let non_normalized_bytes = &[0x00, 0x01];
508/// let normalized_bytes = &[0x01];
509/// assert_eq!(
510///     CqlVarintBorrowed::from_signed_bytes_be_slice(non_normalized_bytes),
511///     CqlVarintBorrowed::from_signed_bytes_be_slice(normalized_bytes)
512/// );
513/// ```
514impl PartialEq for CqlVarintBorrowed<'_> {
515    fn eq(&self, other: &Self) -> bool {
516        self.as_normalized_slice() == other.as_normalized_slice()
517    }
518}
519
520/// Computes the hash of normalized [`CqlVarintBorrowed`].
521impl std::hash::Hash for CqlVarintBorrowed<'_> {
522    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
523        self.as_normalized_slice().hash(state)
524    }
525}
526
527#[cfg(feature = "num-bigint-03")]
528impl From<num_bigint_03::BigInt> for CqlVarint {
529    fn from(value: num_bigint_03::BigInt) -> Self {
530        Self(value.to_signed_bytes_be())
531    }
532}
533
534#[cfg(feature = "num-bigint-03")]
535impl From<CqlVarint> for num_bigint_03::BigInt {
536    fn from(val: CqlVarint) -> Self {
537        num_bigint_03::BigInt::from_signed_bytes_be(&val.0)
538    }
539}
540
541#[cfg(feature = "num-bigint-03")]
542impl From<CqlVarintBorrowed<'_>> for num_bigint_03::BigInt {
543    fn from(val: CqlVarintBorrowed<'_>) -> Self {
544        num_bigint_03::BigInt::from_signed_bytes_be(val.0)
545    }
546}
547
548#[cfg(feature = "num-bigint-04")]
549impl From<num_bigint_04::BigInt> for CqlVarint {
550    fn from(value: num_bigint_04::BigInt) -> Self {
551        Self(value.to_signed_bytes_be())
552    }
553}
554
555#[cfg(feature = "num-bigint-04")]
556impl From<CqlVarint> for num_bigint_04::BigInt {
557    fn from(val: CqlVarint) -> Self {
558        num_bigint_04::BigInt::from_signed_bytes_be(&val.0)
559    }
560}
561
562#[cfg(feature = "num-bigint-04")]
563impl From<CqlVarintBorrowed<'_>> for num_bigint_04::BigInt {
564    fn from(val: CqlVarintBorrowed<'_>) -> Self {
565        num_bigint_04::BigInt::from_signed_bytes_be(val.0)
566    }
567}
568
569/// Native CQL `decimal` representation.
570///
571/// Represented as a pair:
572/// - a [`CqlVarint`] value
573/// - 32-bit integer which determines the position of the decimal point
574///
575/// This struct holds owned bytes. If you wish to borrow the bytes instead,
576/// see [`CqlDecimalBorrowed`] documentation.
577///
578/// The type is not very useful in most use cases.
579/// However, users can make use of more complex types
580/// such as `bigdecimal::BigDecimal` (v0.4).
581/// The library support (e.g. conversion from [`CqlValue`]) for the type is
582/// enabled via `bigdecimal-04` crate feature.
583///
584/// # DB data format
585/// Notice that [constructors](CqlDecimal#impl-CqlDecimal)
586/// don't perform any normalization on the provided data.
587/// For more details, see [`CqlVarint`] documentation.
588#[derive(Clone, PartialEq, Eq, Debug)]
589pub struct CqlDecimal {
590    int_val: CqlVarint,
591    scale: i32,
592}
593
594/// Borrowed version of native CQL `decimal` representation.
595///
596/// Represented as a pair:
597/// - a [`CqlVarintBorrowed`] value
598/// - 32-bit integer which determines the position of the decimal point
599///
600/// Refer to the documentation of [`CqlDecimal`].
601/// Especially, see the disclaimer about [non-normalized values](CqlDecimal#db-data-format).
602#[derive(Clone, PartialEq, Eq, Debug)]
603pub struct CqlDecimalBorrowed<'b> {
604    int_val: CqlVarintBorrowed<'b>,
605    scale: i32,
606}
607
608/// Constructors
609impl CqlDecimal {
610    /// Creates a [`CqlDecimal`] from an array of bytes
611    /// representing [`CqlVarint`] and a 32-bit scale.
612    ///
613    /// See: disclaimer about [non-normalized values](CqlVarint#db-data-format).
614    pub fn from_signed_be_bytes_and_exponent(bytes: Vec<u8>, scale: i32) -> Self {
615        Self {
616            int_val: CqlVarint::from_signed_bytes_be(bytes),
617            scale,
618        }
619    }
620
621    /// Creates a [`CqlDecimal`] from a slice of bytes
622    /// representing [`CqlVarint`] and a 32-bit scale.
623    ///
624    /// See: disclaimer about [non-normalized values](CqlVarint#db-data-format).
625    pub fn from_signed_be_bytes_slice_and_exponent(bytes: &[u8], scale: i32) -> Self {
626        Self::from_signed_be_bytes_and_exponent(bytes.to_vec(), scale)
627    }
628}
629
630/// Constructors
631impl<'b> CqlDecimalBorrowed<'b> {
632    /// Creates a [`CqlDecimalBorrowed`] from a slice of bytes
633    /// representing [`CqlVarintBorrowed`] and a 32-bit scale.
634    ///
635    /// See: disclaimer about [non-normalized values](CqlVarint#db-data-format).
636    pub fn from_signed_be_bytes_slice_and_exponent(bytes: &'b [u8], scale: i32) -> Self {
637        Self {
638            int_val: CqlVarintBorrowed::from_signed_bytes_be_slice(bytes),
639            scale,
640        }
641    }
642}
643
644/// Conversion to raw bytes
645impl CqlDecimal {
646    /// Returns a slice of bytes in two's complement
647    /// binary big-endian representation and a scale.
648    pub fn as_signed_be_bytes_slice_and_exponent(&self) -> (&[u8], i32) {
649        (self.int_val.as_signed_bytes_be_slice(), self.scale)
650    }
651
652    /// Converts [`CqlDecimal`] to an array of bytes in two's
653    /// complement binary big-endian representation and a scale.
654    pub fn into_signed_be_bytes_and_exponent(self) -> (Vec<u8>, i32) {
655        (self.int_val.into_signed_bytes_be(), self.scale)
656    }
657}
658
659/// Conversion to raw bytes
660impl CqlDecimalBorrowed<'_> {
661    /// Returns a slice of bytes in two's complement
662    /// binary big-endian representation and a scale.
663    pub fn as_signed_be_bytes_slice_and_exponent(&self) -> (&[u8], i32) {
664        (self.int_val.as_signed_bytes_be_slice(), self.scale)
665    }
666}
667
668#[cfg(feature = "bigdecimal-04")]
669impl From<CqlDecimal> for bigdecimal_04::BigDecimal {
670    fn from(value: CqlDecimal) -> Self {
671        Self::from((
672            bigdecimal_04::num_bigint::BigInt::from_signed_bytes_be(
673                value.int_val.as_signed_bytes_be_slice(),
674            ),
675            value.scale as i64,
676        ))
677    }
678}
679
680#[cfg(feature = "bigdecimal-04")]
681impl From<CqlDecimalBorrowed<'_>> for bigdecimal_04::BigDecimal {
682    fn from(value: CqlDecimalBorrowed) -> Self {
683        Self::from((
684            bigdecimal_04::num_bigint::BigInt::from_signed_bytes_be(
685                value.int_val.as_signed_bytes_be_slice(),
686            ),
687            value.scale as i64,
688        ))
689    }
690}
691
692#[cfg(feature = "bigdecimal-04")]
693impl TryFrom<bigdecimal_04::BigDecimal> for CqlDecimal {
694    type Error = <i64 as TryInto<i32>>::Error;
695
696    fn try_from(value: bigdecimal_04::BigDecimal) -> Result<Self, Self::Error> {
697        let (bigint, scale) = value.into_bigint_and_exponent();
698        let bytes = bigint.to_signed_bytes_be();
699        Ok(Self::from_signed_be_bytes_and_exponent(
700            bytes,
701            scale.try_into()?,
702        ))
703    }
704}
705
706/// Native CQL date representation that allows for a bigger range of dates (-262145-1-1 to 262143-12-31).
707///
708/// Represented as number of days since -5877641-06-23 i.e. 2^31 days before unix epoch.
709#[derive(Clone, Copy, PartialEq, Eq, Debug)]
710pub struct CqlDate(pub u32);
711
712/// Native CQL timestamp representation that allows full supported timestamp range.
713///
714/// Represented as signed milliseconds since unix epoch.
715#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
716pub struct CqlTimestamp(pub i64);
717
718/// Native CQL time representation.
719///
720/// Represented as nanoseconds since midnight.
721#[derive(Clone, Copy, PartialEq, Eq, Debug)]
722pub struct CqlTime(pub i64);
723
724impl CqlDate {
725    fn try_to_chrono_04_naive_date(&self) -> Result<chrono_04::NaiveDate, ValueOverflow> {
726        let days_since_unix_epoch = self.0 as i64 - (1 << 31);
727
728        // date_days is u32 then converted to i64 then we subtract 2^31;
729        // Max value is 2^31, min value is -2^31. Both values can safely fit in chrono::Duration, this call won't panic
730        let duration_since_unix_epoch =
731            chrono_04::Duration::try_days(days_since_unix_epoch).unwrap();
732
733        chrono_04::NaiveDate::from_yo_opt(1970, 1)
734            .unwrap()
735            .checked_add_signed(duration_since_unix_epoch)
736            .ok_or(ValueOverflow)
737    }
738}
739
740#[cfg(feature = "chrono-04")]
741impl From<chrono_04::NaiveDate> for CqlDate {
742    fn from(value: chrono_04::NaiveDate) -> Self {
743        let unix_epoch = chrono_04::NaiveDate::from_yo_opt(1970, 1).unwrap();
744
745        // `NaiveDate` range is -262145-01-01 to 262143-12-31
746        // Both values are well within supported range
747        let days = ((1 << 31) + value.signed_duration_since(unix_epoch).num_days()) as u32;
748
749        Self(days)
750    }
751}
752
753#[cfg(feature = "chrono-04")]
754impl TryInto<chrono_04::NaiveDate> for CqlDate {
755    type Error = ValueOverflow;
756
757    fn try_into(self) -> Result<chrono_04::NaiveDate, Self::Error> {
758        self.try_to_chrono_04_naive_date()
759    }
760}
761
762impl CqlTimestamp {
763    /// The earliest representable `CqlTimestamp` (milliseconds = `i64::MIN`).
764    pub const MIN: CqlTimestamp = CqlTimestamp(i64::MIN);
765
766    /// The latest representable `CqlTimestamp` (milliseconds = `i64::MAX`).
767    pub const MAX: CqlTimestamp = CqlTimestamp(i64::MAX);
768
769    /// Returns the current wall-clock time as a `CqlTimestamp`.
770    ///
771    /// The returned value holds the number of milliseconds since the Unix epoch
772    /// (1970-01-01 00:00:00 UTC), matching the CQL `timestamp` type semantics.
773    ///
774    /// This is implemented in terms of [`std::time::SystemTime::now`]
775    /// and is therefore **not monotonic**.
776    /// Because of OS/NTP clock adjustments, a later call to `now()` can return
777    /// a smaller value than an earlier call.
778    /// Do not use `now()` to measure elapsed time;
779    /// use [`std::time::Instant`] for that purpose instead.
780    ///
781    /// # Panics
782    ///
783    /// Panics if the system clock is so far removed from the Unix epoch
784    /// (in either direction) that it cannot be represented as `i64` milliseconds.
785    pub fn now() -> Self {
786        match SystemTime::now().duration_since(UNIX_EPOCH) {
787            Ok(d) => Self(
788                i64::try_from(d.as_millis())
789                    .expect("system clock is too far past the Unix epoch to fit in a CqlTimestamp"),
790            ),
791            Err(e) => {
792                let ms = i64::try_from(e.duration().as_millis()).expect(
793                    "system clock is too far before the Unix epoch to fit in a CqlTimestamp",
794                );
795                // `ms` is the result of converting a `u128` (always non-negative) into `i64`,
796                // so it is in the range [0, i64::MAX]. Negating it therefore cannot overflow.
797                Self(-ms)
798            }
799        }
800    }
801
802    /// Returns the amount of time elapsed from `earlier` to `self`.
803    ///
804    /// Mirrors [`std::time::Instant::checked_duration_since`].
805    /// Returns `None` if `earlier` is actually later than `self`,
806    /// instead of silently saturating at zero, since it is easy to swap
807    /// the operands by mistake.
808    pub fn checked_duration_since(self, earlier: CqlTimestamp) -> Option<std::time::Duration> {
809        if self.0 < earlier.0 {
810            return None;
811        }
812        // The ordering check above guarantees `self.0 >= earlier.0`,
813        // so `abs_diff` gives the correct non-negative `u64` difference even
814        // when it wouldn't fit in `i64` (e.g. MAX - MIN).
815        Some(std::time::Duration::from_millis(self.0.abs_diff(earlier.0)))
816    }
817
818    fn try_to_chrono_04_datetime_utc(
819        &self,
820    ) -> Result<chrono_04::DateTime<chrono_04::Utc>, ValueOverflow> {
821        use chrono_04::TimeZone;
822        match chrono_04::Utc.timestamp_millis_opt(self.0) {
823            chrono_04::LocalResult::Single(datetime) => Ok(datetime),
824            _ => Err(ValueOverflow),
825        }
826    }
827}
828
829impl std::ops::Add<std::time::Duration> for CqlTimestamp {
830    type Output = CqlTimestamp;
831
832    /// # Panics
833    ///
834    /// Panics if the resulting timestamp would overflow `i64` milliseconds.
835    fn add(self, rhs: std::time::Duration) -> CqlTimestamp {
836        let rhs_ms = i128::try_from(rhs.as_millis()).unwrap_or(i128::MAX);
837        let result = i128::from(self.0) + rhs_ms;
838        CqlTimestamp(i64::try_from(result).expect("overflow when adding Duration to CqlTimestamp"))
839    }
840}
841
842impl std::ops::AddAssign<std::time::Duration> for CqlTimestamp {
843    /// # Panics
844    ///
845    /// Panics if the resulting timestamp would overflow `i64` milliseconds.
846    fn add_assign(&mut self, rhs: std::time::Duration) {
847        *self = *self + rhs;
848    }
849}
850
851impl std::ops::Sub<std::time::Duration> for CqlTimestamp {
852    type Output = CqlTimestamp;
853
854    /// # Panics
855    ///
856    /// Panics if the resulting timestamp would overflow `i64` milliseconds.
857    fn sub(self, rhs: std::time::Duration) -> CqlTimestamp {
858        let rhs_ms = i128::try_from(rhs.as_millis()).unwrap_or(i128::MAX);
859        let result = i128::from(self.0) - rhs_ms;
860        CqlTimestamp(
861            i64::try_from(result).expect("overflow when subtracting Duration from CqlTimestamp"),
862        )
863    }
864}
865
866impl std::ops::SubAssign<std::time::Duration> for CqlTimestamp {
867    /// # Panics
868    ///
869    /// Panics if the resulting timestamp would overflow `i64` milliseconds.
870    fn sub_assign(&mut self, rhs: std::time::Duration) {
871        *self = *self - rhs;
872    }
873}
874
875#[cfg(feature = "chrono-04")]
876impl From<chrono_04::DateTime<chrono_04::Utc>> for CqlTimestamp {
877    fn from(value: chrono_04::DateTime<chrono_04::Utc>) -> Self {
878        Self(value.timestamp_millis())
879    }
880}
881
882#[cfg(feature = "chrono-04")]
883impl TryInto<chrono_04::DateTime<chrono_04::Utc>> for CqlTimestamp {
884    type Error = ValueOverflow;
885
886    fn try_into(self) -> Result<chrono_04::DateTime<chrono_04::Utc>, Self::Error> {
887        self.try_to_chrono_04_datetime_utc()
888    }
889}
890
891#[cfg(feature = "chrono-04")]
892impl TryFrom<chrono_04::NaiveTime> for CqlTime {
893    type Error = ValueOverflow;
894
895    fn try_from(value: chrono_04::NaiveTime) -> Result<Self, Self::Error> {
896        let nanos = value
897            .signed_duration_since(chrono_04::NaiveTime::MIN)
898            .num_nanoseconds()
899            .unwrap();
900
901        // Value can exceed max CQL time in case of leap second
902        if nanos <= 86399999999999 {
903            Ok(Self(nanos))
904        } else {
905            Err(ValueOverflow)
906        }
907    }
908}
909
910#[cfg(feature = "chrono-04")]
911impl TryInto<chrono_04::NaiveTime> for CqlTime {
912    type Error = ValueOverflow;
913
914    fn try_into(self) -> Result<chrono_04::NaiveTime, Self::Error> {
915        let secs = (self.0 / 1_000_000_000)
916            .try_into()
917            .map_err(|_| ValueOverflow)?;
918        let nanos = (self.0 % 1_000_000_000)
919            .try_into()
920            .map_err(|_| ValueOverflow)?;
921        chrono_04::NaiveTime::from_num_seconds_from_midnight_opt(secs, nanos).ok_or(ValueOverflow)
922    }
923}
924
925#[cfg(feature = "time-03")]
926impl From<time_03::Date> for CqlDate {
927    fn from(value: time_03::Date) -> Self {
928        const JULIAN_DAY_OFFSET: i64 =
929            (1 << 31) - time_03::OffsetDateTime::UNIX_EPOCH.date().to_julian_day() as i64;
930
931        // Statically assert that no possible value will ever overflow
932        const _: () = assert!(
933            time_03::Date::MAX.to_julian_day() as i64 + JULIAN_DAY_OFFSET < u32::MAX as i64
934        );
935        const _: () = assert!(
936            time_03::Date::MIN.to_julian_day() as i64 + JULIAN_DAY_OFFSET > u32::MIN as i64
937        );
938
939        let days = value.to_julian_day() as i64 + JULIAN_DAY_OFFSET;
940
941        Self(days as u32)
942    }
943}
944
945#[cfg(feature = "time-03")]
946impl TryInto<time_03::Date> for CqlDate {
947    type Error = ValueOverflow;
948
949    fn try_into(self) -> Result<time_03::Date, Self::Error> {
950        const JULIAN_DAY_OFFSET: i64 =
951            (1 << 31) - time_03::OffsetDateTime::UNIX_EPOCH.date().to_julian_day() as i64;
952
953        let julian_days = (self.0 as i64 - JULIAN_DAY_OFFSET)
954            .try_into()
955            .map_err(|_| ValueOverflow)?;
956
957        time_03::Date::from_julian_day(julian_days).map_err(|_| ValueOverflow)
958    }
959}
960
961#[cfg(feature = "time-03")]
962impl From<time_03::OffsetDateTime> for CqlTimestamp {
963    fn from(value: time_03::OffsetDateTime) -> Self {
964        // Statically assert that no possible value will ever overflow. OffsetDateTime doesn't allow offset to overflow
965        // the UTC PrimitiveDateTime value value
966        const _: () = assert!(
967            time_03::PrimitiveDateTime::MAX
968                .assume_utc()
969                .unix_timestamp_nanos()
970                // Nanos to millis
971                / 1_000_000
972                < i64::MAX as i128
973        );
974        const _: () = assert!(
975            time_03::PrimitiveDateTime::MIN
976                .assume_utc()
977                .unix_timestamp_nanos()
978                / 1_000_000
979                > i64::MIN as i128
980        );
981
982        // Edge cases were statically asserted above, checked math is not required
983        Self(value.unix_timestamp() * 1000 + value.millisecond() as i64)
984    }
985}
986
987#[cfg(feature = "time-03")]
988impl TryInto<time_03::OffsetDateTime> for CqlTimestamp {
989    type Error = ValueOverflow;
990
991    fn try_into(self) -> Result<time_03::OffsetDateTime, Self::Error> {
992        time_03::OffsetDateTime::from_unix_timestamp_nanos(self.0 as i128 * 1_000_000)
993            .map_err(|_| ValueOverflow)
994    }
995}
996
997#[cfg(feature = "time-03")]
998impl From<time_03::Time> for CqlTime {
999    fn from(value: time_03::Time) -> Self {
1000        let (h, m, s, n) = value.as_hms_nano();
1001
1002        // no need for checked arithmetic as all these types are guaranteed to fit in i64 without overflow
1003        let nanos = (h as i64 * 3600 + m as i64 * 60 + s as i64) * 1_000_000_000 + n as i64;
1004
1005        Self(nanos)
1006    }
1007}
1008
1009#[cfg(feature = "time-03")]
1010impl TryInto<time_03::Time> for CqlTime {
1011    type Error = ValueOverflow;
1012
1013    fn try_into(self) -> Result<time_03::Time, Self::Error> {
1014        let h = self.0 / 3_600_000_000_000;
1015        let m = self.0 / 60_000_000_000 % 60;
1016        let s = self.0 / 1_000_000_000 % 60;
1017        let n = self.0 % 1_000_000_000;
1018
1019        time_03::Time::from_hms_nano(
1020            h.try_into().map_err(|_| ValueOverflow)?,
1021            m as u8,
1022            s as u8,
1023            n as u32,
1024        )
1025        .map_err(|_| ValueOverflow)
1026    }
1027}
1028
1029/// Represents a CQL Duration value
1030#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1031pub struct CqlDuration {
1032    /// Number of months.
1033    pub months: i32,
1034    /// Number of days.
1035    pub days: i32,
1036    /// Number of nanoseconds.
1037    pub nanoseconds: i64,
1038}
1039
1040/// Represents all possible CQL values that can be returned by the database.
1041///
1042/// This type can represent a CQL value of any type. Therefore, it should be used in places
1043/// where dynamic capabilities are needed, while, for efficiency purposes, avoided in places
1044/// where the type of the value is known in the compile time.
1045#[derive(Clone, Debug, PartialEq)]
1046#[non_exhaustive]
1047pub enum CqlValue {
1048    /// ASCII-only string.
1049    Ascii(String),
1050    /// Boolean value.
1051    Boolean(bool),
1052    /// Binary data of any length.
1053    Blob(Vec<u8>),
1054    /// Counter value, represented as a 64-bit integer.
1055    Counter(Counter),
1056    /// Variable-precision decimal.
1057    Decimal(CqlDecimal),
1058    /// Days since -5877641-06-23 i.e. 2^31 days before unix epoch
1059    /// Can be converted to chrono::NaiveDate (-262145-1-1 to 262143-12-31) using [TryInto].
1060    Date(CqlDate),
1061    /// 64-bit IEEE-754 floating point number.
1062    Double(f64),
1063    /// A duration with nanosecond precision.
1064    Duration(CqlDuration),
1065    /// An empty value, which is distinct from null and is some DB legacy.
1066    Empty,
1067    /// 32-bit IEEE-754 floating point number.
1068    Float(f32),
1069    /// 32-bit signed integer.
1070    Int(i32),
1071    /// 64-bit signed integer.
1072    BigInt(i64),
1073    /// UTF-8 encoded string.
1074    Text(String),
1075    /// Milliseconds since unix epoch.
1076    Timestamp(CqlTimestamp),
1077    /// IPv4 or IPv6 address.
1078    Inet(IpAddr),
1079    /// A list of CQL values of the same types.
1080    List(Vec<CqlValue>),
1081    /// A map of CQL values, whose all keys have the same type
1082    /// and all values have the same type.
1083    Map(Vec<(CqlValue, CqlValue)>),
1084    /// A set of CQL values of the same types.
1085    Set(Vec<CqlValue>),
1086    /// A user-defined type (UDT) value.
1087    /// UDT is composed of fields, each with a name
1088    /// and an optional value of its own type.
1089    UserDefinedType {
1090        /// Keyspace the type belongs to.
1091        keyspace: String,
1092        /// Name of the user-defined type.
1093        name: String,
1094        /// Fields of the user-defined type - (name, value) pairs.
1095        fields: Vec<(String, Option<CqlValue>)>,
1096    },
1097    /// 16-bit signed integer.
1098    SmallInt(i16),
1099    /// 8-bit signed integer.
1100    TinyInt(i8),
1101    /// Nanoseconds since midnight.
1102    Time(CqlTime),
1103    /// Version 1 UUID, generally used as a "conflict-free" timestamp.
1104    Timeuuid(CqlTimeuuid),
1105    /// A tuple of CQL values of independent types each, where each element can be `None`
1106    /// if the value is null. The length of the tuple is part of its CQL type.
1107    Tuple(Vec<Option<CqlValue>>),
1108    /// Universally unique identifier (UUID) of any version.
1109    Uuid(Uuid),
1110    /// Arbitrary-precision integer.
1111    Varint(CqlVarint),
1112    /// A vector of CQL values of the same type.
1113    /// The length of the vector is part of its CQL type.
1114    Vector(Vec<CqlValue>),
1115}
1116
1117impl CqlValue {
1118    /// Casts the value to ASCII string if it is of that type.
1119    pub fn as_ascii(&self) -> Option<&String> {
1120        match self {
1121            Self::Ascii(s) => Some(s),
1122            _ => None,
1123        }
1124    }
1125
1126    /// Casts the value to CQL Date if it is of that type.
1127    pub fn as_cql_date(&self) -> Option<CqlDate> {
1128        match self {
1129            Self::Date(d) => Some(*d),
1130            _ => None,
1131        }
1132    }
1133
1134    /// Casts the value to CQL Timestamp if it is of that type.
1135    pub fn as_cql_timestamp(&self) -> Option<CqlTimestamp> {
1136        match self {
1137            Self::Timestamp(i) => Some(*i),
1138            _ => None,
1139        }
1140    }
1141
1142    /// Casts the value to CQL Time if it is of that type.
1143    pub fn as_cql_time(&self) -> Option<CqlTime> {
1144        match self {
1145            Self::Time(i) => Some(*i),
1146            _ => None,
1147        }
1148    }
1149
1150    /// Casts the value to CQL Duration if it is of that type.
1151    pub fn as_cql_duration(&self) -> Option<CqlDuration> {
1152        match self {
1153            Self::Duration(i) => Some(*i),
1154            _ => None,
1155        }
1156    }
1157
1158    /// Casts the value to CQL Counter if it is of that type.
1159    pub fn as_counter(&self) -> Option<Counter> {
1160        match self {
1161            Self::Counter(i) => Some(*i),
1162            _ => None,
1163        }
1164    }
1165
1166    /// Casts the value to bool if it is of that type.
1167    pub fn as_boolean(&self) -> Option<bool> {
1168        match self {
1169            Self::Boolean(i) => Some(*i),
1170            _ => None,
1171        }
1172    }
1173
1174    /// Casts the value to double-precision float if it is of that type.
1175    pub fn as_double(&self) -> Option<f64> {
1176        match self {
1177            Self::Double(d) => Some(*d),
1178            _ => None,
1179        }
1180    }
1181
1182    /// Casts the value to UUID if it is of that type.
1183    pub fn as_uuid(&self) -> Option<Uuid> {
1184        match self {
1185            Self::Uuid(u) => Some(*u),
1186            _ => None,
1187        }
1188    }
1189
1190    /// Casts the value to single-precision float if it is of that type.
1191    pub fn as_float(&self) -> Option<f32> {
1192        match self {
1193            Self::Float(f) => Some(*f),
1194            _ => None,
1195        }
1196    }
1197
1198    /// Casts the value to 32-bit signed integer if it is of that type.
1199    pub fn as_int(&self) -> Option<i32> {
1200        match self {
1201            Self::Int(i) => Some(*i),
1202            _ => None,
1203        }
1204    }
1205
1206    /// Casts the value to 64-bit signed integer if it is of that type.
1207    pub fn as_bigint(&self) -> Option<i64> {
1208        match self {
1209            Self::BigInt(i) => Some(*i),
1210            _ => None,
1211        }
1212    }
1213
1214    /// Casts the value to 8-bit signed integer if it is of that type.
1215    pub fn as_tinyint(&self) -> Option<i8> {
1216        match self {
1217            Self::TinyInt(i) => Some(*i),
1218            _ => None,
1219        }
1220    }
1221
1222    /// Casts the value to 16-bit signed integer if it is of that type.
1223    pub fn as_smallint(&self) -> Option<i16> {
1224        match self {
1225            Self::SmallInt(i) => Some(*i),
1226            _ => None,
1227        }
1228    }
1229
1230    /// Casts the value to a byte sequence if it is of `blob` type.
1231    pub fn as_blob(&self) -> Option<&Vec<u8>> {
1232        match self {
1233            Self::Blob(v) => Some(v),
1234            _ => None,
1235        }
1236    }
1237
1238    /// Casts the value to UTF-8 encoded string if it is of `text` type.
1239    pub fn as_text(&self) -> Option<&String> {
1240        match self {
1241            Self::Text(s) => Some(s),
1242            _ => None,
1243        }
1244    }
1245
1246    /// Casts the value to CQL Timeuuid if it is of that type.
1247    pub fn as_timeuuid(&self) -> Option<CqlTimeuuid> {
1248        match self {
1249            Self::Timeuuid(u) => Some(*u),
1250            _ => None,
1251        }
1252    }
1253
1254    /// Converts the value to string if it is of `ascii` or `text` type.
1255    pub fn into_string(self) -> Option<String> {
1256        match self {
1257            Self::Ascii(s) => Some(s),
1258            Self::Text(s) => Some(s),
1259            _ => None,
1260        }
1261    }
1262
1263    /// Converts the value to a byte sequence if it is of `blob` type.
1264    pub fn into_blob(self) -> Option<Vec<u8>> {
1265        match self {
1266            Self::Blob(b) => Some(b),
1267            _ => None,
1268        }
1269    }
1270
1271    /// Casts the value to an IP address if it is of `inet` type.
1272    pub fn as_inet(&self) -> Option<IpAddr> {
1273        match self {
1274            Self::Inet(a) => Some(*a),
1275            _ => None,
1276        }
1277    }
1278
1279    /// Casts the value to a vec of CQL values if it is of `list` type.
1280    pub fn as_list(&self) -> Option<&Vec<CqlValue>> {
1281        match self {
1282            Self::List(s) => Some(s),
1283            _ => None,
1284        }
1285    }
1286
1287    /// Casts the value to a vec of CQL values if it is of `set` type.
1288    pub fn as_set(&self) -> Option<&Vec<CqlValue>> {
1289        match self {
1290            Self::Set(s) => Some(s),
1291            _ => None,
1292        }
1293    }
1294
1295    /// Casts the value to a vec of CQL values if it is of `vector` type.
1296    pub fn as_vector(&self) -> Option<&Vec<CqlValue>> {
1297        match self {
1298            Self::Vector(s) => Some(s),
1299            _ => None,
1300        }
1301    }
1302
1303    /// Casts the value to a vec of pairs of CQL values if it is of `map` type,
1304    /// where each pair is a key-value pair.
1305    pub fn as_map(&self) -> Option<&Vec<(CqlValue, CqlValue)>> {
1306        match self {
1307            Self::Map(s) => Some(s),
1308            _ => None,
1309        }
1310    }
1311
1312    /// Casts the value to a user-defined type (UDT) if it is of that type.
1313    /// The UDT is represented as a vector of pairs,
1314    /// where each pair consists of a field name and an optional (=nullable) value.
1315    pub fn as_udt(&self) -> Option<&Vec<(String, Option<CqlValue>)>> {
1316        match self {
1317            Self::UserDefinedType { fields, .. } => Some(fields),
1318            _ => None,
1319        }
1320    }
1321
1322    /// Converts the value to a vector of CQL values if it is of `list`, `set`, or `vector` type.
1323    pub fn into_vec(self) -> Option<Vec<CqlValue>> {
1324        match self {
1325            Self::List(s) => Some(s),
1326            Self::Set(s) => Some(s),
1327            Self::Vector(s) => Some(s),
1328            _ => None,
1329        }
1330    }
1331
1332    /// Converts the value to a vec of pairs of CQL values if it is of `map` type,
1333    /// where each pair is a key-value pair.
1334    pub fn into_pair_vec(self) -> Option<Vec<(CqlValue, CqlValue)>> {
1335        match self {
1336            Self::Map(s) => Some(s),
1337            _ => None,
1338        }
1339    }
1340
1341    /// Converts the value to a vec of pairs if it is a user-defined type (UDT).
1342    /// Each pair consists of a field name and an optional (=nullable) value.
1343    pub fn into_udt_pair_vec(self) -> Option<Vec<(String, Option<CqlValue>)>> {
1344        match self {
1345            Self::UserDefinedType { fields, .. } => Some(fields),
1346            _ => None,
1347        }
1348    }
1349
1350    /// Converts the value to CQL Varint if it is of that type.
1351    pub fn into_cql_varint(self) -> Option<CqlVarint> {
1352        match self {
1353            Self::Varint(i) => Some(i),
1354            _ => None,
1355        }
1356    }
1357
1358    /// Converts the value to CQL Decimal if it is of that type.
1359    pub fn into_cql_decimal(self) -> Option<CqlDecimal> {
1360        match self {
1361            Self::Decimal(i) => Some(i),
1362            _ => None,
1363        }
1364    }
1365    // TODO
1366}
1367
1368/// Displays a CqlValue. The syntax should resemble the CQL literal syntax
1369/// (but no guarantee is given that it's always the same).
1370impl std::fmt::Display for CqlValue {
1371    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1372        use crate::pretty::{
1373            CqlStringLiteralDisplayer, HexBytes, MaybeNullDisplayer, PairDisplayer,
1374        };
1375
1376        match self {
1377            // Scalar types
1378            CqlValue::Ascii(a) => write!(f, "{}", CqlStringLiteralDisplayer(a))?,
1379            CqlValue::Text(t) => write!(f, "{}", CqlStringLiteralDisplayer(t))?,
1380            CqlValue::Blob(b) => write!(f, "0x{:x}", HexBytes(b))?,
1381            CqlValue::Empty => write!(f, "0x")?,
1382            CqlValue::Decimal(d) => {
1383                let (bytes, scale) = d.as_signed_be_bytes_slice_and_exponent();
1384                write!(
1385                    f,
1386                    "blobAsDecimal(0x{:x}{:x})",
1387                    HexBytes(&scale.to_be_bytes()),
1388                    HexBytes(bytes)
1389                )?
1390            }
1391            CqlValue::Float(fl) => write!(f, "{fl}")?,
1392            CqlValue::Double(d) => write!(f, "{d}")?,
1393            CqlValue::Boolean(b) => write!(f, "{b}")?,
1394            CqlValue::Int(i) => write!(f, "{i}")?,
1395            CqlValue::BigInt(bi) => write!(f, "{bi}")?,
1396            CqlValue::Inet(i) => write!(f, "'{i}'")?,
1397            CqlValue::SmallInt(si) => write!(f, "{si}")?,
1398            CqlValue::TinyInt(ti) => write!(f, "{ti}")?,
1399            CqlValue::Varint(vi) => write!(
1400                f,
1401                "blobAsVarint(0x{:x})",
1402                HexBytes(vi.as_signed_bytes_be_slice())
1403            )?,
1404            CqlValue::Counter(c) => write!(f, "{}", c.0)?,
1405            CqlValue::Date(d) => {
1406                // TODO: chrono::NaiveDate does not handle the whole range
1407                // supported by the `date` datatype
1408                match d.try_to_chrono_04_naive_date() {
1409                    Ok(d) => write!(f, "'{d}'")?,
1410                    Err(_) => f.write_str("<date out of representable range>")?,
1411                }
1412            }
1413            CqlValue::Duration(d) => write!(f, "{}mo{}d{}ns", d.months, d.days, d.nanoseconds)?,
1414            CqlValue::Time(CqlTime(t)) => {
1415                write!(
1416                    f,
1417                    "'{:02}:{:02}:{:02}.{:09}'",
1418                    t / 3_600_000_000_000,
1419                    t / 60_000_000_000 % 60,
1420                    t / 1_000_000_000 % 60,
1421                    t % 1_000_000_000,
1422                )?;
1423            }
1424            CqlValue::Timestamp(ts) => match ts.try_to_chrono_04_datetime_utc() {
1425                Ok(d) => write!(f, "{}", d.format("'%Y-%m-%d %H:%M:%S%.3f%z'"))?,
1426                Err(_) => f.write_str("<timestamp out of representable range>")?,
1427            },
1428            CqlValue::Timeuuid(t) => write!(f, "{t}")?,
1429            CqlValue::Uuid(u) => write!(f, "{u}")?,
1430
1431            // Compound types
1432            CqlValue::Tuple(t) => {
1433                f.write_str("(")?;
1434                t.iter()
1435                    .map(|x| MaybeNullDisplayer(x.as_ref()))
1436                    .safe_format(",")
1437                    .fmt(f)?;
1438                f.write_str(")")?;
1439            }
1440            CqlValue::List(v) | CqlValue::Vector(v) => {
1441                f.write_str("[")?;
1442                v.iter().safe_format(",").fmt(f)?;
1443                f.write_str("]")?;
1444            }
1445            CqlValue::Set(v) => {
1446                f.write_str("{")?;
1447                v.iter().safe_format(",").fmt(f)?;
1448                f.write_str("}")?;
1449            }
1450            CqlValue::Map(m) => {
1451                f.write_str("{")?;
1452                m.iter()
1453                    .map(|(k, v)| PairDisplayer(k, v))
1454                    .safe_format(",")
1455                    .fmt(f)?;
1456                f.write_str("}")?;
1457            }
1458            CqlValue::UserDefinedType {
1459                keyspace: _,
1460                name: _,
1461                fields,
1462            } => {
1463                f.write_str("{")?;
1464                fields
1465                    .iter()
1466                    .map(|(k, v)| PairDisplayer(k, MaybeNullDisplayer(v.as_ref())))
1467                    .safe_format(",")
1468                    .fmt(f)?;
1469                f.write_str("}")?;
1470            }
1471        }
1472        Ok(())
1473    }
1474}
1475
1476/// A row in a CQL result set, containing a vector of columns.
1477/// Each column can be either a `CqlValue` or `None` if the column
1478/// is null.
1479///
1480/// This type can represent any row:
1481/// - with any number of columns,
1482/// - with any column types.
1483///
1484/// Therefore, this type should be used in places where dynamic capabilities are needed,
1485/// while, for efficiency purposes, avoided in places where the row structure is known at compile time.
1486#[derive(Debug, Default, PartialEq)]
1487pub struct Row {
1488    /// A vector of columns in the row.
1489    ///
1490    /// Each column is represented as an `Option<CqlValue>`, where `None` indicates a null value.
1491    pub columns: Vec<Option<CqlValue>>,
1492}
1493
1494#[cfg(test)]
1495mod tests {
1496    use std::str::FromStr as _;
1497    use std::time::Duration;
1498
1499    use super::*;
1500
1501    #[test]
1502    fn timeuuid_msb_byte_order() {
1503        let uuid = CqlTimeuuid::from_str("00010203-0405-0607-0809-0a0b0c0d0e0f").unwrap();
1504
1505        assert_eq!(0x0607040500010203, uuid.msb());
1506    }
1507
1508    #[test]
1509    fn timeuuid_msb_clears_version_bits() {
1510        // UUID version nibble should be cleared
1511        let uuid = CqlTimeuuid::from_str("ffffffff-ffff-ffff-ffff-ffffffffffff").unwrap();
1512
1513        assert_eq!(0x0fffffffffffffff, uuid.msb());
1514    }
1515
1516    #[test]
1517    fn timeuuid_lsb_byte_order() {
1518        let uuid = CqlTimeuuid::from_str("00010203-0405-0607-0809-0a0b0c0d0e0f").unwrap();
1519
1520        assert_eq!(0x08090a0b0c0d0e0f, uuid.lsb());
1521    }
1522
1523    #[test]
1524    fn timeuuid_lsb_modifies_no_bits() {
1525        let uuid = CqlTimeuuid::from_str("ffffffff-ffff-ffff-ffff-ffffffffffff").unwrap();
1526
1527        assert_eq!(0xffffffffffffffff, uuid.lsb());
1528    }
1529
1530    #[test]
1531    fn timeuuid_nil() {
1532        let uuid = CqlTimeuuid::nil();
1533
1534        assert_eq!(0x0000000000000000, uuid.msb());
1535        assert_eq!(0x0000000000000000, uuid.lsb());
1536    }
1537
1538    #[test]
1539    fn test_cql_value_displayer() {
1540        assert_eq!(format!("{}", CqlValue::Boolean(true)), "true");
1541        assert_eq!(format!("{}", CqlValue::Int(123)), "123");
1542        assert_eq!(
1543            format!(
1544                "{}",
1545                // 123.456
1546                CqlValue::Decimal(CqlDecimal::from_signed_be_bytes_and_exponent(
1547                    vec![0x01, 0xE2, 0x40],
1548                    3
1549                ))
1550            ),
1551            "blobAsDecimal(0x0000000301e240)"
1552        );
1553        assert_eq!(format!("{}", CqlValue::Float(12.75)), "12.75");
1554        assert_eq!(
1555            format!("{}", CqlValue::Text("Ala ma kota".to_owned())),
1556            "'Ala ma kota'"
1557        );
1558        assert_eq!(
1559            format!("{}", CqlValue::Text("Foo's".to_owned())),
1560            "'Foo''s'"
1561        );
1562
1563        // Time types are the most tricky
1564        assert_eq!(
1565            format!("{}", CqlValue::Date(CqlDate(40 + (1 << 31)))),
1566            "'1970-02-10'"
1567        );
1568        assert_eq!(
1569            format!(
1570                "{}",
1571                CqlValue::Duration(CqlDuration {
1572                    months: 1,
1573                    days: 2,
1574                    nanoseconds: 3,
1575                })
1576            ),
1577            "1mo2d3ns"
1578        );
1579        let t = chrono_04::NaiveTime::from_hms_nano_opt(6, 5, 4, 123)
1580            .unwrap()
1581            .signed_duration_since(chrono_04::NaiveTime::MIN);
1582        let t = t.num_nanoseconds().unwrap();
1583        assert_eq!(
1584            format!("{}", CqlValue::Time(CqlTime(t))),
1585            "'06:05:04.000000123'"
1586        );
1587
1588        let t = chrono_04::NaiveDate::from_ymd_opt(2005, 4, 2)
1589            .unwrap()
1590            .and_time(chrono_04::NaiveTime::from_hms_opt(19, 37, 42).unwrap());
1591        assert_eq!(
1592            format!(
1593                "{}",
1594                CqlValue::Timestamp(CqlTimestamp(
1595                    t.signed_duration_since(chrono_04::NaiveDateTime::default())
1596                        .num_milliseconds()
1597                ))
1598            ),
1599            "'2005-04-02 19:37:42.000+0000'"
1600        );
1601
1602        // Compound types
1603        let list_or_set = vec![CqlValue::Int(1), CqlValue::Int(3), CqlValue::Int(2)];
1604        assert_eq!(
1605            format!("{}", CqlValue::List(list_or_set.clone())),
1606            "[1,3,2]"
1607        );
1608        assert_eq!(format!("{}", CqlValue::Set(list_or_set.clone())), "{1,3,2}");
1609
1610        let tuple: Vec<_> = list_or_set
1611            .into_iter()
1612            .map(Some)
1613            .chain(std::iter::once(None))
1614            .collect();
1615        assert_eq!(format!("{}", CqlValue::Tuple(tuple)), "(1,3,2,null)");
1616
1617        let map = vec![
1618            (CqlValue::Text("foo".to_owned()), CqlValue::Int(123)),
1619            (CqlValue::Text("bar".to_owned()), CqlValue::Int(321)),
1620        ];
1621        assert_eq!(format!("{}", CqlValue::Map(map)), "{'foo':123,'bar':321}");
1622
1623        let fields = vec![
1624            ("foo".to_owned(), Some(CqlValue::Int(123))),
1625            ("bar".to_owned(), Some(CqlValue::Int(321))),
1626        ];
1627        assert_eq!(
1628            format!(
1629                "{}",
1630                CqlValue::UserDefinedType {
1631                    keyspace: "ks".to_owned(),
1632                    name: "typ".to_owned(),
1633                    fields,
1634                }
1635            ),
1636            "{foo:123,bar:321}"
1637        );
1638    }
1639
1640    #[test]
1641    fn cql_timestamp_sentinels() {
1642        assert_eq!(CqlTimestamp::MIN.0, i64::MIN);
1643        assert_eq!(CqlTimestamp::MAX.0, i64::MAX);
1644    }
1645
1646    #[test]
1647    fn cql_timestamp_add_duration() {
1648        let epoch = CqlTimestamp(0);
1649        assert_eq!(epoch + Duration::from_millis(1_000), CqlTimestamp(1_000));
1650        assert_eq!(epoch + Duration::from_secs(1), CqlTimestamp(1_000));
1651
1652        let t = CqlTimestamp(1_000);
1653        assert_eq!(t + Duration::from_millis(500), CqlTimestamp(1_500));
1654    }
1655
1656    #[test]
1657    #[should_panic]
1658    fn cql_timestamp_add_duration_panics_on_overflow() {
1659        let _ = CqlTimestamp::MAX + Duration::from_millis(1);
1660    }
1661
1662    #[test]
1663    fn cql_timestamp_add_duration_does_not_panic_when_result_fits() {
1664        assert_eq!(
1665            CqlTimestamp::MIN + Duration::from_millis(u64::MAX),
1666            CqlTimestamp::MAX
1667        );
1668    }
1669
1670    #[test]
1671    fn cql_timestamp_sub_duration() {
1672        let t = CqlTimestamp(2_000);
1673        assert_eq!(t - Duration::from_millis(500), CqlTimestamp(1_500));
1674        assert_eq!(t - Duration::from_secs(1), CqlTimestamp(1_000));
1675        assert_eq!(t - Duration::from_millis(2_000), CqlTimestamp(0));
1676    }
1677
1678    #[test]
1679    #[should_panic]
1680    fn cql_timestamp_sub_duration_panics_on_overflow() {
1681        let _ = CqlTimestamp::MIN - Duration::from_millis(1);
1682    }
1683
1684    #[test]
1685    fn cql_timestamp_sub_duration_does_not_panic_when_result_fits() {
1686        assert_eq!(
1687            CqlTimestamp::MAX - Duration::from_millis(u64::MAX),
1688            CqlTimestamp::MIN
1689        );
1690    }
1691
1692    #[test]
1693    fn cql_timestamp_add_assign_and_sub_assign() {
1694        let mut t = CqlTimestamp(1_000);
1695        t += Duration::from_millis(500);
1696        assert_eq!(t, CqlTimestamp(1_500));
1697        t -= Duration::from_millis(1_500);
1698        assert_eq!(t, CqlTimestamp(0));
1699    }
1700
1701    #[test]
1702    fn cql_timestamp_checked_duration_since() {
1703        let later = CqlTimestamp(3_000);
1704        let earlier = CqlTimestamp(1_000);
1705        assert_eq!(
1706            later.checked_duration_since(earlier),
1707            Some(Duration::from_millis(2_000))
1708        );
1709        assert_eq!(
1710            later.checked_duration_since(CqlTimestamp(0)),
1711            Some(Duration::from_millis(3_000))
1712        );
1713    }
1714
1715    #[test]
1716    fn cql_timestamp_checked_duration_since_none_when_earlier_is_later() {
1717        let earlier = CqlTimestamp(1_000);
1718        let later = CqlTimestamp(3_000);
1719        assert_eq!(earlier.checked_duration_since(later), None);
1720    }
1721
1722    #[test]
1723    fn cql_timestamp_checked_duration_since_no_overflow_on_extreme_range() {
1724        let diff = CqlTimestamp::MAX
1725            .checked_duration_since(CqlTimestamp::MIN)
1726            .unwrap();
1727        // MAX - MIN = i64::MAX - i64::MIN = u64::MAX, which is the full
1728        // non-negative range and must not be truncated to i64::MAX.
1729        assert_eq!(diff, Duration::from_millis(u64::MAX));
1730    }
1731}