I'd like to have dynamically dispatched versions of Sender and Receiver with type erased queue size.
struct Sender<'a, T, const N: usize>(&'a Channel<T, N>);
// no queue size in the type!
struct DynSender<'a, T>(&'a dyn ChannelImpl<T>);
Similar feature is already implemented in embassy_sync.
Motivation
I'm trying to implement an actor model around RTIC. Each actor is supposed to have an address that can be used to send messages to it.
struct Addr<A: Actor, const N: usize> {
sender: Sender<'static, A::Msg, N>
}
Having the channel's size embedded in the Address type is inconvenient and makes some patterns impossible.
Implementation
trait ChannelImpl<T> {
fn send_footer(&mut self, idx: u8, val: T);
fn try_send(&mut self, val: T) -> Result<(), TrySendError<T>>;
// oh no! #![feature(async_fn_in_trait)] required, more on that later...
async fn send(&mut self, val: T) -> Result<(), NoReceiver<T>>;
fn try_recv(&mut self) -> Result<T, ReceiveError>;
async fn recv(&mut self) -> Result<T, ReceiveError>;
fn is_closed(&self) -> bool;
fn is_full(&self) -> bool;
fn is_empty(&self) -> bool;
fn handle_sender_clone(&mut self);
fn handle_receiver_clone(&mut self);
fn handle_sender_drop(&mut self);
fn handle_receiver_drop(&mut self);
}
impl<T, const N: usize> ChannelImpl<T> for Channel<T, N> {
// -- snip! --
}
struct Sender<'a, T, const N: usize>(&'a Channel<T, N>);
impl<'a T, const N: usize> Sender<'a, T, N> {
fn into_dyn(self) -> DynSender<'a, T> {
let sender = DynSender(self.0);
core::mem::forget(self);
sender
}
#[inline(always)]
fn try_send(&mut self, val: T) -> Result<(), TrySendError<T>> {
// forward
self.0.try_send(val)
}
// forward implementation for the other methods
// -- snip! --
}
struct DynSender<'a, T>(&'a dyn ChannelImpl<T>);
impl<'a T> DynSender<'a, T> {
#[inline(always)]
fn try_send(&mut self, val: T) -> Result<(), TrySendError<T>> {
// forward
self.0.try_send(val)
}
// forward implementation for the other methods
// -- snip! --
}
Of course, we can't have async functions in traits, but we could work around that by manually implementing SendFuture and RecvFuture types and returning them from regular functions.
fn send(&mut self, val: T) -> SendFuture;
I'd be happy to write a PR if I get a green light, I may want to ask for some help implementing the futures as I've never done this before.
I'd like to have dynamically dispatched versions of Sender and Receiver with type erased queue size.
Similar feature is already implemented in embassy_sync.
Motivation
I'm trying to implement an actor model around RTIC. Each actor is supposed to have an address that can be used to send messages to it.
Having the channel's size embedded in the Address type is inconvenient and makes some patterns impossible.
Implementation
Of course, we can't have async functions in traits, but we could work around that by manually implementing
SendFutureandRecvFuturetypes and returning them from regular functions.I'd be happy to write a PR if I get a green light, I may want to ask for some help implementing the futures as I've never done this before.