maviola/sync/node/
receive.rs

1use std::time::{Duration, SystemTime};
2
3use crate::core::utils::Sealed;
4use crate::error::{RecvResult, RecvTimeoutError, RecvTimeoutResult, TryRecvError, TryRecvResult};
5
6use crate::prelude::*;
7use crate::sync::prelude::*;
8
9/// <sup>🔒</sup>
10/// Synchronous API for receiving node events.
11///
12/// 🔒 This trait is sealed 🔒
13pub trait ReceiveEvent<V: MaybeVersioned>: Sealed {
14    /// <sup>[`sync`](crate::sync)</sup>
15    /// Receives the next node [`Event`].
16    ///
17    /// Blocks until event received.
18    fn recv(&self) -> RecvResult<Event<V>>;
19
20    /// <sup>[`sync`](crate::sync)</sup>
21    /// Attempts to receive the next node [`Event`] within a `timeout`.
22    ///
23    /// Blocks until event received or deadline is reached.
24    fn recv_timeout(&self, timeout: Duration) -> RecvTimeoutResult<Event<V>>;
25
26    /// <sup>[`sync`](crate::sync)</sup>
27    /// Attempts to receive MAVLink [`Event`] without blocking.
28    fn try_recv(&self) -> TryRecvResult<Event<V>>;
29
30    /// <sup>[`sync`](crate::sync)</sup>
31    /// Subscribes to node events.
32    ///
33    /// Blocks while the underlying node is active.
34    ///
35    /// If you are interested only in valid incoming frames, use [`frames`], [`recv_frame`],
36    /// [`recv_frame_timeout`], or [`try_recv_frame`] instead.
37    ///
38    /// [`recv_frame`]: ReceiveFrame::recv_frame
39    /// [`recv_frame_timeout`]: ReceiveFrame::recv_frame_timeout
40    /// [`try_recv_frame`]: ReceiveFrame::try_recv_frame
41    /// [`frames`]: ReceiveFrame::frames
42    fn events(&self) -> impl Iterator<Item = Event<V>>;
43}
44
45/// <sup>🔒</sup>
46/// Synchronous API for receiving valid MAVLink frames.
47///
48/// 🔒 This trait is sealed 🔒
49pub trait ReceiveFrame<V: MaybeVersioned>: ReceiveEvent<V> {
50    /// <sup>[`sync`](crate::sync)</sup>
51    /// Receives the next frame. Blocks until valid frame received or channel is closed.
52    ///
53    /// If you want to block until the next frame within a timeout, use [`recv_frame_timeout`].
54    /// If you want to check for the next frame without blocking, use [`try_recv_frame`].
55    ///
56    /// **âš ** This method skips all invalid frames. If you are interested in such frames, use
57    /// [`events`] or [`recv`] instead to receive [`Event::Invalid`] event that contain invalid
58    /// frame with the corresponding error.
59    ///
60    /// [`recv_frame_timeout`]: Self::recv_frame_timeout
61    /// [`try_recv_frame`]: Self::try_recv_frame
62    /// [`events`]: ReceiveEvent::events
63    /// [`recv`]: ReceiveEvent::recv
64    fn recv_frame(&self) -> RecvResult<(Frame<V>, Callback<V>)> {
65        loop {
66            match self.recv() {
67                Ok(Event::Frame(frame, callback)) => {
68                    return Ok((frame, callback));
69                }
70                Ok(_) => continue,
71                Err(err) => return Err(err),
72            }
73        }
74    }
75
76    /// <sup>[`sync`](crate::sync)</sup>
77    /// Attempts ot receives the next frame until the timeout is reached. Blocks until valid frame
78    /// received, deadline is reached, or channel is closed.
79    ///
80    /// If you want to block until the next frame is received, use [`recv_frame`].
81    /// If you want to check for the next frame without blocking, use [`try_recv_frame`].
82    ///
83    /// **âš ** This method skips all invalid frames. If you are interested in such frames, use
84    /// [`events`] or [`recv_timeout`] instead to receive [`Event::Invalid`] event that contains
85    /// invalid frame with the corresponding error.
86    ///
87    /// [`recv_frame`]: Self::recv_frame
88    /// [`try_recv_frame`]: Self::try_recv_frame
89    /// [`events`]: ReceiveEvent::events
90    /// [`recv_timeout`]: ReceiveEvent::recv_timeout
91    fn recv_frame_timeout(&self, timeout: Duration) -> RecvTimeoutResult<(Frame<V>, Callback<V>)> {
92        let start = SystemTime::now();
93        let mut current_timeout = timeout;
94
95        loop {
96            match self.recv_timeout(current_timeout) {
97                Ok(Event::Frame(frame, callback)) => {
98                    return Ok((frame, callback));
99                }
100                Ok(_) => {
101                    let since_start =
102                        if let Ok(since_start) = SystemTime::now().duration_since(start) {
103                            since_start
104                        } else {
105                            continue;
106                        };
107
108                    if let Some(new_timeout) = timeout.checked_sub(since_start) {
109                        current_timeout = new_timeout;
110                    } else {
111                        return Err(RecvTimeoutError::Timeout);
112                    }
113                }
114                Err(err) => return Err(err),
115            }
116        }
117    }
118
119    /// <sup>[`sync`](crate::sync)</sup>
120    /// Attempts to receive the next valid frame. Returns immediately if channel is empty.
121    ///
122    /// If you want to block until the next frame within a timeout, use [`recv_frame_timeout`].
123    /// If you want to block until the next frame is received, use [`recv_frame`].
124    ///
125    /// **âš ** This method skips all invalid frames. If you are interested in such frames, use
126    /// [`events`] or [`try_recv`] instead to receive [`Event::Invalid`] event that contains invalid
127    /// frame with the corresponding error.
128    ///
129    /// [`recv_frame`]: Self::recv_frame
130    /// [`recv_frame_timeout`]: Self::recv_frame_timeout
131    /// [`events`]: ReceiveEvent::events
132    /// [`try_recv`]: ReceiveEvent::try_recv
133    fn try_recv_frame(&self) -> TryRecvResult<(Frame<V>, Callback<V>)> {
134        match self.try_recv() {
135            Ok(Event::Frame(frame, callback)) => Ok((frame, callback)),
136            Ok(_) => Err(TryRecvError::Empty),
137            Err(err) => Err(err),
138        }
139    }
140
141    /// <sup>[`sync`](crate::sync)</sup>
142    /// Subscribes to valid MAVLink frames.
143    ///
144    /// Blocks while the underlying node is active.
145    ///
146    /// **âš ** This method skips all invalid frames. If you are interested in such frames, use
147    /// [`events`], [`recv`], [`recv_timeout`], or [`try_recv`] instead to receive
148    /// [`Event::Invalid`] event that contains invalid frame with the corresponding error.
149    ///
150    /// [`recv`]: ReceiveEvent::recv
151    /// [`recv_timeout`]: ReceiveEvent::recv_timeout
152    /// [`try_recv`]: ReceiveEvent::try_recv
153    /// [`events`]: ReceiveEvent::events
154    fn frames(&self) -> impl Iterator<Item = (Frame<V>, Callback<V>)> {
155        self.events().filter_map(|event| match event {
156            Event::Frame(frame, callback) => Some((frame, callback)),
157            _ => None,
158        })
159    }
160}