use rosidl_runtime_rs::Message;
use super::MessageInfo;
use crate::ReadOnlyLoanedMessage;
pub trait SubscriptionCallback<T, Args>: Send + 'static
where
T: Message,
{
fn into_callback(self) -> AnySubscriptionCallback<T>;
}
pub enum AnySubscriptionCallback<T>
where
T: Message,
{
Regular(Box<dyn FnMut(T) + Send>),
RegularWithMessageInfo(Box<dyn FnMut(T, MessageInfo) + Send>),
Boxed(Box<dyn FnMut(Box<T>) + Send>),
BoxedWithMessageInfo(Box<dyn FnMut(Box<T>, MessageInfo) + Send>),
#[allow(clippy::type_complexity)]
Loaned(Box<dyn for<'a> FnMut(ReadOnlyLoanedMessage<'a, T>) + Send>),
#[allow(clippy::type_complexity)]
LoanedWithMessageInfo(Box<dyn for<'a> FnMut(ReadOnlyLoanedMessage<'a, T>, MessageInfo) + Send>),
}
impl<T, A0, Func> SubscriptionCallback<T, (A0,)> for Func
where
Func: FnMut(A0) + Send + 'static,
(A0,): ArgTuple<T, Func>,
T: Message,
{
fn into_callback(self) -> AnySubscriptionCallback<T> {
<(A0,) as ArgTuple<T, Func>>::into_callback_with_args(self)
}
}
impl<T, A0, A1, Func> SubscriptionCallback<T, (A0, A1)> for Func
where
Func: FnMut(A0, A1) + Send + 'static,
(A0, A1): ArgTuple<T, Func>,
T: Message,
{
fn into_callback(self) -> AnySubscriptionCallback<T> {
<(A0, A1) as ArgTuple<T, Func>>::into_callback_with_args(self)
}
}
trait ArgTuple<T, Func>
where
T: Message,
{
fn into_callback_with_args(func: Func) -> AnySubscriptionCallback<T>;
}
impl<T, Func> ArgTuple<T, Func> for (T,)
where
T: Message,
Func: FnMut(T) + Send + 'static,
{
fn into_callback_with_args(func: Func) -> AnySubscriptionCallback<T> {
AnySubscriptionCallback::Regular(Box::new(func))
}
}
impl<T, Func> ArgTuple<T, Func> for (T, MessageInfo)
where
T: Message,
Func: FnMut(T, MessageInfo) + Send + 'static,
{
fn into_callback_with_args(func: Func) -> AnySubscriptionCallback<T> {
AnySubscriptionCallback::RegularWithMessageInfo(Box::new(func))
}
}
impl<T, Func> ArgTuple<T, Func> for (Box<T>,)
where
T: Message,
Func: FnMut(Box<T>) + Send + 'static,
{
fn into_callback_with_args(func: Func) -> AnySubscriptionCallback<T> {
AnySubscriptionCallback::Boxed(Box::new(func))
}
}
impl<T, Func> ArgTuple<T, Func> for (Box<T>, MessageInfo)
where
T: Message,
Func: FnMut(Box<T>, MessageInfo) + Send + 'static,
{
fn into_callback_with_args(func: Func) -> AnySubscriptionCallback<T> {
AnySubscriptionCallback::BoxedWithMessageInfo(Box::new(func))
}
}
impl<T, Func> ArgTuple<T, Func> for (ReadOnlyLoanedMessage<'_, T>,)
where
T: Message,
Func: for<'b> FnMut(ReadOnlyLoanedMessage<'b, T>) + Send + 'static,
{
fn into_callback_with_args(func: Func) -> AnySubscriptionCallback<T> {
AnySubscriptionCallback::Loaned(Box::new(func))
}
}
impl<T, Func> ArgTuple<T, Func> for (ReadOnlyLoanedMessage<'_, T>, MessageInfo)
where
T: Message,
Func: for<'b> FnMut(ReadOnlyLoanedMessage<'b, T>, MessageInfo) + Send + 'static,
{
fn into_callback_with_args(func: Func) -> AnySubscriptionCallback<T> {
AnySubscriptionCallback::LoanedWithMessageInfo(Box::new(func))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn callback_conversion() {
type Message = test_msgs::msg::BoundedSequences;
let cb = |_msg: Message| {};
assert!(matches!(
cb.into_callback(),
AnySubscriptionCallback::<Message>::Regular(_)
));
let cb = |_msg: Message, _info: MessageInfo| {};
assert!(matches!(
cb.into_callback(),
AnySubscriptionCallback::<Message>::RegularWithMessageInfo(_)
));
let cb = |_msg: Box<Message>| {};
assert!(matches!(
cb.into_callback(),
AnySubscriptionCallback::<Message>::Boxed(_)
));
let cb = |_msg: Box<Message>, _info: MessageInfo| {};
assert!(matches!(
cb.into_callback(),
AnySubscriptionCallback::<Message>::BoxedWithMessageInfo(_)
));
let cb = |_msg: ReadOnlyLoanedMessage<'_, Message>| {};
assert!(matches!(
cb.into_callback(),
AnySubscriptionCallback::<Message>::Loaned(_)
));
let cb = |_msg: ReadOnlyLoanedMessage<'_, Message>, _info: MessageInfo| {};
assert!(matches!(
cb.into_callback(),
AnySubscriptionCallback::<Message>::LoanedWithMessageInfo(_)
));
}
}