I have traits for senders and receivers of a specific message type.
pub trait Sends {
type Message;
fn send(&self) -> Self::Message;
}
pub trait Receives {
type Message;
fn receive(&mut self, msg: Self::Message);
}
I want to be able to store a compatible pair of sender and receiver in a struct with a run()
method that passes messages, ie receiver.receive(sender.send())
.
My intuition is that this run()
method should not require knowledge of the message type (because all occurrences of the message type are handled internally), so the struct and its method should not expose the message type. I think keeping track of the message types also becomes impractical when you have a bigger sender-receiver network.
What is the best way to do this? I tried it out with Any
, which mostly works. However,
SendAny
from a Send
, and same for the receiver.Here is what I've got so far:
trait SendsAny {
fn send_any(&self) -> Box<dyn Any>;
}
impl<T> SendsAny for T
where
T: Sends,
T::Message: 'static,
{
fn send_any(&self) -> Box<dyn Any> {
Box::new(self.send())
}
}
// Similar for ReceivesAny
struct SendAndReceive {
// These have to have matching Message types
tx: Box<dyn SendsAny>,
rx: Box<dyn ReceivesAny>,
}
impl SendAndReceive {
fn new<M: 'static>(
tx: Box<dyn Sends<Message = M>>,
rx: Box<dyn Receives<Message = M>>,
) -> Self {
// This doesn't work
let tx = tx as Box<dyn SendsAny>;
todo!()
}
fn run(&mut self) {
self.rx.receive_any(self.tx.send_any());
}
}
You should make the type that binds the Sends
and Receives
together, here SendAndReceiveInner
. And then use a trait object, Box<dyn SendAndReceiveAny>
to use it in the type-erased form in SendAndReceive
.
struct SendAndReceiveInner<R, S>
where
S: Sends,
R: Receives<Message = S::Message>,
{
tx: S,
rx: R,
}
trait SendAndReceiveAny {
fn run(&mut self);
}
impl<R, S> SendAndReceiveAny for SendAndReceiveInner<R, S>
where
S: Sends,
R: Receives<Message = S::Message>,
{
fn run(&mut self) {
self.rx.receive(self.tx.send());
}
}
struct SendAndReceive {
inner: Box<dyn SendAndReceiveAny>,
}
impl SendAndReceive {
fn new<R, S>(tx: S, rx: R) -> Self
where
S: Sends + 'static,
R: Receives<Message = S::Message> + 'static,
{
Self {
inner: Box::new(SendAndReceiveInner{ tx, rx }),
}
}
fn run(&mut self) {
self.inner.run();
}
}
This has a lot less boxing involved but still a bit of boilerplate. You could just use it in the Box<dyn...>
form since the outermost SendAndReceive
isn't doing much at this point, but encapsulation and API presentation is up to the reader.
I don't quite know if this is what you are looking for, but you could make the SendAndReceive
generic on the sender and receiver:
pub trait Sends {
type Message;
fn send(&self) -> Self::Message;
}
pub trait Receives {
type Message;
fn receive(&mut self, msg: Self::Message);
}
struct SendAndReceive<R,S>
where S: Sends, R: Receives<Message=S::Message>
{
// These have to have matching Message types
tx: S,
rx: R,
}
impl<R,S> SendAndReceive<R,S>
where S: Sends, R: Receives<Message=S::Message>
{
fn new(tx: S,rx: R,) -> Self {
Self{tx, rx}
}
fn run(&mut self) {
self.rx.receive(self.tx.send());
}
}
The struct is therefore agnostic to the type of the message but generic on the sender/receiver. Also avoid the whole Any
machinery.
You could also go the other way and make the struct generic on the message:
pub trait Sends {
type Message;
fn send(&self) -> Self::Message;
}
pub trait Receives {
type Message;
fn receive(&mut self, msg: Self::Message);
}
struct SendAndReceive<M> {
// These have to have matching Message types
tx: Box<dyn Sends<Message=M>>,
rx: Box<dyn Receives<Message=M>>,
}
impl<M> SendAndReceive<M> {
fn new(
tx: Box<dyn Sends<Message = M>>,
rx: Box<dyn Receives<Message = M>>,
) -> Self {
Self{tx,rx}
}
fn run(&mut self) {
self.rx.receive(self.tx.send());
}
}
This again avoids Any
and doesn't need to be generic on the sender/receiver but must be generic on the message type.
I don't know whether these two are what you are looking for, but I don't see any other way to avoid run
needing specific types/traits.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.