use crate::byte_converter::FromByteSlice;
use std::{error::Error, marker::PhantomData, sync::mpsc::*, time::Duration};
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum CallbackRecvError {
QueueDisconnected,
MalformedPacket,
}
impl std::fmt::Display for CallbackRecvError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.description()) }
}
impl std::error::Error for CallbackRecvError {
fn description(&self) -> &str {
match self {
CallbackRecvError::QueueDisconnected => "The queue was disconnected. This usually happens if the ip connection is destroyed.",
CallbackRecvError::MalformedPacket =>
"The received packet had an unexpected length. Maybe a function was called on a wrong brick or bricklet?",
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum CallbackRecvTimeoutError {
QueueDisconnected,
QueueTimeout,
MalformedPacket,
}
impl std::fmt::Display for CallbackRecvTimeoutError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.description()) }
}
impl std::error::Error for CallbackRecvTimeoutError {
fn description(&self) -> &str {
match self {
CallbackRecvTimeoutError::QueueDisconnected =>
"The queue was disconnected. This usually happens if the ip connection is destroyed.",
CallbackRecvTimeoutError::QueueTimeout => "The request could not be responded to before the timeout was reached.",
CallbackRecvTimeoutError::MalformedPacket =>
"The received packet had an unexpected length. Maybe a function was called on a wrong brick or bricklet?",
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum CallbackTryRecvError {
QueueDisconnected,
QueueEmpty,
MalformedPacket,
}
impl std::fmt::Display for CallbackTryRecvError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.description()) }
}
impl std::error::Error for CallbackTryRecvError {
fn description(&self) -> &str {
match self {
CallbackTryRecvError::QueueDisconnected =>
"The queue was disconnected. This usually happens if the ip connection is destroyed.",
CallbackTryRecvError::QueueEmpty => "There are currently no responses available.",
CallbackTryRecvError::MalformedPacket =>
"The received packet had an unexpected length. Maybe a function was called on a wrong brick or bricklet?",
}
}
}
pub struct ConvertingCallbackReceiver<T: FromByteSlice> {
receiver: Receiver<Vec<u8>>,
phantom: PhantomData<T>,
}
impl<T: FromByteSlice> ConvertingCallbackReceiver<T> {
pub fn new(receiver: Receiver<Vec<u8>>) -> ConvertingCallbackReceiver<T> {
ConvertingCallbackReceiver { receiver, phantom: PhantomData }
}
pub fn try_recv(&self) -> Result<T, CallbackTryRecvError> {
let recv_result = self.receiver.try_recv();
match recv_result {
Ok(bytes) =>
if T::bytes_expected() == bytes.len() {
Ok(T::from_le_byte_slice(&bytes))
} else {
Err(CallbackTryRecvError::MalformedPacket)
},
Err(TryRecvError::Disconnected) => Err(CallbackTryRecvError::QueueDisconnected),
Err(TryRecvError::Empty) => Err(CallbackTryRecvError::QueueEmpty),
}
}
pub fn recv_forever(&self) -> Result<T, CallbackRecvError> {
let recv_result = self.receiver.recv();
match recv_result {
Ok(bytes) =>
if T::bytes_expected() == bytes.len() {
Ok(T::from_le_byte_slice(&bytes))
} else {
Err(CallbackRecvError::MalformedPacket)
},
Err(RecvError) => Err(CallbackRecvError::QueueDisconnected),
}
}
pub fn recv_timeout(&self, timeout: Duration) -> Result<T, CallbackRecvTimeoutError> {
let recv_result = self.receiver.recv_timeout(timeout);
match recv_result {
Ok(bytes) =>
if T::bytes_expected() == bytes.len() {
Ok(T::from_le_byte_slice(&bytes))
} else {
Err(CallbackRecvTimeoutError::MalformedPacket)
},
Err(RecvTimeoutError::Disconnected) => Err(CallbackRecvTimeoutError::QueueDisconnected),
Err(RecvTimeoutError::Timeout) => Err(CallbackRecvTimeoutError::QueueTimeout),
}
}
pub fn iter(&self) -> Iter<T> { Iter { rx: self } }
pub fn try_iter(&self) -> TryIter<T> { TryIter { rx: self } }
}
pub struct Iter<'a, T: 'a + FromByteSlice> {
rx: &'a ConvertingCallbackReceiver<T>,
}
pub struct TryIter<'a, T: 'a + FromByteSlice> {
rx: &'a ConvertingCallbackReceiver<T>,
}
pub struct IntoIter<T: FromByteSlice> {
rx: ConvertingCallbackReceiver<T>,
}
impl<'a, T: FromByteSlice> Iterator for Iter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<T> { self.rx.recv_forever().ok() }
}
impl<'a, T: FromByteSlice> Iterator for TryIter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<T> { self.rx.try_recv().ok() }
}
impl<'a, T: FromByteSlice> IntoIterator for &'a ConvertingCallbackReceiver<T> {
type Item = T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Iter<'a, T> { self.iter() }
}
impl<T: FromByteSlice> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<T> { self.rx.recv_forever().ok() }
}
impl<T: FromByteSlice> IntoIterator for ConvertingCallbackReceiver<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> IntoIter<T> { IntoIter { rx: self } }
}