use core::{cell::Cell, task::Waker};
use std::{rc::Rc, vec::Vec};
use crate::{cell::LocalCell, queue::Flavor};
pub(super) struct Chan<T> {
flavor: LocalCell<Flavor<T>>,
redelivery: LocalCell<Option<T>>,
senders: Cell<usize>,
receivers: Cell<usize>,
recv_wakers: LocalCell<Vec<(u64, Waker)>>,
next_recv_id: Cell<u64>,
send_wakers: LocalCell<Vec<(u64, Waker)>>,
next_send_id: Cell<u64>,
}
impl<T> Chan<T> {
pub(super) fn bounded(cap: usize) -> Rc<Self> {
Self::new(Flavor::bounded(cap))
}
pub(super) fn unbounded() -> Rc<Self> {
Self::new(Flavor::unbounded())
}
fn new(flavor: Flavor<T>) -> Rc<Self> {
Rc::new(Self {
flavor: LocalCell::new(flavor),
redelivery: LocalCell::new(None),
senders: Cell::new(1),
receivers: Cell::new(1),
recv_wakers: LocalCell::new(Vec::new()),
next_recv_id: Cell::new(0),
send_wakers: LocalCell::new(Vec::new()),
next_send_id: Cell::new(0),
})
}
pub(super) fn cap(&self) -> Option<usize> {
self.flavor.borrow().cap()
}
pub(super) fn len(&self) -> usize {
self.flavor.borrow().len() + usize::from(self.redelivery.borrow().is_some())
}
pub(super) fn is_empty(&self) -> bool {
self.redelivery.borrow().is_none() && self.flavor.borrow().is_empty()
}
pub(super) fn is_full(&self) -> bool {
self.flavor.borrow().is_full()
}
#[inline(always)]
pub(super) fn receiver_alive(&self) -> bool {
self.receivers.get() > 0
}
pub(super) fn senders(&self) -> usize {
self.senders.get()
}
pub(super) fn incr_senders(&self) {
self.senders.set(self.senders.get() + 1);
}
pub(super) fn decr_senders(&self) -> usize {
let n = self.senders.get();
self.senders.set(n - 1);
n
}
pub(super) fn incr_receivers(&self) {
self.receivers.set(self.receivers.get() + 1);
}
pub(super) fn decr_receivers(&self) -> usize {
let n = self.receivers.get();
self.receivers.set(n - 1);
n
}
pub(super) fn add_recv_waker(&self, waker: &Waker) -> u64 {
let waker = waker.clone();
let id = self.next_recv_id.get();
self.next_recv_id.set(id.wrapping_add(1));
self.recv_wakers.borrow_mut().push((id, waker));
id
}
pub(super) fn remove_recv_waker(&self, id: u64) {
let removed = {
let mut wakers = self.recv_wakers.borrow_mut();
wakers
.iter()
.position(|(wid, _)| *wid == id)
.map(|pos| wakers.swap_remove(pos))
};
drop(removed);
}
#[inline(always)]
pub(super) fn wake_receivers(&self) {
if self.recv_wakers.borrow().is_empty() {
return;
}
let wakers = {
let mut list = self.recv_wakers.borrow_mut();
core::mem::take(&mut *list)
};
wake_all(wakers);
}
pub(super) fn add_send_waker(&self, waker: &Waker) -> u64 {
let waker = waker.clone();
let id = self.next_send_id.get();
self.next_send_id.set(id.wrapping_add(1));
self.send_wakers.borrow_mut().push((id, waker));
id
}
pub(super) fn remove_send_waker(&self, id: u64) {
let removed = {
let mut wakers = self.send_wakers.borrow_mut();
wakers
.iter()
.position(|(wid, _)| *wid == id)
.map(|pos| wakers.swap_remove(pos))
};
drop(removed);
}
#[cfg(all(test, feature = "std"))]
pub(super) fn send_wakers_len(&self) -> usize {
self.send_wakers.borrow().len()
}
#[cfg(all(test, feature = "std"))]
pub(super) fn recv_wakers_len(&self) -> usize {
self.recv_wakers.borrow().len()
}
#[inline(always)]
pub(super) fn wake_senders(&self) {
if self.send_wakers.borrow().is_empty() {
return;
}
let wakers = {
let mut list = self.send_wakers.borrow_mut();
core::mem::take(&mut *list)
};
wake_all(wakers);
}
#[inline(always)]
pub(super) fn try_push(&self, item: T) -> Result<(), T> {
self.flavor.borrow_mut().try_push(item)
}
#[inline(always)]
pub(super) fn pop(&self) -> Option<T> {
self.flavor.borrow_mut().pop()
}
#[inline(always)]
pub(super) fn has_parked_senders(&self) -> bool {
!self.send_wakers.borrow().is_empty()
}
#[inline]
pub(super) fn try_take(&self) -> Option<T> {
loop {
if let Some(item) = self.redelivery.borrow_mut().take() {
return Some(item);
}
let item = self.flavor.borrow_mut().pop()?;
if !self.has_parked_senders() {
return Some(item);
}
*self.redelivery.borrow_mut() = Some(item);
self.wake_senders();
if let Some(item) = self.redelivery.borrow_mut().take() {
return Some(item);
}
}
}
pub(super) fn drain(&self) {
struct ContinueOnUnwind<'a, T>(&'a Chan<T>);
impl<T> Drop for ContinueOnUnwind<'_, T> {
fn drop(&mut self) {
self.0.drain();
}
}
let guard = ContinueOnUnwind(self);
let parked = self.redelivery.borrow_mut().take();
drop(parked);
while let Some(item) = self.pop() {
drop(item);
}
core::mem::forget(guard);
}
}
fn wake_all(wakers: Vec<(u64, Waker)>) {
#[cfg(feature = "std")]
{
let mut first_panic = None;
for (_id, waker) in wakers {
if let Err(panic) =
std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || waker.wake()))
{
if first_panic.is_none() {
first_panic = Some(panic);
}
}
}
if let Some(panic) = first_panic {
std::panic::resume_unwind(panic);
}
}
#[cfg(not(feature = "std"))]
{
struct WakeRest(Vec<(u64, Waker)>);
impl Drop for WakeRest {
fn drop(&mut self) {
for (_id, waker) in core::mem::take(&mut self.0) {
waker.wake();
}
}
}
let mut rest = WakeRest(wakers);
while let Some((_id, waker)) = rest.0.pop() {
waker.wake();
}
}
}