use std::{fmt::Debug, future::Future, io, pin::Pin, task};
use n0_error::{e, stack_error};
use n0_future::future::Boxed as BoxFuture;
use super::SendError;
#[cfg(feature = "rpc")]
use crate::rpc::{self, ErrorCode, RpcRecvError};
use crate::util::FusedOneshotReceiver;
#[stack_error(derive, add_meta, from_sources)]
#[non_exhaustive]
pub enum RecvError {
#[error("Sender closed")]
SenderClosed,
#[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 {
if let Some(None | Some(ErrorCode::MessageAborted)) = rpc::reset_code(&err) {
return e!(RecvError::SenderClosed);
}
if rpc::is_truncated(&err) {
return e!(RecvError::SenderClosed);
}
RpcRecvError::from(err).into()
}
}
impl From<RecvError> for io::Error {
fn from(e: RecvError) -> Self {
match e {
RecvError::SenderClosed { .. } => io::Error::new(io::ErrorKind::BrokenPipe, 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(),
_ => None,
}
}
}
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let (tx, rx) = tokio::sync::oneshot::channel();
(tx.into(), rx.into())
}
pub(crate) trait DynSender<T>: Debug + Send + Sync + 'static {
fn send(self: Box<Self>, value: T) -> BoxFuture<Result<(), SendError>>;
fn is_rpc(&self) -> bool;
}
type BoxedReceiver<T> = BoxFuture<Result<T, RecvError>>;
pub struct Sender<T>(SenderInner<T>);
enum SenderInner<T> {
Tokio(tokio::sync::oneshot::Sender<T>),
Boxed(Box<dyn DynSender<T>>),
}
impl<T> Debug for Sender<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.0 {
SenderInner::Tokio(_) => f.debug_tuple("Tokio").finish(),
SenderInner::Boxed(sender) => f.debug_tuple("Boxed").field(sender).finish(),
}
}
}
impl<T> From<tokio::sync::oneshot::Sender<T>> for Sender<T> {
fn from(tx: tokio::sync::oneshot::Sender<T>) -> Self {
Self(SenderInner::Tokio(tx))
}
}
impl<T> TryFrom<Sender<T>> for tokio::sync::oneshot::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),
}
}
}
impl<T> Sender<T> {
pub(crate) fn from_boxed(inner: Box<dyn DynSender<T>>) -> Self {
Self(SenderInner::Boxed(inner))
}
pub async fn send(self, value: T) -> Result<(), SendError>
where
T: 'static,
{
match self.0 {
SenderInner::Tokio(tx) => tx.send(value).map_err(|_| e!(SendError::ReceiverClosed)),
SenderInner::Boxed(sender) => sender.send(value).await,
}
}
pub fn is_rpc(&self) -> bool
where
T: 'static,
{
match &self.0 {
SenderInner::Tokio(_) => false,
SenderInner::Boxed(sender) => sender.is_rpc(),
}
}
}
impl<T: Send + Sync + 'static> Sender<T> {
pub fn with_filter(self, f: impl Fn(&T) -> bool + Send + Sync + 'static) -> Sender<T> {
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,
{
Sender::from_boxed(Box::new(FilterMapSender { inner: self, f }))
}
}
struct FilterMapSender<T, F> {
inner: Sender<T>,
f: F,
}
impl<T, F> Debug for FilterMapSender<T, F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FilterMapSender")
.field("inner", &self.inner)
.finish_non_exhaustive()
}
}
impl<T, U, F> DynSender<U> for FilterMapSender<T, F>
where
T: Send + Sync + 'static,
U: Send + Sync + 'static,
F: Fn(U) -> Option<T> + Send + Sync + 'static,
{
fn send(self: Box<Self>, value: U) -> BoxFuture<Result<(), SendError>> {
let Self { inner, f } = *self;
let opt = f(value);
Box::pin(async move {
if let Some(v) = opt {
inner.send(v).await
} else {
Ok(())
}
})
}
fn is_rpc(&self) -> bool {
self.inner.is_rpc()
}
}
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(FusedOneshotReceiver<T>),
Boxed(BoxedReceiver<T>),
}
impl<T> Future for Receiver<T> {
type Output = Result<T, RecvError>;
fn poll(self: Pin<&mut Self>, cx: &mut task::Context) -> task::Poll<Self::Output> {
match &mut self.get_mut().0 {
ReceiverInner::Tokio(rx) => Pin::new(rx)
.poll(cx)
.map_err(|_| e!(RecvError::SenderClosed)),
ReceiverInner::Boxed(rx) => Pin::new(rx).poll(cx),
}
}
}
impl<T> From<tokio::sync::oneshot::Receiver<T>> for Receiver<T> {
fn from(rx: tokio::sync::oneshot::Receiver<T>) -> Self {
Self(ReceiverInner::Tokio(FusedOneshotReceiver(rx)))
}
}
impl<T> TryFrom<Receiver<T>> for tokio::sync::oneshot::Receiver<T> {
type Error = Receiver<T>;
fn try_from(value: Receiver<T>) -> Result<Self, Self::Error> {
match value.0 {
ReceiverInner::Tokio(tx) => Ok(tx.0),
ReceiverInner::Boxed(_) => Err(value),
}
}
}
impl<T, F, Fut> From<F> for Receiver<T>
where
F: FnOnce() -> Fut,
Fut: Future<Output = Result<T, RecvError>> + Send + 'static,
{
fn from(f: F) -> Self {
Self(ReceiverInner::Boxed(Box::pin(f())))
}
}
impl<T> Debug for Receiver<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.0 {
ReceiverInner::Tokio(_) => f.debug_tuple("Tokio").finish(),
ReceiverInner::Boxed(_) => f.debug_tuple("Boxed").finish(),
}
}
}
impl<T> crate::sealed::Sealed for Receiver<T> {}
impl<T> crate::Receiver for Receiver<T> {}