use super::types::{Receiver, ReceiverInner};
use tokio::sync::mpsc;
pub(super) enum RelayAction<U> {
Forward(U),
Drop,
}
pub(super) enum RelaySender<T> {
Unbounded(mpsc::UnboundedSender<T>),
Bounded(mpsc::Sender<T>),
}
impl<T> RelaySender<T> {
pub(super) async fn send(&self, value: T) -> std::result::Result<(), ()> {
match self {
RelaySender::Unbounded(tx) => tx.send(value).map_err(|_| ()),
RelaySender::Bounded(tx) => tx.send(value).await.map_err(|_| ()),
}
}
}
pub(super) fn matching_channel<T, U>(inner: &ReceiverInner<T>) -> (RelaySender<U>, ReceiverInner<U>) {
match inner {
ReceiverInner::Unbounded(_) => {
let (tx, rx) = mpsc::unbounded_channel();
(RelaySender::Unbounded(tx), ReceiverInner::Unbounded(rx))
}
ReceiverInner::Bounded(bounded_rx) => {
let capacity = bounded_rx.max_capacity();
let (tx, rx) = mpsc::channel(capacity);
(RelaySender::Bounded(tx), ReceiverInner::Bounded(rx))
}
ReceiverInner::DropOldest(drop_oldest_rx) => {
let capacity = drop_oldest_rx.capacity();
let (tx, rx) = mpsc::channel(capacity);
(RelaySender::Bounded(tx), ReceiverInner::Bounded(rx))
}
}
}
impl<T> Receiver<T> {
pub(super) fn spawn_relay<U, F>(self, mut transform: F) -> Receiver<U>
where
F: FnMut(T) -> RelayAction<U> + Send + 'static,
T: Send + 'static,
U: Send + 'static,
{
let (tx, rx) = matching_channel::<T, U>(&self.inner);
let mut receiver = self;
tokio::spawn(async move {
while let Some(msg) = receiver.recv().await {
match transform(msg) {
RelayAction::Forward(item) => {
if tx.send(item).await.is_err() {
break;
}
}
RelayAction::Drop => {}
}
}
});
Receiver { inner: rx }
}
}