Skip to main content

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