use core::fmt;
use core::future::poll_fn;
use core::task::{Context, Poll};
use super::chan::{Chan, Limit};
use super::error::{SendError, TryRecvError};
use super::queue;
use crate::sync::internal::{self, Arc, AtomicUsize, Ordering};
const CLOSED: usize = 1;
const ONE: usize = 2;
pub(super) struct Unbounded(AtomicUsize);
impl Unbounded {
#[inline]
fn admit(&self) -> bool {
let before = self.0.fetch_add(ONE, Ordering::AcqRel);
if before & CLOSED == 0 {
return true;
}
self.0.fetch_sub(ONE, Ordering::AcqRel);
false
}
}
impl Limit for Unbounded {
type Queue<T> = queue::Radix<T>;
fn queue<T>(&self) -> queue::Radix<T> {
queue::Radix::new()
}
#[inline]
fn is_idle(&self) -> bool {
self.0.load(Ordering::Acquire) >> 1 == 0
}
#[inline]
fn release(&self, n: usize) {
let before = self.0.fetch_sub(n * ONE, Ordering::AcqRel);
debug_assert!(before >> 1 >= n, "released more values than were admitted");
}
fn close(&self) {
self.0.fetch_or(CLOSED, Ordering::AcqRel);
}
#[inline]
fn is_closed(&self) -> bool {
self.0.load(Ordering::Acquire) & CLOSED != 0
}
}
pub fn unbounded_channel<T>() -> (UnboundedSender<T>, UnboundedReceiver<T>) {
let chan = Arc::new(Chan::new(Unbounded(AtomicUsize::new(0))));
let tx = UnboundedSender {
chan: Arc::clone(&chan),
};
(tx, UnboundedReceiver { chan })
}
pub struct UnboundedSender<T> {
chan: Arc<Chan<T, Unbounded>>,
}
pub struct WeakUnboundedSender<T> {
chan: Arc<Chan<T, Unbounded>>,
}
pub struct UnboundedReceiver<T> {
chan: Arc<Chan<T, Unbounded>>,
}
impl<T> UnboundedSender<T> {
pub fn send(&self, message: T) -> Result<(), SendError<T>> {
if !self.chan.limit.admit() {
self.chan.wake_if_finished();
return Err(SendError(message));
}
self.chan.send(message);
Ok(())
}
pub async fn closed(&self) {
self.chan.closed().await;
}
pub fn is_closed(&self) -> bool {
self.chan.is_closed()
}
pub fn same_channel(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.chan, &other.chan)
}
#[must_use = "Downgrade creates a WeakUnboundedSender without destroying the original non-weak sender."]
pub fn downgrade(&self) -> WeakUnboundedSender<T> {
self.chan.add_weak();
WeakUnboundedSender {
chan: Arc::clone(&self.chan),
}
}
pub fn strong_count(&self) -> usize {
self.chan.strong_count()
}
pub fn weak_count(&self) -> usize {
self.chan.weak_count()
}
}
impl<T> Clone for UnboundedSender<T> {
fn clone(&self) -> Self {
self.chan.add_sender();
UnboundedSender {
chan: Arc::clone(&self.chan),
}
}
}
impl<T> Drop for UnboundedSender<T> {
fn drop(&mut self) {
self.chan.drop_sender();
}
}
impl<T> fmt::Debug for UnboundedSender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("UnboundedSender")
.field("closed", &self.is_closed())
.finish()
}
}
impl<T> WeakUnboundedSender<T> {
pub fn upgrade(&self) -> Option<UnboundedSender<T>> {
self.chan.try_add_sender().then(|| UnboundedSender {
chan: Arc::clone(&self.chan),
})
}
pub fn strong_count(&self) -> usize {
self.chan.strong_count()
}
pub fn weak_count(&self) -> usize {
self.chan.weak_count()
}
}
impl<T> Clone for WeakUnboundedSender<T> {
fn clone(&self) -> Self {
self.chan.add_weak();
WeakUnboundedSender {
chan: Arc::clone(&self.chan),
}
}
}
impl<T> Drop for WeakUnboundedSender<T> {
fn drop(&mut self) {
self.chan.drop_weak();
}
}
impl<T> fmt::Debug for WeakUnboundedSender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WeakUnboundedSender").finish()
}
}
impl<T> UnboundedReceiver<T> {
pub async fn recv(&mut self) -> Option<T> {
poll_fn(|cx| self.poll_recv(cx)).await
}
pub async fn recv_many(&mut self, buffer: &mut Vec<T>, limit: usize) -> usize {
poll_fn(|cx| self.poll_recv_many(cx, buffer, limit)).await
}
pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
unsafe { self.chan.try_recv() }
}
pub fn blocking_recv(&mut self) -> Option<T> {
internal::blocking(self.recv())
}
pub fn blocking_recv_many(&mut self, buffer: &mut Vec<T>, limit: usize) -> usize {
internal::blocking(self.recv_many(buffer, limit))
}
pub fn close(&mut self) {
self.chan.close_rx();
}
pub fn is_closed(&self) -> bool {
self.chan.rx_is_closed()
}
pub fn is_empty(&self) -> bool {
self.chan.len() == 0
}
pub fn len(&self) -> usize {
self.chan.len()
}
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
unsafe { self.chan.poll_recv(cx) }
}
pub fn poll_recv_many(
&mut self,
cx: &mut Context<'_>,
buffer: &mut Vec<T>,
limit: usize,
) -> Poll<usize> {
unsafe { self.chan.poll_recv_many(cx, buffer, limit) }
}
pub fn sender_strong_count(&self) -> usize {
self.chan.strong_count()
}
pub fn sender_weak_count(&self) -> usize {
self.chan.weak_count()
}
}
impl<T> Drop for UnboundedReceiver<T> {
fn drop(&mut self) {
unsafe { self.chan.drop_rx() };
}
}
impl<T> fmt::Debug for UnboundedReceiver<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("UnboundedReceiver")
.field("closed", &self.is_closed())
.field("len", &self.len())
.finish()
}
}
#[cfg(all(test, not(loom)))]
mod tests {
use super::*;
use crate::sync::test_support::Polled;
#[test]
fn the_word_counts_values_in_flight_above_the_closed_bit() {
let limit = Unbounded(AtomicUsize::new(0));
assert!(limit.is_idle() && !limit.is_closed());
assert!(limit.admit() && limit.admit());
assert!(!limit.is_idle());
limit.release(1);
assert!(!limit.is_idle());
limit.close();
limit.close();
assert!(limit.is_closed());
assert!(!limit.admit(), "a closed channel admits nothing");
limit.release(1);
assert!(limit.is_idle() && limit.is_closed());
}
#[test]
fn a_receiver_waiting_on_a_closed_channel_ends_when_the_last_value_is_taken() {
let (tx, mut rx) = unbounded_channel::<u8>();
tx.send(1).unwrap();
rx.close();
assert_eq!(rx.try_recv(), Ok(1));
assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
let mut recv = Polled::new(rx.recv());
assert_eq!(recv.ready(), None);
}
}