1use crate::{DeserializeError, Sbp};
4
5pub trait SbpIterExt: Iterator {
7 fn ignore_errors<'a>(self) -> HandleErrorsIter<'a, Self, DeserializeError>
10 where
11 Self: Iterator<Item = Result<Sbp, DeserializeError>> + Sized,
12 {
13 HandleErrorsIter::new(self, |e| match e {
14 DeserializeError::IoError(_) => ControlFlow::Break,
15 _ => ControlFlow::Continue,
16 })
17 }
18
19 fn log_errors<'a>(self, level: log::Level) -> HandleErrorsIter<'a, Self, DeserializeError>
22 where
23 Self: Iterator<Item = Result<Sbp, DeserializeError>> + Sized,
24 {
25 HandleErrorsIter::new(self, move |e| {
26 log::log!(level, "{e}");
27 match e {
28 DeserializeError::IoError(_) => ControlFlow::Break,
29 _ => ControlFlow::Continue,
30 }
31 })
32 }
33
34 fn handle_errors<'a, E, F>(self, on_err: F) -> HandleErrorsIter<'a, Self, E>
37 where
38 Self: Iterator<Item = Result<Sbp, E>> + Sized,
39 F: FnMut(&E) -> ControlFlow + 'a,
40 {
41 HandleErrorsIter::new(self, on_err)
42 }
43
44 #[cfg(feature = "swiftnav")]
48 fn with_rover_time<T>(self) -> swiftnav_impl::RoverTimeIter<Self>
49 where
50 T: swiftnav_impl::HasTime,
51 Self: Iterator<Item = T> + Sized,
52 {
53 swiftnav_impl::RoverTimeIter::new(self)
54 }
55}
56
57impl<I> SbpIterExt for I where I: Iterator + Sized {}
58
59pub enum ControlFlow {
63 Continue,
64 Break,
65}
66
67pub struct HandleErrorsIter<'a, I, E>
69where
70 I: Iterator,
71{
72 messages: I,
73 on_err: Box<dyn FnMut(&E) -> ControlFlow + 'a>,
74 err: Result<(), E>,
75}
76
77impl<'a, I, E> HandleErrorsIter<'a, I, E>
78where
79 I: Iterator<Item = Result<Sbp, E>>,
80{
81 fn new<F>(messages: I, on_err: F) -> HandleErrorsIter<'a, I, E>
82 where
83 F: FnMut(&E) -> ControlFlow + 'a,
84 {
85 Self {
86 messages,
87 on_err: Box::new(on_err),
88 err: Ok(()),
89 }
90 }
91
92 pub fn take_err(&mut self) -> Result<(), E> {
93 std::mem::replace(&mut self.err, Ok(()))
94 }
95}
96
97impl<I, E> Iterator for HandleErrorsIter<'_, I, E>
98where
99 I: Iterator<Item = Result<Sbp, E>>,
100{
101 type Item = Sbp;
102
103 fn next(&mut self) -> Option<Self::Item> {
104 match self.messages.next()? {
105 Ok(msg) => Some(msg),
106 Err(e) => {
107 let flow = (self.on_err)(&e);
108 self.err = Err(e);
109 match flow {
110 ControlFlow::Continue => self.next(),
111 ControlFlow::Break => None,
112 }
113 }
114 }
115 }
116}
117
118#[cfg(feature = "swiftnav")]
119mod swiftnav_impl {
120 use swiftnav::time::GpsTime;
121
122 use crate::{
123 Frame, Sbp,
124 messages::SbpMessage,
125 time::{GpsTimeError, MessageTime, RoverTime},
126 };
127
128 pub struct RoverTimeIter<I: Iterator> {
130 messages: I,
131 clock: Option<GpsTime>,
132 }
133
134 impl<I> RoverTimeIter<I>
135 where
136 I: Iterator,
137 {
138 pub fn new(messages: I) -> RoverTimeIter<I> {
139 Self {
140 messages,
141 clock: None,
142 }
143 }
144
145 fn update(&mut self, time: MessageTime) -> Option<GpsTime> {
146 match time {
147 MessageTime::Rover(time) => match time {
148 RoverTime::GpsTime(time) => {
149 self.clock = Some(time);
150 Some(time)
151 }
152 RoverTime::Tow(tow) => {
153 if let Some(clock) = self.clock {
154 let time = GpsTime::new(clock.wn(), tow).unwrap();
156 self.clock = Some(time);
157 Some(time)
158 } else {
159 None
161 }
162 }
163 },
164 _ => None,
165 }
166 }
167 }
168
169 impl<I> Iterator for RoverTimeIter<I>
170 where
171 I: Iterator,
172 I::Item: HasTime,
173 {
174 type Item = (I::Item, Option<Result<GpsTime, GpsTimeError>>);
175
176 fn next(&mut self) -> Option<Self::Item> {
177 let msg = self.messages.next()?;
178 match msg.time() {
179 Some(Ok(time)) => match self.update(time) {
180 Some(gps_time) => Some((msg, Some(Ok(gps_time)))),
181 None => Some((msg, None)),
182 },
183 Some(Err(e)) => Some((msg, Some(Err(e)))),
184 None => Some((msg, None)),
185 }
186 }
187 }
188
189 pub trait HasTime {
190 fn time(&self) -> Option<Result<MessageTime, GpsTimeError>>;
191 }
192
193 impl HasTime for Sbp {
194 fn time(&self) -> Option<Result<MessageTime, GpsTimeError>> {
195 self.gps_time()
196 }
197 }
198
199 impl<E> HasTime for Result<Sbp, E> {
200 fn time(&self) -> Option<Result<MessageTime, GpsTimeError>> {
201 match self {
202 Ok(m) => m.gps_time(),
203 Err(_) => None,
204 }
205 }
206 }
207
208 impl HasTime for Frame {
209 fn time(&self) -> Option<Result<MessageTime, GpsTimeError>> {
210 self.to_sbp().time()
211 }
212 }
213
214 impl<E> HasTime for Result<Frame, E> {
215 fn time(&self) -> Option<Result<MessageTime, GpsTimeError>> {
216 match self {
217 Ok(m) => m.time(),
218 Err(_) => None,
219 }
220 }
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use std::io::Cursor;
227
228 use crate::iter_messages;
229
230 use super::*;
231
232 #[cfg(feature = "swiftnav")]
233 #[test]
234 fn test_rover_time_wn() {
235 #[rustfmt::skip]
236 let data = Cursor::new(vec![
237 85, 0, 1, 246, 215, 11, 251, 6, 120, 46, 39, 0, 0, 0, 0, 0, 0, 133, 36,
239 85, 255, 255, 246, 215, 4, 0, 50, 0, 0, 249, 216,
241 85, 0, 2, 246, 215, 32, 220, 46, 39, 0, 216, 41, 227, 254, 33, 154, 68, 193, 9, 151,
243 154, 124, 231, 95, 80, 193, 1, 183, 214, 139, 255, 105, 77, 65, 0, 0, 9, 0, 7, 98,
244 85, 0, 1, 246, 215, 11, 251, 6, 64, 47, 39, 0, 0, 0, 0, 0, 0, 171, 190,
246 ]);
247
248 let mut with_time = iter_messages(data).ignore_errors().with_rover_time();
249
250 let gps_time = with_time.next().and_then(|(_, t)| t).unwrap().unwrap();
251 assert_eq!(gps_time.wn(), 1787);
252 assert!((gps_time.tow() - 2567.8).abs() < f64::EPSILON);
253
254 assert!(with_time.next().and_then(|(_, t)| t).is_none());
255
256 let gps_time = with_time.next().and_then(|(_, t)| t).unwrap().unwrap();
257 assert_eq!(gps_time.wn(), 1787);
258 assert!((gps_time.tow() - 2567.9).abs() < f64::EPSILON);
259
260 let gps_time = with_time.next().and_then(|(_, t)| t).unwrap().unwrap();
261 assert_eq!(gps_time.wn(), 1787);
262 assert!((gps_time.tow() - 2568.).abs() < f64::EPSILON);
263 }
264
265 #[cfg(feature = "swiftnav")]
266 #[test]
267 fn test_rover_time_result() {
268 let data = Cursor::new(vec![
269 85, 0, 1, 246, 215, 11, 251, 6, 120, 46, 39, 0, 0, 0, 0, 0, 0, 133, 36,
271 ]);
272
273 let mut with_time = iter_messages(data).with_rover_time();
274
275 let msg = with_time.next().unwrap();
276 assert!(msg.0.is_ok());
277
278 let gps_time = msg.1.unwrap().unwrap();
279 assert_eq!(gps_time.wn(), 1787);
280 assert!((gps_time.tow() - 2567.8).abs() < f64::EPSILON);
281 }
282
283 #[test]
284 fn test_handle_errors() {
285 #[rustfmt::skip]
286 let data = Cursor::new(vec![
287 85, 0, 1, 246, 215, 11, 251, 6, 120, 46, 39, 0, 0, 0, 0, 0, 0, 133, 36,
288 85, 0, 1, 246, 215, 11, 251, 6, 220, 46, 39, 0, 0, 0, 0, 0, 0, 36, 159, 85, 0, 1, 246, 215, 11, 251, 6, 220, 46, 39, 0, 0, 0, 0, 0, 0, 36, 160,
290 ]);
291
292 let mut errors: usize = 0;
293 let messages = iter_messages(data.clone())
294 .handle_errors(|_| {
295 errors += 1;
296 ControlFlow::Continue
297 })
298 .count();
299 assert_eq!(messages, 2);
300 assert_eq!(errors, 1);
301
302 let messages = iter_messages(data).ignore_errors().count();
303 assert_eq!(messages, 2);
304 }
305
306 #[test]
307 fn test_stop_on_errors() {
308 #[rustfmt::skip]
309 let data = Cursor::new(vec![
310 85, 0, 1, 246, 215, 11, 251, 6, 120, 46, 39, 0, 0, 0, 0, 0, 0, 133, 36,
311 85, 0, 1, 246, 215, 11, 251, 6, 120, 46, 39, 0, 0, 0, 0, 0, 0, 133, 36,
312 85, 0, 1, 246, 215, 11, 251, 6, 220, 46, 39, 0, 0, 0, 0, 0, 0, 36, 159, 85, 0, 1, 246, 215, 11, 251, 6, 220, 46, 39, 0, 0, 0, 0, 0, 0, 36, 160,
314 ]);
315
316 let mut err_count: usize = 0;
317 let mut msg_count: usize = 0;
318
319 let mut messages = iter_messages(data).handle_errors(|_| {
320 err_count += 1;
321 ControlFlow::Break
322 });
323
324 for _ in &mut messages {
325 msg_count += 1;
326 }
327 assert!(matches!(
328 messages.take_err(),
329 Err(DeserializeError::CrcError { .. })
330 ));
331 assert_eq!(msg_count, 2);
332
333 for _ in &mut messages {
334 msg_count += 1;
335 }
336 assert!(messages.take_err().is_ok());
337 assert_eq!(msg_count, 3);
338
339 assert_eq!(messages.count(), 0);
340 assert_eq!(err_count, 1);
341 }
342}