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