prost_validate/
utils.rs

1use prost_types::{Duration, Timestamp};
2use time::{Duration as TimeDelta, OffsetDateTime};
3
4#[allow(clippy::unwrap_used)]
5pub fn datetime(seconds: i64, nanos: i32) -> OffsetDateTime {
6    OffsetDateTime::from_unix_timestamp(seconds)
7        .unwrap_or(OffsetDateTime::from_unix_timestamp(0).unwrap())
8        + TimeDelta::nanoseconds(nanos as i64)
9}
10
11pub fn duration(seconds: i64, nanos: i32) -> TimeDelta {
12    TimeDelta::new(seconds, nanos)
13}
14
15pub trait AsDateTime {
16    fn as_datetime(&self) -> OffsetDateTime;
17}
18
19impl AsDateTime for Timestamp {
20    #[allow(clippy::unwrap_used)]
21    fn as_datetime(&self) -> OffsetDateTime {
22        OffsetDateTime::from_unix_timestamp(self.seconds)
23            .unwrap_or(OffsetDateTime::from_unix_timestamp(0).unwrap())
24            + TimeDelta::nanoseconds(self.nanos as i64)
25    }
26}
27
28impl AsDateTime for &Timestamp {
29    fn as_datetime(&self) -> OffsetDateTime {
30        (*self).as_datetime()
31    }
32}
33
34pub trait AsDuration {
35    fn as_duration(&self) -> TimeDelta;
36}
37
38impl AsDuration for Duration {
39    fn as_duration(&self) -> TimeDelta {
40        TimeDelta::new(self.seconds, self.nanos)
41    }
42}
43
44impl AsDuration for Option<Duration> {
45    #[allow(clippy::unwrap_used)]
46    fn as_duration(&self) -> TimeDelta {
47        self.map(|d| d.as_duration()).unwrap_or_default()
48    }
49}
50
51pub trait VecExt<T> {
52    fn unique(&self) -> Vec<T>
53    where
54        T: Clone + PartialEq;
55}
56
57macro_rules! unique {
58    ($typ:ident) => {
59        impl VecExt<$typ> for Vec<$typ> {
60            fn unique(&self) -> Vec<$typ> {
61                let mut seen = Vec::new();
62                self.iter()
63                    .filter(|x| {
64                        if seen.contains(x) {
65                            false
66                        } else {
67                            seen.push(x.clone());
68                            true
69                        }
70                    })
71                    .cloned()
72                    .collect()
73            }
74        }
75    };
76}
77
78macro_rules! unique_to_bits {
79    ($typ:ident) => {
80        impl VecExt<$typ> for Vec<$typ> {
81            fn unique(&self) -> Vec<$typ> {
82                let mut seen = Vec::new();
83                self.iter()
84                    .filter(|x| {
85                        if seen.contains(&x.to_bits()) {
86                            false
87                        } else {
88                            seen.push(x.to_bits());
89                            true
90                        }
91                    })
92                    .cloned()
93                    .collect()
94            }
95        }
96    };
97}
98
99unique!(String);
100unique!(i32);
101unique!(i64);
102unique!(u32);
103unique!(u64);
104unique_to_bits!(f32);
105unique_to_bits!(f64);
106
107impl VecExt<Vec<u8>> for Vec<Vec<u8>> {
108    fn unique(&self) -> Vec<Vec<u8>> {
109        let mut seen = Vec::new();
110        self.iter()
111            .filter(|x| {
112                if seen.contains(x) {
113                    false
114                } else {
115                    #[allow(suspicious_double_ref_op)]
116                    seen.push(x.clone());
117                    true
118                }
119            })
120            .cloned()
121            .collect()
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    #[test]
130    fn unique_float() {
131        let vals = vec![1.0, 2.0, 1.0, 3.0, 2.0];
132        let unique = vals.unique();
133        assert_eq!(unique, vec![1.0, 2.0, 3.0]);
134    }
135}