I have a use case, where I want to accept either Sender or SyncSender or whatever else can .send() a specific type through a channel.
Is there a trait in std that I'm overlooking here?
I currently roll my own helper trait
use crate::request::Request;
use std::sync::mpsc::{SendError, Sender, SyncSender};
/// A trait to identify types that can be used as `ASHv2` hosts.
pub trait Host {
/// Send a request to the transceiver.
///
/// # Errors
///
/// Returns a [`SendError`] if the request could not be sent.
fn send(&self, request: Request) -> Result<(), SendError<Request>>;
}
impl Host for Sender<Request> {
fn send(&self, request: Request) -> Result<(), SendError<Request>> {
Self::send(self, request)
}
}
impl Host for SyncSender<Request> {
fn send(&self, request: Request) -> Result<(), SendError<Request>> {
Self::send(self, request)
}
}
But would like to use something existing if available.
Alternatively, instead of building a "use-once" trait, you can use simple closure callbacks, preferably FnOnce or FnMut:
fn use_sender(send: impl FnOnce(Request) -> Result<(), Request>) {
if let Err(not_sent) = send(Request::new(...)) {
todo!()
}
}
fn caller() {
let (tx, rx) = channel();
let send = move |msg| {
tx.send(msg).unwrap();
Ok(())
};
use_sender(send);
}
This technique allows the caller to adapt your functionality easily. The caller can even store the value in a variable:
fn caller() {
let mut store = None;
let send = |msg| {
store = Some(msg);
Ok(())
};
use_sender(send); // Maybe a message is sent, maybe not...
match store {
Some(msg) => handle_the_message(msg), // We got a message
None => no_message_sent(),
}
}
This approach offers flexibility, allowing the caller to adapt to different situations without needing a custom trait.