Skip to main content

hopr_transport_mixer/
data.rs

1use std::cmp::Ordering;
2
3/// Data structure holding the data alongside a release timemestamp.
4///
5/// The ordering functionality is defined only over the release timestamp
6/// to ensure proper mixing.
7pub struct DelayedData<T> {
8    pub release_at: std::time::Instant,
9    pub item: T,
10}
11
12impl<T> PartialEq for DelayedData<T> {
13    fn eq(&self, other: &Self) -> bool {
14        self.release_at == other.release_at
15    }
16}
17
18impl<T> PartialOrd for DelayedData<T> {
19    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
20        Some(self.cmp(other))
21    }
22}
23
24impl<T> Eq for DelayedData<T> {}
25
26impl<T> Ord for DelayedData<T> {
27    fn cmp(&self, other: &Self) -> Ordering {
28        self.release_at.cmp(&other.release_at)
29    }
30}
31
32impl<T> From<(std::time::Instant, T)> for DelayedData<T> {
33    fn from(value: (std::time::Instant, T)) -> Self {
34        Self {
35            release_at: value.0,
36            item: value.1,
37        }
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use std::time::{Duration, Instant};
44
45    use rstest::rstest;
46
47    use super::*;
48
49    #[rstest]
50    #[case::equal_timestamps(0, 0, Ordering::Equal)]
51    #[case::earlier_is_less(0, 1000, Ordering::Less)]
52    #[case::later_is_greater(1000, 0, Ordering::Greater)]
53    #[case::ordering_ignores_item_value(0, 0, Ordering::Equal)]
54    fn delayed_data_ordering(#[case] delay_a_ms: u64, #[case] delay_b_ms: u64, #[case] expected: Ordering) {
55        let now = Instant::now();
56        let a = DelayedData {
57            release_at: now + Duration::from_millis(delay_a_ms),
58            item: 1,
59        };
60        let b = DelayedData {
61            release_at: now + Duration::from_millis(delay_b_ms),
62            item: 2,
63        };
64        assert_eq!(a.cmp(&b), expected);
65    }
66
67    #[test]
68    fn from_tuple_sets_fields() {
69        let now = Instant::now();
70        let data = DelayedData::from((now, "hello"));
71        assert_eq!(data.release_at, now);
72        assert_eq!(data.item, "hello");
73    }
74
75    #[test]
76    fn sorting_respects_release_time() {
77        let now = Instant::now();
78        let mut items: Vec<DelayedData<&str>> = [(3, "c"), (1, "a"), (2, "b")]
79            .into_iter()
80            .map(|(secs, val)| DelayedData {
81                release_at: now + Duration::from_secs(secs),
82                item: val,
83            })
84            .collect();
85        items.sort();
86        let sorted: Vec<&str> = items.iter().map(|d| d.item).collect();
87        insta::assert_yaml_snapshot!(sorted);
88    }
89}