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