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