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}