#![allow(unsafe_code)]
use core::task::{Context, Poll};
use std::panic::{RefUnwindSafe, UnwindSafe};
use super::error::TryRecvError;
use super::queue::MessageQueue;
use crate::sync::Event;
use crate::sync::atomic_waker::AtomicWaker;
use crate::sync::internal::{AtomicBool, AtomicUsize, Ordering, seq_cst_handshake};
pub(super) trait Limit {
type Queue<T>: MessageQueue<T>;
fn queue<T>(&self) -> Self::Queue<T>;
fn is_idle(&self) -> bool;
fn release(&self, n: usize);
fn close(&self);
fn is_closed(&self) -> bool;
}
enum Pop<T> {
Value(T),
Closed,
Empty,
}
pub(super) struct Chan<T, L: Limit> {
queue: L::Queue<T>,
rx_waker: AtomicWaker,
rx_waiting: AtomicBool,
rx_closed: Event,
pub(super) limit: L,
tx_count: AtomicUsize,
tx_weak_count: AtomicUsize,
}
impl<T, L: Limit> UnwindSafe for Chan<T, L> {}
impl<T, L: Limit> RefUnwindSafe for Chan<T, L> {}
impl<T, L: Limit> Chan<T, L> {
pub(super) fn new(limit: L) -> Self {
Self {
queue: limit.queue(),
rx_waker: AtomicWaker::new(),
rx_waiting: AtomicBool::new(false),
rx_closed: Event::new(),
limit,
tx_count: AtomicUsize::new(1),
tx_weak_count: AtomicUsize::new(0),
}
}
#[inline]
pub(super) fn send(&self, value: T) {
self.queue.push(value);
seq_cst_handshake();
if self.rx_waiting.load(Ordering::SeqCst) {
self.wake_waiting_rx();
}
}
#[inline(never)]
fn wake_waiting_rx(&self) {
if self.rx_waiting.swap(false, Ordering::SeqCst) {
self.rx_waker.wake();
}
}
fn rx_says_it_waits(&self) {
self.rx_waiting.store(true, Ordering::SeqCst);
seq_cst_handshake();
}
fn rx_does_not_wait(&self) {
self.rx_waiting.store(false, Ordering::Relaxed);
}
pub(super) fn give_back(&self, n: usize) {
self.limit.release(n);
self.wake_if_finished();
}
pub(super) fn wake_if_finished(&self) {
if self.finished() {
self.rx_waker.wake();
}
}
pub(super) fn is_closed(&self) -> bool {
self.limit.is_closed()
}
pub(super) async fn closed(&self) {
if self.limit.is_closed() {
return;
}
self.rx_closed.wait().await;
}
pub(super) fn add_sender(&self) {
self.tx_count.fetch_add(1, Ordering::Relaxed);
}
pub(super) fn drop_sender(&self) {
if self.tx_count.fetch_sub(1, Ordering::AcqRel) == 1 {
self.rx_waker.wake();
}
}
pub(super) fn add_weak(&self) {
self.tx_weak_count.fetch_add(1, Ordering::Relaxed);
}
pub(super) fn drop_weak(&self) {
self.tx_weak_count.fetch_sub(1, Ordering::Relaxed);
}
pub(super) fn try_add_sender(&self) -> bool {
let mut count = self.tx_count.load(Ordering::Acquire);
loop {
if count == 0 {
return false;
}
match self.tx_count.compare_exchange_weak(
count,
count + 1,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => return true,
Err(actual) => count = actual,
}
}
}
pub(super) fn strong_count(&self) -> usize {
self.tx_count.load(Ordering::Acquire)
}
pub(super) fn weak_count(&self) -> usize {
self.tx_weak_count.load(Ordering::Relaxed)
}
pub(super) fn rx_is_closed(&self) -> bool {
self.limit.is_closed() || self.tx_count.load(Ordering::Acquire) == 0
}
pub(super) fn len(&self) -> usize {
self.queue.len()
}
unsafe fn pop(&self) -> Pop<T> {
if let Some(value) = unsafe { self.queue.try_pop() } {
return Pop::Value(value);
}
if self.tx_count.load(Ordering::Acquire) != 0 {
return Pop::Empty;
}
match unsafe { self.queue.try_pop() } {
Some(value) => Pop::Value(value),
None => Pop::Closed,
}
}
unsafe fn next(&self) -> Option<Option<T>> {
match unsafe { self.pop() } {
Pop::Value(value) => {
self.limit.release(1);
Some(Some(value))
}
Pop::Closed => Some(None),
Pop::Empty => None,
}
}
fn finished(&self) -> bool {
self.limit.is_closed() && self.limit.is_idle()
}
pub(super) unsafe fn poll_recv(&self, cx: &mut Context<'_>) -> Poll<Option<T>> {
if crate::coop::exhausted(cx.waker()) {
return Poll::Pending;
}
if let Some(done) = unsafe { self.next() } {
crate::coop::spent_one();
return Poll::Ready(done);
}
self.rx_waker.register(cx.waker());
self.rx_says_it_waits();
if let Some(done) = unsafe { self.next() } {
self.rx_does_not_wait();
crate::coop::spent_one();
return Poll::Ready(done);
}
if self.finished() {
crate::coop::spent_one();
Poll::Ready(None)
} else {
Poll::Pending
}
}
unsafe fn take_many(&self, buf: &mut Vec<T>, limit: usize) -> Option<usize> {
let mut taken = 0;
let ended = loop {
if taken == limit {
break false;
}
match unsafe { self.pop() } {
Pop::Value(value) => {
buf.push(value);
taken += 1;
}
Pop::Closed => break true,
Pop::Empty => break false,
}
};
if taken > 0 {
self.limit.release(taken);
}
(taken > 0 || ended).then_some(taken)
}
pub(super) unsafe fn poll_recv_many(
&self,
cx: &mut Context<'_>,
buf: &mut Vec<T>,
limit: usize,
) -> Poll<usize> {
if limit == 0 {
return Poll::Ready(0);
}
if crate::coop::exhausted(cx.waker()) {
return Poll::Pending;
}
if let Some(taken) = unsafe { self.take_many(buf, limit) } {
crate::coop::spent_one();
return Poll::Ready(taken);
}
self.rx_waker.register(cx.waker());
self.rx_says_it_waits();
if let Some(taken) = unsafe { self.take_many(buf, limit) } {
self.rx_does_not_wait();
crate::coop::spent_one();
return Poll::Ready(taken);
}
if self.finished() {
crate::coop::spent_one();
Poll::Ready(0)
} else {
Poll::Pending
}
}
pub(super) unsafe fn try_recv(&self) -> Result<T, TryRecvError> {
match unsafe { self.pop() } {
Pop::Value(value) => {
self.limit.release(1);
Ok(value)
}
Pop::Closed => Err(TryRecvError::Disconnected),
Pop::Empty if self.finished() => Err(TryRecvError::Disconnected),
Pop::Empty => Err(TryRecvError::Empty),
}
}
pub(super) fn close_rx(&self) {
self.limit.close();
self.rx_closed.set();
}
unsafe fn drain(&self) {
while let Some(value) = unsafe { self.queue.try_pop() } {
self.limit.release(1);
drop(value);
}
}
pub(super) unsafe fn drop_rx(&self) {
struct Drain<'a, T, L: Limit>(&'a Chan<T, L>);
impl<T, L: Limit> Drop for Drain<'_, T, L> {
fn drop(&mut self) {
unsafe { self.0.drain() };
}
}
self.close_rx();
drop(self.rx_waker.take());
let guard = Drain(self);
unsafe { guard.0.drain() };
}
}