#![allow(unsafe_code)]
use core::cell::{Cell, UnsafeCell};
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll, Waker};
use std::collections::VecDeque;
use crate::sync::local::waiters::{Key, State, Waiters};
use crate::sync::mpsc::error::TryRecvError;
pub(super) trait Limit {
fn release(&self, n: usize);
fn is_idle(&self) -> bool;
fn close(&self);
}
pub(super) struct Chan<T, L> {
queue: UnsafeCell<VecDeque<T>>,
rx_waker: Cell<Option<Waker>>,
senders: Cell<usize>,
rx_closed: Cell<bool>,
closed_waiters: Waiters,
pub(super) limit: L,
}
impl<T, L: Limit> Chan<T, L> {
pub(super) fn new(limit: L) -> Self {
Self {
queue: UnsafeCell::new(VecDeque::new()),
rx_waker: Cell::new(None),
senders: Cell::new(1),
rx_closed: Cell::new(false),
closed_waiters: Waiters::new(),
limit,
}
}
#[inline]
fn queue<R>(&self, f: impl FnOnce(&mut VecDeque<T>) -> R) -> R {
f(unsafe { &mut *self.queue.get() })
}
pub(super) fn len(&self) -> usize {
self.queue(|q| q.len())
}
pub(super) fn push(&self, value: T) {
self.queue(|q| q.push_back(value));
self.wake_rx();
}
fn pop(&self) -> Option<T> {
self.queue(|q| q.pop_front())
}
fn take_many(&self, buf: &mut Vec<T>, limit: usize) -> usize {
self.queue(|q| {
let n = q.len().min(limit);
buf.extend(q.drain(..n));
n
})
}
pub(super) fn wake_rx(&self) {
if let Some(waker) = self.rx_waker.take() {
waker.wake();
}
}
fn register_rx(&self, waker: &Waker) {
match self.rx_waker.take() {
Some(old) if old.will_wake(waker) => self.rx_waker.set(Some(old)),
old => {
self.rx_waker.set(Some(waker.clone()));
drop(old);
}
}
}
pub(super) fn add_sender(&self) {
self.senders.set(self.senders.get() + 1);
}
pub(super) fn drop_sender(&self) {
let left = self.senders.get() - 1;
self.senders.set(left);
if left == 0 {
self.wake_rx();
}
}
pub(super) fn is_closed(&self) -> bool {
self.rx_closed.get()
}
pub(super) fn rx_is_closed(&self) -> bool {
self.rx_closed.get() || self.senders.get() == 0
}
fn finished(&self) -> bool {
self.rx_is_closed() && self.len() == 0 && self.limit.is_idle()
}
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.wake_rx();
}
}
pub(super) fn poll_recv(&self, cx: &mut Context<'_>) -> Poll<Option<T>> {
if crate::coop::exhausted(cx.waker()) {
return Poll::Pending;
}
if let Some(value) = self.pop() {
self.limit.release(1);
crate::coop::spent_one();
return Poll::Ready(Some(value));
}
if self.finished() {
crate::coop::spent_one();
return Poll::Ready(None);
}
self.register_rx(cx.waker());
Poll::Pending
}
pub(super) 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;
}
let taken = self.take_many(buf, limit);
if taken > 0 {
self.limit.release(taken);
crate::coop::spent_one();
return Poll::Ready(taken);
}
if self.finished() {
crate::coop::spent_one();
return Poll::Ready(0);
}
self.register_rx(cx.waker());
Poll::Pending
}
pub(super) fn try_recv(&self) -> Result<T, TryRecvError> {
if let Some(value) = self.pop() {
self.limit.release(1);
return Ok(value);
}
if self.finished() {
Err(TryRecvError::Disconnected)
} else {
Err(TryRecvError::Empty)
}
}
pub(super) fn close_rx(&self) {
if self.rx_closed.replace(true) {
return;
}
self.limit.close();
while let Some(waker) = self.closed_waiters.close_front() {
if let Some(waker) = waker {
waker.wake();
}
}
}
pub(super) fn drop_rx(&self) {
self.close_rx();
drop(self.rx_waker.take());
let left = self.queue(core::mem::take);
self.limit.release(left.len());
drop(left);
}
pub(super) fn closed(&self) -> ClosedWait<'_, T, L> {
ClosedWait {
chan: self,
key: None,
}
}
}
pub(super) struct ClosedWait<'a, T, L: Limit> {
chan: &'a Chan<T, L>,
key: Option<Key>,
}
impl<T, L: Limit> Future for ClosedWait<'_, T, L> {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
let this = self.get_mut();
let waiters = &this.chan.closed_waiters;
if this.chan.rx_closed.get() {
if let Some(key) = this.key.take() {
drop(waiters.cancel(key));
}
return Poll::Ready(());
}
if let Some(key) = this.key.take() {
if waiters.refresh(key, cx.waker()) == State::Waiting {
this.key = Some(key);
return Poll::Pending;
}
drop(waiters.cancel(key));
}
this.key = Some(waiters.push(0, cx.waker().clone()));
Poll::Pending
}
}
impl<T, L: Limit> Drop for ClosedWait<'_, T, L> {
fn drop(&mut self) {
if let Some(key) = self.key.take() {
drop(self.chan.closed_waiters.cancel(key));
}
}
}