summaryrefslogtreecommitdiff
path: root/crates/windlass/src/mcu.rs
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-10-01 15:42:50 +0100
committertcmal <me@aria.rip>2024-10-11 23:57:19 +0100
commit34572a8f3839e37063641fa693029ad52265730a (patch)
treedd81dfba798039acb638aa1945a58cff023f1c38 /crates/windlass/src/mcu.rs
parentd7275a13989b82ea8fc7b2320ef0cf2f427f7d5d (diff)
Stricter clippy lints
Diffstat (limited to 'crates/windlass/src/mcu.rs')
-rw-r--r--crates/windlass/src/mcu.rs142
1 files changed, 65 insertions, 77 deletions
diff --git a/crates/windlass/src/mcu.rs b/crates/windlass/src/mcu.rs
index c2ca54a..8bc725f 100644
--- a/crates/windlass/src/mcu.rs
+++ b/crates/windlass/src/mcu.rs
@@ -20,8 +20,8 @@ use tracing::{debug, error, trace};
use crate::messages::{format_command_args, EncodedMessage, Message, WithOid, WithoutOid};
use crate::transport::{Transport, TransportReceiver};
use crate::{
- dictionary::{Dictionary, DictionaryError, RawDictionary},
- transport::TransportError,
+ dictionary::{self, Dictionary, RawDictionary},
+ transport::Error,
};
use crate::{
encoding::{parse_vlq_int, MessageDecodeError},
@@ -38,7 +38,7 @@ mcu_reply!(
/// MCU Connection Errors
#[derive(thiserror::Error, Debug)]
-pub enum McuConnectionError {
+pub enum ConnectionError {
/// Encoding a message was attempted but a command with a matching name doesn't exist in the
/// dictionary.
#[error("unknown message ID for command '{0}'")]
@@ -51,7 +51,7 @@ pub enum McuConnectionError {
DictionaryFetch(Box<dyn std::error::Error + Send + Sync>),
/// An error was encountered while parsing the dictionary
#[error("dictionary issue: {0}")]
- Dictionary(#[from] DictionaryError),
+ Dictionary(#[from] dictionary::Error),
/// Received an unknown command from the MCU
#[error("unknown command {0}")]
UnknownCommand(u16),
@@ -60,7 +60,7 @@ pub enum McuConnectionError {
CommandMismatch(&'static str, String, String),
/// There was a transport-level issue
#[error("transport error: {0}")]
- Transport(#[from] TransportError),
+ Transport(#[from] Error),
}
#[derive(thiserror::Error, Debug)]
@@ -68,7 +68,7 @@ pub enum SendReceiveError {
#[error("timeout")]
Timeout,
#[error("mcu connection error: {0}")]
- McuConnection(#[from] McuConnectionError),
+ McuConnection(#[from] ConnectionError),
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
@@ -94,7 +94,7 @@ impl std::fmt::Debug for Handlers {
let h = self
.handlers
.try_lock()
- .map(|h| h.keys().cloned().collect::<BTreeSet<_>>())
+ .map(|h| h.keys().copied().collect::<BTreeSet<_>>())
.unwrap_or_default();
f.debug_struct("Handlers")
.field("handlers", &h)
@@ -158,11 +158,11 @@ struct McuConnectionInner {
}
impl McuConnectionInner {
- async fn receive_loop(&self, mut inbox: TransportReceiver) -> Result<(), McuConnectionError> {
+ async fn receive_loop(&self, mut inbox: TransportReceiver) -> Result<(), ConnectionError> {
while let Some(frame) = inbox.recv().await {
let frame = match frame {
Ok(frame) => frame,
- Err(e) => return Err(McuConnectionError::Transport(e)),
+ Err(e) => return Err(ConnectionError::Transport(e)),
};
let frame = &mut frame.as_slice();
self.parse_frame(frame)?;
@@ -170,9 +170,9 @@ impl McuConnectionInner {
Ok(())
}
- fn parse_frame(&self, frame: &mut &[u8]) -> Result<(), McuConnectionError> {
+ fn parse_frame(&self, frame: &mut &[u8]) -> Result<(), ConnectionError> {
while !frame.is_empty() {
- let cmd = parse_vlq_int(frame)? as u16;
+ let cmd = u16::try_from(parse_vlq_int(frame)?).expect("command handler overflow");
// If a raw handler is registered for this, call it
if self.handlers.call(cmd, None, frame) {
@@ -206,7 +206,7 @@ impl McuConnectionInner {
);
}
} else {
- return Err(McuConnectionError::UnknownCommand(cmd));
+ return Err(ConnectionError::UnknownCommand(cmd));
}
} else {
break;
@@ -220,7 +220,7 @@ impl McuConnectionInner {
///
///
#[derive(Debug)]
-pub struct McuConnection {
+pub struct Connection {
inner: Arc<McuConnectionInner>,
transport: Transport,
_receiver: JoinHandle<()>,
@@ -229,22 +229,24 @@ pub struct McuConnection {
#[derive(Debug)]
enum ExitCode {
- Waiting(oneshot::Receiver<Result<(), McuConnectionError>>),
- Exited(Result<(), McuConnectionError>),
+ Waiting(oneshot::Receiver<Result<(), ConnectionError>>),
+ Exited(Result<(), ConnectionError>),
}
-impl McuConnection {
+impl Connection {
/// Connect to an MCU
///
/// Attempts to connect to a MCU on the given data stream interface. The MCU is contacted and
- /// the dictionary is loaded and applied. The returned [McuConnection] is fully ready to
+ /// the dictionary is loaded and applied. The returned [`McuConnection`] is fully ready to
/// communicate with the MCU.
- pub async fn connect<R, W>(rdr: R, wr: W) -> Result<Self, McuConnectionError>
+ /// # Panics
+ /// Panics if the MCU attempts to send an identify payload with size > [`u32::MAX`]
+ pub async fn connect<R, W>(rdr: R, wr: W) -> Result<Self, ConnectionError>
where
R: AsyncBufRead + Send + Unpin + 'static,
W: AsyncWrite + Send + Unpin + 'static,
{
- let (transport, inbox) = Transport::connect(rdr, wr).await;
+ let (transport, inbox) = Transport::connect(rdr, wr);
let (exit_tx, exit_rx) = oneshot::channel();
let inner = Arc::new(McuConnectionInner {
@@ -258,7 +260,7 @@ impl McuConnection {
let _ = exit_tx.send(receiver_inner.receive_loop(inbox).await);
});
- let conn = McuConnection {
+ let conn = Self {
inner,
transport,
_receiver: receiver,
@@ -269,16 +271,16 @@ impl McuConnection {
let identify_start = Instant::now();
loop {
let data = conn
- .send_receive(
- Identify::encode(identify_data.len() as u32, 40),
- IdentifyResponse,
- )
+ .send_receive::<_, IdentifyResponse>(Identify::encode(
+ u32::try_from(identify_data.len()).expect("identify data too long"),
+ 40,
+ ))
.await;
let mut data = match data {
Ok(data) => data,
Err(e) => {
if identify_start.elapsed() > Duration::from_secs(10) {
- return Err(McuConnectionError::DictionaryFetch(Box::new(e)));
+ return Err(ConnectionError::DictionaryFetch(Box::new(e)));
}
continue;
}
@@ -294,20 +296,19 @@ impl McuConnection {
let mut buf = Vec::new();
decoder
.read_to_end(&mut buf)
- .map_err(|err| McuConnectionError::DictionaryFetch(Box::new(err)))?;
+ .map_err(|err| ConnectionError::DictionaryFetch(Box::new(err)))?;
let raw_dict: RawDictionary = serde_json::from_slice(&buf)
- .map_err(|err| McuConnectionError::DictionaryFetch(Box::new(err)))?;
- let dict = Dictionary::try_from(raw_dict).map_err(McuConnectionError::Dictionary)?;
+ .map_err(|err| ConnectionError::DictionaryFetch(Box::new(err)))?;
+ let dict = Dictionary::try_from(raw_dict).map_err(ConnectionError::Dictionary)?;
debug!(dictionary = ?dict, "MCU dictionary");
- conn.inner
- .dictionary
- .set(dict)
- .expect("Dictionary already set");
+ let Ok(()) = conn.inner.dictionary.set(dict) else {
+ unreachable!()
+ };
Ok(conn)
}
- fn verify_command_matches<C: Message>(&self) -> Result<(), McuConnectionError> {
+ fn verify_command_matches<C: Message>(&self) -> Result<(), ConnectionError> {
// Special handling for identify/identify_response
if C::get_id(None) == Some(0) || C::get_id(None) == Some(1) {
return Ok(());
@@ -327,7 +328,7 @@ impl McuConnection {
// tested before then.
let dictionary = self.inner.dictionary.get().unwrap();
let id = C::get_id(Some(dictionary))
- .ok_or_else(|| McuConnectionError::UnknownMessageId(C::get_name()))?;
+ .ok_or_else(|| ConnectionError::UnknownMessageId(C::get_name()))?;
// Must exist because we know the tag
let parser = dictionary.message_parser(id).unwrap();
@@ -335,7 +336,7 @@ impl McuConnection {
let local_fields = C::fields().into_iter();
if !remote_fields.eq(local_fields) {
- return Err(McuConnectionError::CommandMismatch(
+ return Err(ConnectionError::CommandMismatch(
C::get_name(),
format_command_args(parser.fields.iter().map(|(s, t)| (s.as_str(), *t))),
format_command_args(C::fields().into_iter()),
@@ -354,9 +355,9 @@ impl McuConnection {
fn encode_command<C: Message>(
&self,
command: EncodedMessage<C>,
- ) -> Result<FrontTrimmableBuffer, McuConnectionError> {
+ ) -> Result<FrontTrimmableBuffer, ConnectionError> {
let id = C::get_id(self.inner.dictionary.get())
- .ok_or_else(|| McuConnectionError::UnknownMessageId(C::get_name()))?;
+ .ok_or_else(|| ConnectionError::UnknownMessageId(C::get_name()))?;
let mut payload = command.payload;
if id >= 0x80 {
payload.content[0] = ((id >> 7) & 0x7F) as u8 | 0x80;
@@ -368,24 +369,20 @@ impl McuConnection {
}
/// Sends a command to the MCU
- pub async fn send<C: Message>(
- &self,
- command: EncodedMessage<C>,
- ) -> Result<(), McuConnectionError> {
+ pub fn send<C: Message>(&self, command: EncodedMessage<C>) -> Result<(), ConnectionError> {
let cmd = self.encode_command(command)?;
self.transport
.send(cmd.as_slice())
- .map_err(|e| McuConnectionError::Transport(TransportError::Transmitter(e)))
+ .map_err(|e| ConnectionError::Transport(Error::Transmitter(e)))
}
async fn send_receive_impl<C: Message, R: Message>(
&self,
command: EncodedMessage<C>,
- reply: R,
oid: Option<u8>,
) -> Result<R::PodOwned, SendReceiveError> {
struct RespHandler<R: Message>(
- Option<oneshot::Sender<Result<R::PodOwned, McuConnectionError>>>,
+ Option<oneshot::Sender<Result<R::PodOwned, ConnectionError>>>,
);
impl<R: Message> Handler for RespHandler<R> {
@@ -393,7 +390,7 @@ impl McuConnection {
if let Some(tx) = self.0.take() {
let _ = match R::decode(data) {
Ok(msg) => tx.send(Ok(msg.into())),
- Err(e) => tx.send(Err(McuConnectionError::DecodingError(e))),
+ Err(e) => tx.send(Err(ConnectionError::DecodingError(e))),
};
}
HandlerResult::Deregister
@@ -406,13 +403,13 @@ impl McuConnection {
self.verify_command_matches::<R>()?;
let (tx, mut rx) = tokio::sync::oneshot::channel::<Result<R::PodOwned, _>>();
- self.register_raw_response(reply, oid, Box::new(RespHandler::<R>(Some(tx))))?;
+ self.register_raw_response::<R>(oid, Box::new(RespHandler::<R>(Some(tx))))?;
let mut retry_delay = 0.01;
for _retry in 0..=5 {
self.transport
.send(cmd.as_slice())
- .map_err(|e| McuConnectionError::Transport(TransportError::Transmitter(e)))?;
+ .map_err(|e| ConnectionError::Transport(Error::Transmitter(e)))?;
let sleep = tokio::time::sleep(Duration::from_secs_f32(retry_delay));
tokio::pin!(sleep);
@@ -425,7 +422,7 @@ impl McuConnection {
Err(_) => Err(SendReceiveError::Timeout)
};
},
- _ = &mut sleep => {},
+ () = &mut sleep => {},
}
retry_delay *= 2.0;
@@ -441,10 +438,9 @@ impl McuConnection {
pub async fn send_receive_oid<C: Message, R: Message + WithOid>(
&self,
command: EncodedMessage<C>,
- reply: R,
oid: u8,
) -> Result<R::PodOwned, SendReceiveError> {
- self.send_receive_impl(command, reply, Some(oid)).await
+ self.send_receive_impl::<C, R>(command, Some(oid)).await
}
/// Sends a message to the MCU, and await a reply
@@ -454,27 +450,24 @@ impl McuConnection {
pub async fn send_receive<C: Message, R: Message + WithoutOid>(
&self,
command: EncodedMessage<C>,
- reply: R,
) -> Result<R::PodOwned, SendReceiveError> {
- self.send_receive_impl(command, reply, None).await
+ self.send_receive_impl::<C, R>(command, None).await
}
fn register_raw_response<R: Message>(
&self,
- _reply: R,
oid: Option<u8>,
handler: Box<dyn Handler>,
- ) -> Result<RegisteredResponseHandle, McuConnectionError> {
+ ) -> Result<RegisteredResponseHandle, ConnectionError> {
let id = R::get_id(self.inner.dictionary.get())
- .ok_or_else(|| McuConnectionError::UnknownMessageId(R::get_name()))?;
+ .ok_or_else(|| ConnectionError::UnknownMessageId(R::get_name()))?;
Ok(self.inner.handlers.register(id, oid, handler))
}
fn register_response_impl<R: Message>(
&self,
- reply: R,
oid: Option<u8>,
- ) -> Result<UnboundedReceiver<R::PodOwned>, McuConnectionError> {
+ ) -> Result<UnboundedReceiver<R::PodOwned>, ConnectionError> {
struct RespHandler<R: Message>(UnboundedSender<R::PodOwned>, Option<oneshot::Sender<()>>);
impl<R: Message> Drop for RespHandler<R> {
@@ -489,7 +482,7 @@ impl McuConnection {
.expect("Parser should already have assured this could parse")
.into();
match self.0.send(msg) {
- Ok(_) => HandlerResult::Continue,
+ Ok(()) => HandlerResult::Continue,
Err(_) => HandlerResult::Deregister,
}
}
@@ -500,11 +493,8 @@ impl McuConnection {
let (tx, rx) = unbounded_channel();
let tx_closed = tx.clone();
let (closer_tx, closer_rx) = oneshot::channel();
- let uniq = self.register_raw_response(
- reply,
- oid,
- Box::new(RespHandler::<R>(tx, Some(closer_tx))),
- )?;
+ let uniq =
+ self.register_raw_response::<R>(oid, Box::new(RespHandler::<R>(tx, Some(closer_tx))))?;
// Safe because register_raw_response already verified this
let id = R::get_id(self.inner.dictionary.get()).unwrap();
@@ -512,7 +502,7 @@ impl McuConnection {
let inner = self.inner.clone();
spawn(async move {
select! {
- _ = tx_closed.closed() => {},
+ () = tx_closed.closed() => {},
_ = closer_rx => {},
}
inner.handlers.remove_handler(id, oid, Some(uniq));
@@ -528,10 +518,9 @@ impl McuConnection {
/// This version works with replies that have an `oid` field.
pub fn register_response_oid<R: Message + WithOid>(
&self,
- reply: R,
oid: u8,
- ) -> Result<UnboundedReceiver<R::PodOwned>, McuConnectionError> {
- self.register_response_impl(reply, Some(oid))
+ ) -> Result<UnboundedReceiver<R::PodOwned>, ConnectionError> {
+ self.register_response_impl::<R>(Some(oid))
}
/// Registers a subscriber for a reply message
@@ -541,14 +530,16 @@ impl McuConnection {
/// This version works with replies that do not have an `oid` field.
pub fn register_response<R: Message + WithoutOid>(
&self,
- reply: R,
- ) -> Result<UnboundedReceiver<R::PodOwned>, McuConnectionError> {
- self.register_response_impl(reply, None)
+ ) -> Result<UnboundedReceiver<R::PodOwned>, ConnectionError> {
+ self.register_response_impl::<R>(None)
}
/// Returns a reference the dictionary the MCU returned during initial handshake
pub fn dictionary(&self) -> &Dictionary {
- self.inner.dictionary.get().unwrap()
+ self.inner
+ .dictionary
+ .get()
+ .unwrap_or_else(|| unreachable!())
}
/// Closes the transport and ends all subscriptions. Returns when the transport is closed.
@@ -557,16 +548,13 @@ impl McuConnection {
}
/// Waits for the connection to close, returning the error that closed it if any.
- pub async fn closed(&mut self) -> &Result<(), McuConnectionError> {
+ pub async fn closed(&mut self) -> &Result<(), ConnectionError> {
if let ExitCode::Waiting(chan) = &mut self.exit_code {
- self.exit_code = ExitCode::Exited(match chan.await {
- Ok(r) => r,
- Err(_) => Ok(()),
- });
+ self.exit_code = ExitCode::Exited(chan.await.unwrap_or_else(|_| Ok(())));
}
match self.exit_code {
ExitCode::Exited(ref val) => val,
- _ => unreachable!(),
+ ExitCode::Waiting(_) => unreachable!(),
}
}
}