use std::{
fmt::Debug,
future::{Future, poll_fn},
io,
marker::PhantomData,
pin::Pin,
sync::Arc,
task::{Context, Poll, ready},
};
use n0_error::{e, stack_error};
use super::SendError;
#[cfg(feature = "rpc")]
use crate::rpc::{ErrorCode, RpcRecvError};
#[stack_error(derive, add_meta, from_sources)]
#[non_exhaustive]
pub enum RecvError {
#[cfg(feature = "rpc")]
#[error("Remote channel failed")]
Rpc { source: RpcRecvError },
}
#[cfg(feature = "rpc")]
impl From<io::Error> for RecvError {
fn from(err: io::Error) -> Self {
RpcRecvError::from(err).into()
}
}
impl From<RecvError> for io::Error {
fn from(e: RecvError) -> Self {
match e {
#[cfg(feature = "rpc")]
RecvError::Rpc { source, .. } => source.into(),
}
}
}
#[cfg(feature = "rpc")]
impl RecvError {
pub fn remote_code(&self) -> Option<ErrorCode> {
match self {
Self::Rpc { source, .. } => source.remote_code(),
}
}
}
pub fn channel<T>(buffer: usize) -> (Sender<T>, Receiver<T>) {
let (tx, rx) = tokio::sync::mpsc::channel(buffer);
(tx.into(), rx.into())
}
pub struct Sender<T>(SenderInner<T>);
enum SenderInner<T> {
Tokio(tokio::sync::mpsc::Sender<T>),
Boxed(Arc<dyn DynSender<T>>),
}
impl<T> Clone for Sender<T> {
fn clone(&self) -> Self {
Self(match &self.0 {
SenderInner::Tokio(tx) => SenderInner::Tokio(tx.clone()),
SenderInner::Boxed(inner) => SenderInner::Boxed(inner.clone()),
})
}
}
impl<T> Sender<T> {
pub(crate) fn from_boxed(inner: Arc<dyn DynSender<T>>) -> Self {
Self(SenderInner::Boxed(inner))
}
pub fn is_rpc(&self) -> bool
where
T: 'static,
{
match &self.0 {
SenderInner::Tokio(_) => false,
SenderInner::Boxed(x) => x.is_rpc(),
}
}
#[cfg(feature = "stream")]
pub fn into_sink(self) -> impl n0_future::Sink<T, Error = SendError> + Send + 'static
where
T: Send + Sync + 'static,
{
futures_util::sink::unfold(self, |sink, value| async move {
sink.send(value).await?;
Ok(sink)
})
}
}
impl<T: Send + Sync + 'static> Sender<T> {
pub fn with_filter<F>(self, f: F) -> Sender<T>
where
F: Fn(&T) -> bool + Send + Sync + 'static,
{
self.with_filter_map(move |u| if f(&u) { Some(u) } else { None })
}
pub fn with_map<U, F>(self, f: F) -> Sender<U>
where
F: Fn(U) -> T + Send + Sync + 'static,
U: Send + Sync + 'static,
{
self.with_filter_map(move |u| Some(f(u)))
}
pub fn with_filter_map<U, F>(self, f: F) -> Sender<U>
where
F: Fn(U) -> Option<T> + Send + Sync + 'static,
U: Send + Sync + 'static,
{
let inner: Arc<dyn DynSender<U>> = Arc::new(FilterMapSender {
f,
sender: self,
_p: PhantomData,
});
Sender::from_boxed(inner)
}
pub async fn closed(&self) {
match &self.0 {
SenderInner::Tokio(tx) => tx.closed().await,
SenderInner::Boxed(sink) => sink.closed().await,
}
}
}
impl<T> From<tokio::sync::mpsc::Sender<T>> for Sender<T> {
fn from(tx: tokio::sync::mpsc::Sender<T>) -> Self {
Self(SenderInner::Tokio(tx))
}
}
impl<T> TryFrom<Sender<T>> for tokio::sync::mpsc::Sender<T> {
type Error = Sender<T>;
fn try_from(value: Sender<T>) -> Result<Self, Self::Error> {
match value.0 {
SenderInner::Tokio(tx) => Ok(tx),
SenderInner::Boxed(_) => Err(value),
}
}
}
pub(crate) trait DynSender<T>: Debug + Send + Sync + 'static {
fn send(&self, value: T) -> Pin<Box<dyn Future<Output = Result<(), SendError>> + Send + '_>>;
fn try_send(
&self,
value: T,
) -> Pin<Box<dyn Future<Output = Result<bool, SendError>> + Send + '_>>;
fn closed(&self) -> Pin<Box<dyn Future<Output = ()> + Send + Sync + '_>>;
fn is_rpc(&self) -> bool;
}
pub(crate) trait DynReceiver<T>: Debug + Send + Sync + 'static {
fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Result<Option<T>, RecvError>>;
}
impl<T> Debug for Sender<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.0 {
SenderInner::Tokio(x) => f
.debug_struct("Tokio")
.field("avail", &x.capacity())
.field("cap", &x.max_capacity())
.finish(),
SenderInner::Boxed(inner) => f.debug_tuple("Boxed").field(&inner).finish(),
}
}
}
impl<T: Send + 'static> Sender<T> {
pub async fn send(&self, value: T) -> Result<(), SendError> {
match &self.0 {
SenderInner::Tokio(tx) => tx
.send(value)
.await
.map_err(|_| e!(SendError::ReceiverClosed)),
SenderInner::Boxed(sink) => sink.send(value).await,
}
}
pub async fn try_send(&self, value: T) -> Result<bool, SendError> {
match &self.0 {
SenderInner::Tokio(tx) => match tx.try_send(value) {
Ok(()) => Ok(true),
Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => {
Err(e!(SendError::ReceiverClosed))
}
Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => Ok(false),
},
SenderInner::Boxed(sink) => sink.try_send(value).await,
}
}
}
impl<T> crate::sealed::Sealed for Sender<T> {}
impl<T> crate::Sender for Sender<T> {}
pub struct Receiver<T>(ReceiverInner<T>);
enum ReceiverInner<T> {
Tokio(tokio::sync::mpsc::Receiver<T>),
Boxed(Box<dyn DynReceiver<T>>),
}
impl<T> Receiver<T> {
pub(crate) fn from_boxed(inner: Box<dyn DynReceiver<T>>) -> Self {
Self(ReceiverInner::Boxed(inner))
}
}
impl<T: Send + Sync + 'static> Receiver<T> {
pub async fn recv(&mut self) -> Result<Option<T>, RecvError> {
poll_fn(|cx| self.poll_recv(cx)).await
}
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Result<Option<T>, RecvError>> {
match &mut self.0 {
ReceiverInner::Tokio(rx) => rx.poll_recv(cx).map(Ok),
ReceiverInner::Boxed(rx) => rx.poll_recv(cx),
}
}
pub fn map<U, F>(self, f: F) -> Receiver<U>
where
F: Fn(T) -> U + Send + Sync + 'static,
U: Send + Sync + 'static,
{
self.filter_map(move |u| Some(f(u)))
}
pub fn filter<F>(self, f: F) -> Receiver<T>
where
F: Fn(&T) -> bool + Send + Sync + 'static,
{
self.filter_map(move |u| if f(&u) { Some(u) } else { None })
}
pub fn filter_map<F, U>(self, f: F) -> Receiver<U>
where
U: Send + Sync + 'static,
F: Fn(T) -> Option<U> + Send + Sync + 'static,
{
let inner: Box<dyn DynReceiver<U>> = Box::new(FilterMapReceiver {
f,
receiver: self,
_p: PhantomData,
});
Receiver::from_boxed(inner)
}
#[cfg(feature = "stream")]
pub fn into_stream(
self,
) -> impl n0_future::Stream<Item = Result<T, RecvError>> + Send + Sync + 'static {
self
}
}
#[cfg(feature = "stream")]
impl<T: Send + Sync + 'static> n0_future::Stream for Receiver<T> {
type Item = Result<T, RecvError>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.get_mut().poll_recv(cx).map(Result::transpose)
}
}
impl<T> From<tokio::sync::mpsc::Receiver<T>> for Receiver<T> {
fn from(rx: tokio::sync::mpsc::Receiver<T>) -> Self {
Self(ReceiverInner::Tokio(rx))
}
}
impl<T> TryFrom<Receiver<T>> for tokio::sync::mpsc::Receiver<T> {
type Error = Receiver<T>;
fn try_from(value: Receiver<T>) -> Result<Self, Self::Error> {
match value.0 {
ReceiverInner::Tokio(tx) => Ok(tx),
ReceiverInner::Boxed(_) => Err(value),
}
}
}
impl<T> Debug for Receiver<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.0 {
ReceiverInner::Tokio(inner) => f
.debug_struct("Tokio")
.field("avail", &inner.capacity())
.field("cap", &inner.max_capacity())
.finish(),
ReceiverInner::Boxed(inner) => f.debug_tuple("Boxed").field(&inner).finish(),
}
}
}
struct FilterMapSender<F, T, U> {
f: F,
sender: Sender<T>,
_p: PhantomData<U>,
}
impl<F, T, U> Debug for FilterMapSender<F, T, U> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FilterMapSender").finish_non_exhaustive()
}
}
impl<F, T, U> DynSender<U> for FilterMapSender<F, T, U>
where
F: Fn(U) -> Option<T> + Send + Sync + 'static,
T: Send + Sync + 'static,
U: Send + Sync + 'static,
{
fn send(&self, value: U) -> Pin<Box<dyn Future<Output = Result<(), SendError>> + Send + '_>> {
Box::pin(async move {
match (self.f)(value) {
Some(v) => self.sender.send(v).await,
_ => Ok(()),
}
})
}
fn try_send(
&self,
value: U,
) -> Pin<Box<dyn Future<Output = Result<bool, SendError>> + Send + '_>> {
Box::pin(async move {
match (self.f)(value) {
Some(v) => self.sender.try_send(v).await,
_ => Ok(true),
}
})
}
fn is_rpc(&self) -> bool {
self.sender.is_rpc()
}
fn closed(&self) -> Pin<Box<dyn Future<Output = ()> + Send + Sync + '_>> {
match &self.sender.0 {
SenderInner::Tokio(tx) => Box::pin(tx.closed()),
SenderInner::Boxed(sink) => sink.closed(),
}
}
}
struct FilterMapReceiver<F, T, U> {
f: F,
receiver: Receiver<T>,
_p: PhantomData<U>,
}
impl<F, T, U> Debug for FilterMapReceiver<F, T, U> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FilterMapReceiver").finish_non_exhaustive()
}
}
impl<F, T, U> DynReceiver<U> for FilterMapReceiver<F, T, U>
where
F: Fn(T) -> Option<U> + Send + Sync + 'static,
T: Send + Sync + 'static,
U: Send + Sync + 'static,
{
fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Result<Option<U>, RecvError>> {
loop {
let Some(msg) = ready!(self.receiver.poll_recv(cx))? else {
return Poll::Ready(Ok(None));
};
if let Some(v) = (self.f)(msg) {
return Poll::Ready(Ok(Some(v)));
}
}
}
}
impl<T> crate::sealed::Sealed for Receiver<T> {}
impl<T> crate::Receiver for Receiver<T> {}