cassandra_protocol/types/
duration.rs

1use integer_encoding::VarInt;
2use std::io::{Cursor, Write};
3use thiserror::Error;
4
5use crate::frame::{Serialize, Version};
6
7/// Possible `Duration` creation error.
8#[derive(Debug, Error, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
9pub enum DurationCreationError {
10    #[error(
11        "All values must be either negative or positive, got {months} months, {days} days, {nanoseconds} nanoseconds"
12    )]
13    MixedPositiveAndNegative {
14        months: i32,
15        days: i32,
16        nanoseconds: i64,
17    },
18}
19
20/// Cassandra Duration type. A duration stores separately months, days, and seconds due to the fact
21/// that the number of days in a month varies, and a day can have 23 or 25 hours if a daylight
22/// saving is involved.
23#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
24pub struct Duration {
25    months: i32,
26    days: i32,
27    nanoseconds: i64,
28}
29
30impl Duration {
31    pub fn new(months: i32, days: i32, nanoseconds: i64) -> Result<Self, DurationCreationError> {
32        if (months < 0 || days < 0 || nanoseconds < 0)
33            && (months > 0 || days > 0 || nanoseconds > 0)
34        {
35            Err(DurationCreationError::MixedPositiveAndNegative {
36                months,
37                days,
38                nanoseconds,
39            })
40        } else {
41            Ok(Self {
42                months,
43                days,
44                nanoseconds,
45            })
46        }
47    }
48
49    pub fn months(&self) -> i32 {
50        self.months
51    }
52
53    pub fn days(&self) -> i32 {
54        self.days
55    }
56
57    pub fn nanoseconds(&self) -> i64 {
58        self.nanoseconds
59    }
60}
61
62impl Serialize for Duration {
63    fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, _version: Version) {
64        let month_space = self.months.required_space();
65        let day_space = self.days.required_space();
66
67        let mut buffer = vec![0u8; month_space + day_space + self.nanoseconds.required_space()];
68
69        self.months.encode_var(&mut buffer);
70        self.days.encode_var(&mut buffer[month_space..]);
71        self.nanoseconds
72            .encode_var(&mut buffer[(month_space + day_space)..]);
73
74        let _ = cursor.write(&buffer);
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use crate::frame::{Serialize, Version};
81    use crate::types::duration::Duration;
82
83    #[test]
84    fn should_serialize_duration() {
85        let duration = Duration::new(100, 200, 300).unwrap();
86        assert_eq!(
87            duration.serialize_to_vec(Version::V5),
88            vec![200, 1, 144, 3, 216, 4]
89        );
90    }
91}