1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3
4use core::cmp::{Ord, Ordering, PartialOrd};
5use time::OffsetDateTime;
6
7use crate::TickValue;
8
9#[cfg(feature = "serde")]
10mod rfc3339 {
11    use serde::{Deserializer, Serializer};
12    use time::{serde::rfc3339, OffsetDateTime};
13
14    pub(super) fn serialize<S: Serializer>(
16        datetime: &Option<OffsetDateTime>,
17        serializer: S,
18    ) -> Result<S::Ok, S::Error> {
19        match datetime {
20            Some(datetime) => rfc3339::serialize(datetime, serializer),
21            None => serializer.serialize_none(),
22        }
23    }
24
25    pub(super) fn deserialize<'a, D: Deserializer<'a>>(
27        deserializer: D,
28    ) -> Result<Option<OffsetDateTime>, D::Error> {
29        struct Visitor;
30
31        impl<'de> serde::de::Visitor<'de> for Visitor {
32            type Value = Option<OffsetDateTime>;
33
34            fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
35                write!(f, "a optional timestamp str in RFC3339 format")
36            }
37
38            fn visit_none<E>(self) -> Result<Self::Value, E>
39            where
40                E: serde::de::Error,
41            {
42                Ok(None)
43            }
44
45            fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
46            where
47                D: Deserializer<'de>,
48            {
49                Ok(Some(rfc3339::deserialize(deserializer)?))
50            }
51        }
52
53        deserializer.deserialize_option(Visitor)
54    }
55}
56
57#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub struct Tick(#[cfg_attr(feature = "serde", serde(with = "rfc3339"))] Option<OffsetDateTime>);
61
62impl Tick {
63    pub const BIG_BANG: Tick = Tick(None);
65
66    pub fn new(ts: OffsetDateTime) -> Self {
68        Self(Some(ts))
69    }
70
71    pub fn ts(&self) -> Option<&OffsetDateTime> {
73        self.0.as_ref()
74    }
75
76    pub fn with_value<T>(self, value: T) -> TickValue<T> {
78        TickValue { tick: self, value }
79    }
80}
81
82impl From<OffsetDateTime> for Tick {
83    fn from(value: OffsetDateTime) -> Self {
84        Self::new(value)
85    }
86}
87
88impl PartialOrd for Tick {
89    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
90        Some(self.cmp(other))
91    }
92}
93
94impl Ord for Tick {
95    fn cmp(&self, other: &Self) -> Ordering {
96        match (self.0.as_ref(), other.0.as_ref()) {
97            (Some(lhs), Some(rhs)) => lhs.cmp(rhs),
98            (Some(_), None) => Ordering::Greater,
99            (None, Some(_)) => Ordering::Less,
100            (None, None) => Ordering::Equal,
101        }
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn test_big_bang() {
111        assert_eq!(Tick::BIG_BANG, Tick::BIG_BANG);
112    }
113
114    #[cfg(feature = "serde")]
115    #[test]
116    fn serialize_tick() {
117        use time::macros::datetime;
118
119        let tick = Tick::BIG_BANG;
120        assert_eq!(serde_json::to_string(&tick).unwrap(), r#"null"#);
121
122        let tick = Tick::new(datetime!(2022-09-26 01:23:45 +06:54));
123        assert_eq!(
124            serde_json::to_string(&tick).unwrap(),
125            r#""2022-09-26T01:23:45+06:54""#
126        );
127    }
128
129    #[cfg(feature = "serde")]
130    #[test]
131    fn deserialize_tick() {
132        use time::macros::datetime;
133
134        let tick = serde_json::from_str::<Tick>(r#"null"#).unwrap();
135        assert_eq!(tick, Tick::BIG_BANG);
136
137        let tick = serde_json::from_str::<Tick>(r#""2022-09-26T01:23:45+06:54""#).unwrap();
138        assert_eq!(tick, Tick::new(datetime!(2022-09-26 01:23:45 +06:54)),);
139    }
140}