use crate::sync::ring_deque::{self, RingDeque};
use core::{fmt, task::Poll};
use std::{
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
task::Waker,
};
pub use ring_deque::{Capacity, Closed, Priority};
pub fn new<T>(cap: impl Into<Capacity>) -> (Sender<T>, Receiver<T>) {
let cap = cap.into();
assert!(cap.max >= 1, "capacity must be at least 2");
let channel = Arc::new(Channel {
queue: RingDeque::new(cap),
sender_count: AtomicUsize::new(1),
});
let s = Sender {
channel: channel.clone(),
};
let r = Receiver { channel };
(s, r)
}
struct Channel<T> {
queue: RingDeque<T, Option<Waker>>,
sender_count: AtomicUsize,
}
impl<T> Channel<T> {
#[inline]
fn clone_for_sender(self: &Arc<Self>) -> Arc<Self> {
let count = self.sender_count.fetch_add(1, Ordering::Relaxed);
assert!(count < usize::MAX / 2, "too many senders");
self.clone()
}
fn close(&self) -> Result<(), Closed> {
self.queue.close()?;
Ok(())
}
}
pub struct Sender<T> {
channel: Arc<Channel<T>>,
}
impl<T> Sender<T> {
#[inline]
pub fn send_back(&self, msg: T) -> Result<Option<T>, Closed> {
let res = self.channel.queue.push_back(msg)?;
Ok(res)
}
#[inline]
pub fn send_front(&self, msg: T) -> Result<Option<T>, Closed> {
let res = self.channel.queue.push_front(msg)?;
Ok(res)
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
if self.channel.sender_count.fetch_sub(1, Ordering::AcqRel) == 1 {
let _ = self.channel.close();
}
}
}
impl<T> fmt::Debug for Sender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Sender {{ .. }}")
}
}
impl<T> Clone for Sender<T> {
#[inline]
fn clone(&self) -> Sender<T> {
Sender {
channel: self.channel.clone_for_sender(),
}
}
}
pub struct Receiver<T> {
channel: Arc<Channel<T>>,
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
let _ = self.channel.close();
}
}
impl<T> Receiver<T> {
#[inline]
pub fn sender(&self) -> Sender<T> {
Sender {
channel: self.channel.clone_for_sender(),
}
}
#[inline]
pub fn try_recv_front(&self) -> Result<Option<T>, Closed> {
self.channel.queue.pop_front()
}
#[inline]
pub fn try_recv_back(&self) -> Result<Option<T>, Closed> {
self.channel.queue.pop_back()
}
#[inline]
pub async fn recv_front(&self) -> Result<T, Closed> {
core::future::poll_fn(|cx| self.poll_recv_front(cx)).await
}
#[inline]
pub fn poll_recv_front(&self, cx: &mut core::task::Context<'_>) -> Poll<Result<T, Closed>> {
self.channel.queue.poll_pop_front(cx)
}
#[inline]
pub async fn recv_back(&self) -> Result<T, Closed> {
core::future::poll_fn(|cx| self.poll_recv_back(cx)).await
}
#[inline]
pub fn poll_recv_back(&self, cx: &mut core::task::Context<'_>) -> Poll<Result<T, Closed>> {
self.channel.queue.poll_pop_back(cx)
}
#[inline]
pub async fn swap(&self, out: &mut std::collections::VecDeque<T>) -> Result<(), Closed> {
core::future::poll_fn(|cx| self.poll_swap(cx, out)).await
}
#[inline]
pub fn poll_swap(
&self,
cx: &mut core::task::Context<'_>,
out: &mut std::collections::VecDeque<T>,
) -> Poll<Result<(), Closed>> {
self.channel.queue.poll_swap(cx, out)
}
#[inline]
pub fn close(&self) -> Result<(), Closed> {
self.channel.close()
}
}
impl<T> fmt::Debug for Receiver<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Receiver {{ .. }}")
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testing::{ext::*, sim, task};
use std::time::Duration;
#[test]
fn test_unlimited() {
sim(|| {
let (tx, rx) = new(2);
async move {
for v in 0u64.. {
if tx.send_back(v).is_err() {
return;
};
task::yield_now().await;
}
}
.primary()
.spawn();
async move {
for expected in 0u64..10 {
let actual = rx.recv_front().await.unwrap();
assert_eq!(actual, expected);
}
}
.primary()
.spawn();
});
}
#[test]
fn test_send_limited() {
sim(|| {
let (tx, rx) = new(2);
async move {
for v in 0u64.. {
if tx.send_back(v).is_err() {
return;
};
Duration::from_millis(1).sleep().await;
}
}
.primary()
.spawn();
async move {
for expected in 0u64..10 {
let actual = rx.recv_front().await.unwrap();
assert_eq!(actual, expected);
}
}
.primary()
.spawn();
});
}
#[test]
fn test_recv_limited() {
sim(|| {
let (tx, rx) = new(2);
async move {
for v in 0u64.. {
match tx.send_back(v) {
Ok(Some(_old)) => {
Duration::from_millis(1).sleep().await;
}
Ok(None) => {
continue;
}
Err(_) => {
return;
}
}
}
}
.primary()
.spawn();
async move {
let mut min = 0;
for _ in 0u64..10 {
let actual = rx.recv_front().await.unwrap();
assert!(actual > min);
min = actual;
Duration::from_millis(1).sleep().await;
}
}
.primary()
.spawn();
});
}
}