wlancfg_lib/util/
historical_list.rs1use fuchsia_async as fasync;
6use log::warn;
7use std::collections::VecDeque;
8
9pub trait Timestamped {
11 fn time(&self) -> fasync::MonotonicInstant;
12}
13
14#[derive(Clone, Debug, PartialEq)]
17pub struct HistoricalList<T: Timestamped>(pub VecDeque<T>);
18
19impl<T> HistoricalList<T>
20where
21 T: Timestamped + Clone,
22{
23 pub fn new(capacity: usize) -> Self {
24 Self(VecDeque::with_capacity(capacity))
25 }
26
27 pub fn add(&mut self, historical_data: T) {
30 if let Some(newest) = self.0.back()
31 && historical_data.time() < newest.time()
32 {
33 warn!("HistoricalList entry must be newer than existing elements.");
34 return;
35 }
36 if self.0.len() == self.0.capacity() {
37 let _ = self.0.pop_front();
38 }
39 self.0.push_back(historical_data);
40 }
41
42 #[allow(clippy::needless_return, reason = "mass allow for https://fxbug.dev/381896734")]
43 pub fn get_recent(&self, earliest_time: fasync::MonotonicInstant) -> Vec<T> {
46 let i = self.0.partition_point(|data| data.time() < earliest_time);
47 return self.0.iter().skip(i).cloned().collect();
48 }
49
50 #[allow(clippy::needless_return, reason = "mass allow for https://fxbug.dev/381896734")]
51 pub fn get_before(&self, latest_time: fasync::MonotonicInstant) -> Vec<T> {
54 let i = self.0.partition_point(|data| data.time() <= latest_time);
55 return self.0.iter().take(i).cloned().collect();
56 }
57
58 pub fn get_between(
61 &self,
62 earliest_time: fasync::MonotonicInstant,
63 latest_time: fasync::MonotonicInstant,
64 ) -> Vec<T> {
65 let i = self.0.partition_point(|data| data.time() < earliest_time);
66 let j = self.0.partition_point(|data| data.time() <= latest_time);
67 match j.checked_sub(i) {
68 Some(diff) if diff != 0 => self.0.iter().skip(i).take(diff).cloned().collect(),
69 _ => {
70 warn!(
71 "Invalid time bounds - earliest time: {:?}, latest time: {:?}",
72 earliest_time, latest_time
73 );
74 vec![]
75 }
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use zx::MonotonicDuration;
84
85 impl Timestamped for fasync::MonotonicInstant {
86 fn time(&self) -> fasync::MonotonicInstant {
87 *self
88 }
89 }
90
91 const EARLIEST_TIME: fasync::MonotonicInstant =
92 fasync::MonotonicInstant::from_nanos(1_000_000_000);
93 fn create_test_list(
94 earlist_time: fasync::MonotonicInstant,
95 ) -> HistoricalList<fasync::MonotonicInstant> {
96 HistoricalList(VecDeque::from_iter([
97 earlist_time,
98 earlist_time + MonotonicDuration::from_seconds(1),
99 earlist_time + MonotonicDuration::from_seconds(3),
100 earlist_time + MonotonicDuration::from_seconds(5),
101 ]))
102 }
103
104 #[fuchsia::test]
105 fn test_historical_list_capacity() {
106 let mut historical_list = create_test_list(EARLIEST_TIME);
107
108 historical_list.add(EARLIEST_TIME + MonotonicDuration::from_seconds(10));
110 assert_eq!(historical_list.0.len(), 4);
111 assert!(!historical_list.0.contains(&EARLIEST_TIME));
112
113 let t = historical_list.clone();
115 historical_list.add(EARLIEST_TIME);
116 assert_eq!(historical_list, t);
117 }
118
119 #[fuchsia::test]
120 fn test_get_recent() {
121 let historical_list = create_test_list(EARLIEST_TIME);
122
123 assert_eq!(
124 historical_list.get_recent(EARLIEST_TIME + MonotonicDuration::from_seconds(1)),
125 vec![
126 EARLIEST_TIME + MonotonicDuration::from_seconds(1),
127 EARLIEST_TIME + MonotonicDuration::from_seconds(3),
128 EARLIEST_TIME + MonotonicDuration::from_seconds(5)
129 ]
130 );
131
132 assert_eq!(
133 historical_list.get_recent(
134 EARLIEST_TIME
135 + MonotonicDuration::from_seconds(5)
136 + MonotonicDuration::from_millis(1)
137 ),
138 vec![]
139 );
140 }
141
142 #[fuchsia::test]
143 fn test_get_before() {
144 let historical_list = create_test_list(EARLIEST_TIME);
145
146 assert_eq!(
147 historical_list.get_before(EARLIEST_TIME + MonotonicDuration::from_seconds(3)),
148 vec![
149 EARLIEST_TIME,
150 EARLIEST_TIME + MonotonicDuration::from_seconds(1),
151 EARLIEST_TIME + MonotonicDuration::from_seconds(3),
152 ]
153 );
154
155 assert_eq!(
156 historical_list.get_before(EARLIEST_TIME - MonotonicDuration::from_millis(1)),
157 vec![]
158 );
159 }
160
161 #[fuchsia::test]
162 fn test_get_between() {
163 let historical_list = create_test_list(EARLIEST_TIME);
164
165 assert_eq!(
166 historical_list.get_between(
167 EARLIEST_TIME + MonotonicDuration::from_seconds(1),
168 EARLIEST_TIME + MonotonicDuration::from_seconds(5)
169 ),
170 vec![
171 EARLIEST_TIME + MonotonicDuration::from_seconds(1),
172 EARLIEST_TIME + MonotonicDuration::from_seconds(3),
173 EARLIEST_TIME + MonotonicDuration::from_seconds(5),
174 ]
175 );
176
177 assert_eq!(historical_list.get_between(EARLIEST_TIME, EARLIEST_TIME), vec![EARLIEST_TIME]);
178
179 assert_eq!(
180 historical_list.get_between(
181 EARLIEST_TIME + MonotonicDuration::from_seconds(10),
182 EARLIEST_TIME + MonotonicDuration::from_seconds(11)
183 ),
184 vec![]
185 );
186
187 assert_eq!(
189 historical_list
190 .get_between(EARLIEST_TIME + MonotonicDuration::from_seconds(3), EARLIEST_TIME),
191 vec![]
192 )
193 }
194}