#[cfg(feature = "std")]
use futures::executor::block_on;
#[derive(Debug, thiserror::Error)]
#[error("send on closed channel")]
pub struct SendError<T>(pub T);
impl<T> SendError<T> {
pub fn into_inner(self) -> T {
self.0
}
}
#[derive(Debug, thiserror::Error)]
pub enum TrySendError<T> {
#[error("channel full")]
Full(T),
#[error("channel closed")]
Closed(T),
}
impl<T> TrySendError<T> {
pub fn into_inner(self) -> T {
match self {
Self::Full(value) | Self::Closed(value) => value,
}
}
}
#[derive(Debug)]
pub struct Sender<T> {
inner: async_channel::Sender<T>,
}
impl<T> Clone for Sender<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl<T> Sender<T> {
pub async fn send(&self, value: T) -> Result<(), SendError<T>> {
self.inner
.send(value)
.await
.map_err(|error| SendError(error.0))
}
pub fn try_send(&self, value: T) -> Result<(), TrySendError<T>> {
match self.inner.try_send(value) {
Ok(()) => Ok(()),
Err(async_channel::TrySendError::Full(value)) => Err(TrySendError::Full(value)),
Err(async_channel::TrySendError::Closed(value)) => Err(TrySendError::Closed(value)),
}
}
pub fn is_closed(&self) -> bool {
self.inner.is_closed()
}
pub fn close(&self) -> bool {
self.inner.close()
}
}
#[derive(Debug)]
pub struct Receiver<T> {
inner: async_channel::Receiver<T>,
}
impl<T> Receiver<T> {
pub async fn recv(&mut self) -> Option<T> {
self.inner.recv().await.ok()
}
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub fn recv_blocking(&self) -> Option<T> {
block_on(self.inner.recv()).ok()
}
pub fn close(&mut self) -> bool {
self.inner.close()
}
}
pub fn channel<T>(capacity: usize) -> (Sender<T>, Receiver<T>) {
let (sender, receiver) = async_channel::bounded(capacity.max(1));
(Sender { inner: sender }, Receiver { inner: receiver })
}
#[derive(Debug)]
pub struct UnboundedSender<T> {
inner: async_channel::Sender<T>,
}
impl<T> Clone for UnboundedSender<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl<T> UnboundedSender<T> {
pub fn send(&self, value: T) -> Result<(), SendError<T>> {
match self.inner.try_send(value) {
Ok(()) => Ok(()),
Err(async_channel::TrySendError::Closed(value)) => Err(SendError(value)),
Err(async_channel::TrySendError::Full(_)) => {
unreachable!("unbounded channel reported full")
}
}
}
pub fn is_closed(&self) -> bool {
self.inner.is_closed()
}
}
#[derive(Debug)]
pub struct UnboundedReceiver<T> {
inner: async_channel::Receiver<T>,
}
impl<T> UnboundedReceiver<T> {
pub async fn recv(&mut self) -> Option<T> {
self.inner.recv().await.ok()
}
pub fn close(&mut self) -> bool {
self.inner.close()
}
}
pub fn unbounded_channel<T>() -> (UnboundedSender<T>, UnboundedReceiver<T>) {
let (sender, receiver) = async_channel::unbounded();
(
UnboundedSender { inner: sender },
UnboundedReceiver { inner: receiver },
)
}
#[cfg(all(test, not(loom)))]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
use futures::executor::block_on;
#[test]
fn bounded_send_recv_roundtrips() {
let (sender, mut receiver) = channel::<u32>(4);
block_on(async move {
sender.send(7).await.expect("send");
assert_eq!(receiver.recv().await, Some(7));
});
}
#[test]
fn bounded_try_send_returns_full_when_at_capacity() {
let (sender, _receiver) = channel::<u32>(1);
sender.try_send(1).expect("first slot");
match sender.try_send(2) {
Err(TrySendError::Full(value)) => assert_eq!(value, 2),
other => panic!("expected Full, got {other:?}"),
}
}
#[test]
fn bounded_send_returns_value_after_receiver_dropped() {
let (sender, receiver) = channel::<u32>(1);
drop(receiver);
block_on(async move {
match sender.send(9).await {
Err(error) => assert_eq!(error.into_inner(), 9),
Ok(()) => panic!("send to dropped receiver should error"),
}
});
}
#[test]
fn mpsc_sender_close_returns_pending_send_and_drains_accepted_values() {
let (sender, mut receiver) = channel::<u32>(1);
sender.try_send(11).expect("first value should be accepted");
block_on(async move {
let mut pending_send = core::pin::pin!(sender.send(22));
let first_poll = futures::future::poll_fn(|context| {
core::task::Poll::Ready(pending_send.as_mut().poll(context))
})
.await;
assert!(matches!(first_poll, core::task::Poll::Pending));
assert!(sender.close());
match pending_send.await {
Err(error) => assert_eq!(error.into_inner(), 22),
Ok(()) => panic!("close should return a send that was waiting for capacity"),
}
assert_eq!(receiver.recv().await, Some(11));
assert_eq!(receiver.recv().await, None);
});
}
#[test]
fn mpsc_receiver_blocking_drains_after_sender_close() {
let (sender, receiver) = channel::<u32>(1);
sender.try_send(31).expect("value should be accepted");
assert!(sender.close());
assert_eq!(receiver.recv_blocking(), Some(31));
assert_eq!(receiver.recv_blocking(), None);
}
#[test]
fn unbounded_send_recv_roundtrips() {
let (sender, mut receiver) = unbounded_channel::<u32>();
sender.send(42).expect("send");
block_on(async move {
assert_eq!(receiver.recv().await, Some(42));
});
}
#[test]
fn unbounded_send_returns_value_after_receiver_dropped() {
let (sender, receiver) = unbounded_channel::<u32>();
drop(receiver);
match sender.send(3) {
Err(error) => assert_eq!(error.into_inner(), 3),
Ok(()) => panic!("send to dropped receiver should error"),
}
}
}