use parking_lot::Mutex;
use smallvec::SmallVec;
use std::collections::VecDeque;
use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Arc, Weak};
use std::task::{Context, Poll, Waker};
use crate::cx::Cx;
use crate::runtime::reactor::token::{SlabToken, TokenSlab};
use crate::types::outcome::Outcome;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SendError<T> {
Disconnected(T),
Cancelled(T),
Full(T),
}
impl<T> std::fmt::Display for SendError<T> {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Disconnected(_) => write!(f, "sending on a closed mpsc channel"),
Self::Cancelled(_) => write!(f, "send operation cancelled"),
Self::Full(_) => write!(f, "mpsc channel is full"),
}
}
}
impl<T: std::fmt::Debug> std::error::Error for SendError<T> {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum CheckedSendError<T> {
Channel(SendError<T>),
Admission {
error: crate::runtime::obligation_mailbox::ObligationAdmissionError,
value: T,
},
}
impl<T> From<SendError<T>> for CheckedSendError<T> {
fn from(error: SendError<T>) -> Self {
Self::Channel(error)
}
}
impl<T> std::fmt::Display for CheckedSendError<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Channel(error) => write!(f, "{error}"),
Self::Admission { error, .. } => write!(f, "{error}"),
}
}
}
impl<T: std::fmt::Debug> std::error::Error for CheckedSendError<T> {}
impl CheckedSendError<()> {
fn with_value<T>(self, value: T) -> CheckedSendError<T> {
match self {
Self::Channel(SendError::Disconnected(())) => {
CheckedSendError::Channel(SendError::Disconnected(value))
}
Self::Channel(SendError::Cancelled(())) => {
CheckedSendError::Channel(SendError::Cancelled(value))
}
Self::Channel(SendError::Full(())) => CheckedSendError::Channel(SendError::Full(value)),
Self::Admission { error, value: () } => CheckedSendError::Admission { error, value },
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RecvError {
Disconnected,
Cancelled,
Empty,
}
impl std::fmt::Display for RecvError {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Disconnected => write!(f, "receiving on a closed mpsc channel"),
Self::Cancelled => write!(f, "[ASUP-E203] receive operation cancelled"),
Self::Empty => write!(f, "mpsc channel is empty"),
}
}
}
impl std::error::Error for RecvError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MpscTelemetrySnapshot {
pub channel_id: u64,
pub channel_kind: &'static str,
pub capacity: usize,
pub queued_messages: usize,
pub reserved_uncommitted_obligations: usize,
pub send_waiter_count: usize,
pub recv_waiter_count: usize,
pub receiver_health: &'static str,
pub lagged_receiver_count: Option<usize>,
pub cancellation_count: u64,
pub closed: bool,
}
#[derive(Debug)]
struct RegisteredWaker {
waker: Waker,
}
impl RegisteredWaker {
#[inline]
fn new(waker: &Waker) -> Arc<Self> {
Arc::new(Self {
waker: waker.clone(),
})
}
#[inline]
fn will_wake(&self, waker: &Waker) -> bool {
self.waker.will_wake(waker)
}
#[inline]
fn wake_by_ref(&self) {
self.waker.wake_by_ref();
}
}
struct PreparedReceiverWaker {
registration: Arc<RegisteredWaker>,
wake_epoch: u64,
}
#[derive(Debug)]
struct ChannelInner<T> {
queue: VecDeque<T>,
reserved: usize,
send_wakers: TokenSlab<Arc<RegisteredWaker>>,
waiter_queue: VecDeque<SlabToken>,
recv_waker: Option<Arc<RegisteredWaker>>,
recv_wake_epoch: u64,
cancellation_count: u64,
}
struct ChannelShared<T> {
inner: Mutex<ChannelInner<T>>,
sender_count: AtomicUsize,
receiver_dropped: AtomicBool,
capacity: usize,
}
impl<T: std::fmt::Debug> std::fmt::Debug for ChannelShared<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ChannelShared")
.field("inner", &self.inner)
.field("sender_count", &self.sender_count.load(Ordering::Acquire))
.finish_non_exhaustive()
}
}
impl<T> ChannelInner<T> {
#[inline]
fn new(capacity: usize) -> Self {
let queue = if capacity == usize::MAX {
VecDeque::new()
} else {
VecDeque::with_capacity(capacity)
};
Self {
queue,
reserved: 0,
send_wakers: TokenSlab::with_capacity(4),
waiter_queue: VecDeque::with_capacity(4),
recv_waker: None,
recv_wake_epoch: 0,
cancellation_count: 0,
}
}
#[inline]
fn used_slots(&self) -> usize {
self.queue.len().saturating_add(self.reserved)
}
#[inline]
fn has_capacity(&self, capacity: usize) -> bool {
self.used_slots() < capacity
}
#[inline]
fn prune_stale_waiter_front(&mut self) {
while let Some(&token) = self.waiter_queue.front() {
if self.send_wakers.get(token).is_some() {
break;
}
self.waiter_queue.pop_front();
}
}
#[inline]
fn has_waiting_sender(&mut self) -> bool {
self.prune_stale_waiter_front();
!self.waiter_queue.is_empty()
}
#[inline]
fn take_next_sender_waker(&mut self) -> Option<Arc<RegisteredWaker>> {
self.prune_stale_waiter_front();
self.waiter_queue
.front()
.and_then(|&token| self.send_wakers.get(token))
.cloned()
}
#[inline]
fn sender_wakers_for_freed_slots(
&mut self,
freed_slots: usize,
capacity: usize,
) -> SmallVec<[Arc<RegisteredWaker>; 4]> {
let wake_budget = freed_slots.min(capacity.saturating_sub(self.used_slots()));
if wake_budget == 0 {
return SmallVec::new();
}
self.prune_stale_waiter_front();
let mut wakers = SmallVec::new();
for &token in &self.waiter_queue {
if wakers.len() == wake_budget {
break;
}
if let Some(waker) = self.send_wakers.get(token) {
wakers.push(Arc::clone(waker));
}
}
wakers
}
fn drain_sender_wakers(&mut self) -> SmallVec<[Arc<RegisteredWaker>; 4]> {
let mut wakers = SmallVec::with_capacity(self.waiter_queue.len());
while let Some(token) = self.waiter_queue.pop_front() {
if let Some(waker) = self.send_wakers.remove(token) {
wakers.push(waker);
}
}
wakers
}
#[inline]
fn record_cancellation(&mut self) {
self.cancellation_count = self.cancellation_count.saturating_add(1);
}
#[inline]
fn remove_waiter_token(&mut self, token: crate::runtime::reactor::token::SlabToken) -> bool {
if self.waiter_queue.front().copied() == Some(token) {
self.waiter_queue.pop_front();
return true;
}
if self.waiter_queue.back().copied() == Some(token) {
self.waiter_queue.pop_back();
return true;
}
let mut found = false;
self.waiter_queue.retain(|&t| {
if !found && t == token {
found = true;
false } else {
true }
});
found
}
}
#[cfg(any(test, feature = "test-internals"))]
#[doc(hidden)]
pub struct MpscWaiterCancelFixture {
inner: ChannelInner<()>,
token: SlabToken,
}
#[cfg(any(test, feature = "test-internals"))]
impl MpscWaiterCancelFixture {
#[must_use]
pub fn oldest(waiter_count: usize) -> Self {
let waiter_count = waiter_count.max(1);
let mut inner = ChannelInner::new(usize::MAX);
let waker = Arc::new(RegisteredWaker {
waker: Waker::noop().clone(),
});
let mut target = None;
for index in 0..waiter_count {
let token = inner.send_wakers.insert(Arc::clone(&waker));
if index == 0 {
target = Some(token);
}
inner.waiter_queue.push_back(token);
}
Self {
inner,
token: target.expect("oldest waiter fixture always inserts a target"),
}
}
pub fn remove_target(mut self) -> bool {
self.inner.remove_waiter_token(self.token)
}
}
impl<T> ChannelShared<T> {
#[inline]
fn telemetry_snapshot(&self, channel_id: u64) -> MpscTelemetrySnapshot {
let mut inner = self.inner.lock();
let sender_count = self.sender_count.load(Ordering::Acquire);
let receiver_dropped = self.receiver_dropped.load(Ordering::Acquire);
let queued_messages = inner.queue.len();
let recv_waiter_count = usize::from(inner.recv_waker.is_some());
let send_waiter_count = {
inner.prune_stale_waiter_front();
inner.waiter_queue.len()
};
let closed = receiver_dropped || sender_count == 0;
let receiver_health = if receiver_dropped {
"receiver_dropped"
} else if queued_messages > 0 {
"value_ready"
} else if sender_count == 0 {
"sender_closed"
} else if recv_waiter_count > 0 {
"waiting"
} else {
"open"
};
MpscTelemetrySnapshot {
channel_id,
channel_kind: "mpsc",
capacity: self.capacity,
queued_messages,
reserved_uncommitted_obligations: inner.reserved,
send_waiter_count,
recv_waiter_count,
receiver_health,
lagged_receiver_count: None,
cancellation_count: inner.cancellation_count,
closed,
}
}
}
#[inline]
#[must_use]
pub fn channel<T>(capacity: usize) -> (Sender<T>, Receiver<T>) {
assert!(capacity > 0, "channel capacity must be non-zero");
let shared = Arc::new(ChannelShared {
inner: Mutex::new(ChannelInner::new(capacity)),
sender_count: AtomicUsize::new(1),
receiver_dropped: AtomicBool::new(false),
capacity,
});
let sender = Sender {
shared: Arc::clone(&shared),
};
let receiver = Receiver { shared };
(sender, receiver)
}
#[inline]
#[must_use]
pub fn unbounded_channel<T>() -> (UnboundedSender<T>, UnboundedReceiver<T>) {
let (sender, receiver) = channel(usize::MAX);
(
UnboundedSender { inner: sender },
UnboundedReceiver { inner: receiver },
)
}
#[inline]
#[must_use]
pub fn unbounded<T>() -> (UnboundedSender<T>, UnboundedReceiver<T>) {
unbounded_channel()
}
#[derive(Debug)]
pub struct Sender<T> {
shared: Arc<ChannelShared<T>>,
}
impl<T> Sender<T> {
#[inline]
#[must_use]
pub fn reserve<'a>(&'a self, cx: &'a Cx) -> Reserve<'a, T> {
Reserve {
sender: self,
cx,
waiter_token: None,
completed: false,
}
}
#[must_use]
pub fn reserve_checked<'a>(&'a self, cx: &'a Cx) -> CheckedReserve<'a, T> {
CheckedReserve {
inner: self.reserve(cx),
}
}
pub async fn send_checked(&self, cx: &Cx, value: T) -> Result<(), CheckedSendError<T>> {
match self.reserve_checked(cx).await {
Ok(permit) => permit.try_send(value).map_err(CheckedSendError::Channel),
Err(error) => Err(error.with_value(value)),
}
}
pub fn try_reserve_checked(&self, cx: &Cx) -> Result<SendPermit<'_, T>, CheckedSendError<()>> {
if cx.checkpoint().is_err() {
return Err(CheckedSendError::Channel(SendError::Cancelled(())));
}
let mut permit = self.try_reserve().map_err(CheckedSendError::Channel)?;
permit.obligation = cx
.try_register_obligation_checked(
crate::record::ObligationKind::SendPermit,
cx.task_id(),
)
.map_err(|error| CheckedSendError::Admission { error, value: () })?;
Ok(permit)
}
pub fn try_send_checked(&self, cx: &Cx, value: T) -> Result<(), CheckedSendError<T>> {
match self.try_reserve_checked(cx) {
Ok(permit) => permit.try_send(value).map_err(CheckedSendError::Channel),
Err(error) => Err(error.with_value(value)),
}
}
#[inline]
pub async fn send(&self, cx: &Cx, value: T) -> Result<(), SendError<T>> {
let result = self.reserve(cx).await;
match result {
Ok(permit) => permit.try_send(value),
Err(SendError::<()>::Disconnected(())) => Err(SendError::Disconnected(value)),
Err(SendError::<()>::Full(())) => Err(SendError::Full(value)),
Err(SendError::<()>::Cancelled(())) => Err(SendError::Cancelled(value)),
}
}
#[inline]
pub fn try_reserve(&self) -> Result<SendPermit<'_, T>, SendError<()>> {
let mut inner = self.shared.inner.lock();
if self.shared.receiver_dropped.load(Ordering::Relaxed) {
return Err(SendError::<()>::Disconnected(()));
}
if inner.has_waiting_sender() {
return Err(SendError::<()>::Full(()));
}
if inner.has_capacity(self.shared.capacity) {
inner.reserved += 1;
drop(inner);
Ok(SendPermit {
sender: self,
sent: false,
obligation: None,
})
} else {
Err(SendError::<()>::Full(()))
}
}
#[inline]
pub fn try_send(&self, value: T) -> Result<(), SendError<T>> {
let recv_waker = {
let mut inner = self.shared.inner.lock();
if self.shared.receiver_dropped.load(Ordering::Relaxed) {
return Err(SendError::Disconnected(value));
}
if inner.has_waiting_sender() || !inner.has_capacity(self.shared.capacity) {
return Err(SendError::Full(value));
}
inner.queue.push_back(value);
inner.recv_waker.take()
};
if let Some(waker) = recv_waker {
waker.wake_by_ref();
}
Ok(())
}
#[inline]
#[must_use]
pub fn is_closed(&self) -> bool {
self.shared.receiver_dropped.load(Ordering::Acquire)
}
#[inline]
pub fn wake_receiver(&self) {
let mut inner = self.shared.inner.lock();
inner.recv_wake_epoch = inner.recv_wake_epoch.wrapping_add(1);
let waker = inner.recv_waker.take();
drop(inner);
if let Some(waker) = waker {
waker.wake_by_ref();
}
}
pub(crate) fn close_receiver(&self) {
let (send_wakers, recv_waker) = {
let mut inner = self.shared.inner.lock();
if self.shared.receiver_dropped.load(Ordering::Relaxed) {
return;
}
let send_wakers = inner.drain_sender_wakers();
self.shared.receiver_dropped.store(true, Ordering::Release);
let recv_waker = inner.recv_waker.take();
drop(inner);
(send_wakers, recv_waker)
};
for waker in send_wakers {
waker.wake_by_ref();
}
if let Some(waker) = recv_waker {
waker.wake_by_ref();
}
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.shared.capacity
}
#[inline]
#[must_use]
pub fn telemetry_snapshot(&self, channel_id: u64) -> MpscTelemetrySnapshot {
self.shared.telemetry_snapshot(channel_id)
}
#[cfg(test)]
pub(crate) fn debug_counts(&self) -> (usize, usize) {
let inner = self.shared.inner.lock();
(inner.queue.len(), inner.reserved)
}
#[inline]
pub fn send_evict_oldest(&self, value: T) -> Result<Option<T>, SendError<T>> {
self.send_evict_oldest_where(value, |_| true)
}
pub fn send_evict_oldest_where<F>(
&self,
value: T,
mut predicate: F,
) -> Result<Option<T>, SendError<T>>
where
F: FnMut(&T) -> bool,
{
let mut inner = self.shared.inner.lock();
if self.shared.receiver_dropped.load(Ordering::Relaxed) {
return Err(SendError::Disconnected(value));
}
let has_physical_capacity = inner.has_capacity(self.shared.capacity);
let waiter_owns_available_slot = has_physical_capacity && inner.has_waiting_sender();
let evicted = if waiter_owns_available_slot {
return Err(SendError::Full(value));
} else if has_physical_capacity {
None
} else if let Some(index) = inner.queue.iter().position(&mut predicate) {
Some(
inner
.queue
.remove(index)
.expect("position() returned a valid queue index"),
)
} else {
return Err(SendError::Full(value));
};
inner.queue.push_back(value);
let waker = inner.recv_waker.take();
drop(inner);
if let Some(waker) = waker {
waker.wake_by_ref();
}
Ok(evicted)
}
#[inline]
#[must_use]
pub fn downgrade(&self) -> WeakSender<T> {
WeakSender {
shared: Arc::downgrade(&self.shared),
}
}
}
pub struct Reserve<'a, T> {
sender: &'a Sender<T>,
cx: &'a Cx,
waiter_token: Option<SlabToken>,
completed: bool,
}
impl<T> Reserve<'_, T> {
fn cleanup_waiter(&mut self) {
if let Some(token) = self.waiter_token.take() {
let (next_waker, retired_waker) = {
let mut inner = self.sender.shared.inner.lock();
if self.sender.shared.receiver_dropped.load(Ordering::Relaxed) {
(None, inner.send_wakers.remove(token))
} else {
let retired_waker = inner.send_wakers.remove(token);
if retired_waker.is_none() {
(None, None)
} else {
let removed_from_queue = inner.remove_waiter_token(token);
let next_waker = if removed_from_queue
&& inner.has_capacity(self.sender.shared.capacity)
{
inner.take_next_sender_waker()
} else {
None
};
(next_waker, retired_waker)
}
}
};
drop(retired_waker);
if let Some(w) = next_waker {
w.wake_by_ref();
}
}
}
}
impl<'a, T> Reserve<'a, T> {
fn poll_with_registration<E>(
mut self: Pin<&mut Self>,
ctx: &mut Context<'_>,
register: impl FnOnce(
&Cx,
)
-> Result<Option<crate::runtime::obligation_mailbox::ObligationToken>, E>,
) -> Poll<Result<SendPermit<'a, T>, E>>
where
E: From<SendError<()>>,
{
assert!(
!self.completed,
"mpsc reserve future polled after completion"
);
let mut prepared_waker = None;
loop {
if self.cx.checkpoint().is_err() {
self.completed = true;
self.cx.trace("mpsc::reserve cancelled");
self.sender.shared.inner.lock().record_cancellation();
self.cleanup_waiter();
drop(prepared_waker);
return Poll::Ready(Err(SendError::<()>::Cancelled(()).into()));
}
let mut inner = self.sender.shared.inner.lock();
if self.sender.shared.receiver_dropped.load(Ordering::Relaxed) {
drop(inner);
self.waiter_token = None;
self.completed = true;
drop(prepared_waker);
return Poll::Ready(Err(SendError::<()>::Disconnected(()).into()));
}
let is_first = self.waiter_token.map_or_else(
|| inner.waiter_queue.is_empty(),
|token| inner.waiter_queue.front().copied() == Some(token),
);
if is_first && inner.has_capacity(self.sender.shared.capacity) {
inner.reserved += 1;
let mut retired_waker = None;
let mut cascade_waker = None;
if let Some(token) = self.waiter_token {
if inner.waiter_queue.front().copied() == Some(token) {
inner.waiter_queue.pop_front();
} else {
inner.remove_waiter_token(token);
}
retired_waker = inner.send_wakers.remove(token);
if inner.has_capacity(self.sender.shared.capacity) {
cascade_waker = inner.take_next_sender_waker();
}
}
drop(inner);
self.waiter_token = None;
self.completed = true;
let mut permit = SendPermit {
sender: self.sender,
sent: false,
obligation: None,
};
permit.obligation = match register(self.cx) {
Ok(obligation) => obligation,
Err(error) => return Poll::Ready(Err(error)),
};
drop(retired_waker);
drop(prepared_waker);
if let Some(waker) = cascade_waker {
waker.wake_by_ref();
}
return Poll::Ready(Ok(permit));
}
let current_waker = self
.waiter_token
.and_then(|token| inner.send_wakers.get(token));
if current_waker.is_some_and(|waker| waker.will_wake(ctx.waker())) {
drop(inner);
drop(prepared_waker);
return Poll::Pending;
}
let Some(new_waker) = prepared_waker.as_ref() else {
drop(inner);
prepared_waker = Some(RegisteredWaker::new(ctx.waker()));
continue;
};
let (retired_waker, inserted_token) = if let Some(token) = self.waiter_token {
let retired_waker = inner
.send_wakers
.get_mut(token)
.map(|slot| std::mem::replace(slot, Arc::clone(new_waker)));
(retired_waker, None)
} else {
let token = inner.send_wakers.insert(Arc::clone(new_waker));
inner.waiter_queue.push_back(token);
(None, Some(token))
};
drop(inner);
if let Some(token) = inserted_token {
self.waiter_token = Some(token);
}
let new_waker = prepared_waker
.take()
.expect("prepared sender waker remains owned until after unlock");
drop(retired_waker);
drop(new_waker);
return Poll::Pending;
}
}
}
impl<'a, T> Future for Reserve<'a, T> {
type Output = Result<SendPermit<'a, T>, SendError<()>>;
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
self.poll_with_registration(ctx, |cx| {
Ok(cx.try_register_obligation(crate::record::ObligationKind::SendPermit, cx.task_id()))
})
}
}
pub struct CheckedReserve<'a, T> {
inner: Reserve<'a, T>,
}
impl<'a, T> Future for CheckedReserve<'a, T> {
type Output = Result<SendPermit<'a, T>, CheckedSendError<()>>;
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut self.inner).poll_with_registration(ctx, |cx| {
cx.try_register_obligation_checked(
crate::record::ObligationKind::SendPermit,
cx.task_id(),
)
.map_err(|error| CheckedSendError::Admission { error, value: () })
})
}
}
impl<T> Drop for Reserve<'_, T> {
fn drop(&mut self) {
self.cleanup_waiter();
}
}
impl<T> Clone for Sender<T> {
#[inline]
fn clone(&self) -> Self {
self.shared.sender_count.fetch_add(1, Ordering::Relaxed);
Self {
shared: Arc::clone(&self.shared),
}
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
let old = self.shared.sender_count.fetch_sub(1, Ordering::Release);
debug_assert!(old > 0, "sender_count underflow in Sender::drop");
if old == 1 {
let recv_waker = {
let mut inner = self.shared.inner.lock();
inner.recv_waker.take()
};
if let Some(waker) = recv_waker {
waker.wake_by_ref();
}
}
}
}
pub struct WeakSender<T> {
shared: Weak<ChannelShared<T>>,
}
impl<T: std::fmt::Debug> std::fmt::Debug for WeakSender<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WeakSender").finish_non_exhaustive()
}
}
impl<T> WeakSender<T> {
#[inline]
#[must_use]
pub fn upgrade(&self) -> Option<Sender<T>> {
self.shared.upgrade().and_then(|shared| {
let mut observed = shared.sender_count.load(Ordering::Relaxed);
loop {
if observed == 0 {
return None;
}
match shared.sender_count.compare_exchange_weak(
observed,
observed + 1,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => return Some(Sender { shared }),
Err(actual) => observed = actual,
}
}
})
}
}
impl<T> Clone for WeakSender<T> {
#[inline]
fn clone(&self) -> Self {
Self {
shared: self.shared.clone(),
}
}
}
#[derive(Debug)]
pub struct UnboundedSender<T> {
inner: Sender<T>,
}
impl<T> UnboundedSender<T> {
#[inline]
#[must_use]
pub fn reserve<'a>(&'a self, cx: &'a Cx) -> Reserve<'a, T> {
self.inner.reserve(cx)
}
#[must_use]
pub fn reserve_checked<'a>(&'a self, cx: &'a Cx) -> CheckedReserve<'a, T> {
self.inner.reserve_checked(cx)
}
pub fn try_reserve_checked(&self, cx: &Cx) -> Result<SendPermit<'_, T>, CheckedSendError<()>> {
self.inner.try_reserve_checked(cx)
}
pub fn send_checked(&self, cx: &Cx, value: T) -> Result<(), CheckedSendError<T>> {
self.inner.try_send_checked(cx, value)
}
#[inline]
pub fn try_reserve(&self) -> Result<SendPermit<'_, T>, SendError<()>> {
self.inner.try_reserve()
}
#[inline]
pub fn send(&self, value: T) -> Result<(), SendError<T>> {
match self.try_reserve() {
Ok(permit) => permit.try_send(value),
Err(SendError::<()>::Disconnected(())) => Err(SendError::Disconnected(value)),
Err(SendError::<()>::Full(())) => Err(SendError::Full(value)),
Err(SendError::<()>::Cancelled(())) => Err(SendError::Cancelled(value)),
}
}
#[inline]
#[must_use]
pub fn is_closed(&self) -> bool {
self.inner.is_closed()
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
#[inline]
#[must_use]
pub fn telemetry_snapshot(&self, channel_id: u64) -> MpscTelemetrySnapshot {
self.inner.telemetry_snapshot(channel_id)
}
#[inline]
#[must_use]
pub fn downgrade(&self) -> WeakUnboundedSender<T> {
WeakUnboundedSender {
inner: self.inner.downgrade(),
}
}
}
impl<T> Clone for UnboundedSender<T> {
#[inline]
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
#[derive(Debug)]
pub struct WeakUnboundedSender<T> {
inner: WeakSender<T>,
}
impl<T> WeakUnboundedSender<T> {
#[inline]
#[must_use]
pub fn upgrade(&self) -> Option<UnboundedSender<T>> {
self.inner.upgrade().map(|inner| UnboundedSender { inner })
}
}
impl<T> Clone for WeakUnboundedSender<T> {
#[inline]
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
#[derive(Debug)]
#[must_use = "deferred receiver wake must be consumed after releasing external locks"]
pub(crate) struct DeferredReceiverWake {
receiver: Option<Arc<RegisteredWaker>>,
obligation: Option<Arc<crate::runtime::obligation_mailbox::ObligationGateway>>,
}
impl DeferredReceiverWake {
#[inline]
pub(crate) fn wake(mut self) {
let _wake = ReleasedCapacityWake(self.receiver.take());
if let Some(gateway) = self.obligation.take() {
gateway.notify();
}
}
}
#[derive(Debug)]
#[must_use = "SendPermit must be consumed via send() or abort()"]
pub struct SendPermit<'a, T> {
sender: &'a Sender<T>,
sent: bool,
obligation: Option<crate::runtime::obligation_mailbox::ObligationToken>,
}
#[inline]
fn resolve_send_obligation(
token: Option<crate::runtime::obligation_mailbox::ObligationToken>,
delivered: bool,
) -> Option<Arc<crate::runtime::obligation_mailbox::ObligationGateway>> {
token.and_then(|token| {
if delivered {
token.commit_deferred().1
} else {
token
.abort_deferred(crate::record::ObligationAbortReason::Error)
.1
}
})
}
struct ReleasedCapacityWake(Option<Arc<RegisteredWaker>>);
impl Drop for ReleasedCapacityWake {
fn drop(&mut self) {
let Some(waker) = self.0.take() else {
return;
};
let already_unwinding = std::thread::panicking();
let notified =
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| waker.wake_by_ref()));
let retired = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| drop(waker)));
let failure = match (notified, retired) {
(Err(primary), Err(secondary)) => {
std::mem::forget(secondary);
Some(primary)
}
(Err(error), Ok(())) | (Ok(()), Err(error)) => Some(error),
(Ok(()), Ok(())) => None,
};
if let Some(payload) = failure {
if already_unwinding {
std::mem::forget(payload);
} else {
std::panic::resume_unwind(payload);
}
}
}
}
impl<T> SendPermit<'_, T> {
#[inline]
pub fn send(self, value: T) -> Outcome<(), SendError<T>> {
match self.try_send(value) {
Ok(()) => Outcome::Ok(()),
Err(error) => Outcome::Err(error),
}
}
#[inline]
pub fn try_send(self, value: T) -> Result<(), SendError<T>> {
let (result, recv_waker) = self.try_send_deferred_wake(value);
recv_waker.wake();
result
}
#[inline]
pub(crate) fn try_send_deferred_wake(
mut self,
value: T,
) -> (Result<(), SendError<T>>, DeferredReceiverWake) {
self.sent = true;
let obligation = self.obligation.take();
let mut inner = self.sender.shared.inner.lock();
if inner.reserved == 0 {
debug_assert!(false, "send permit without reservation");
} else {
inner.reserved -= 1;
}
if self.sender.shared.receiver_dropped.load(Ordering::Relaxed) {
drop(inner);
let obligation = resolve_send_obligation(obligation, false);
return (
Err(SendError::Disconnected(value)),
DeferredReceiverWake {
receiver: None,
obligation,
},
);
}
inner.queue.push_back(value);
let recv_waker = inner.recv_waker.take();
drop(inner);
let obligation = resolve_send_obligation(obligation, true);
(
Ok(()),
DeferredReceiverWake {
receiver: recv_waker,
obligation,
},
)
}
#[inline]
pub fn abort(mut self) {
self.sent = true;
let _wake = self.release_capacity();
if let Some(token) = self.obligation.take() {
let _ = token.abort(crate::record::ObligationAbortReason::Explicit);
}
}
fn release_capacity(&self) -> ReleasedCapacityWake {
let next_waker = {
let mut inner = self.sender.shared.inner.lock();
if inner.reserved == 0 {
debug_assert!(false, "abort permit without reservation");
} else {
inner.reserved -= 1;
}
inner.record_cancellation();
inner.take_next_sender_waker()
};
ReleasedCapacityWake(next_waker)
}
#[inline]
#[must_use]
pub fn telemetry_snapshot(&self, channel_id: u64) -> MpscTelemetrySnapshot {
self.sender.shared.telemetry_snapshot(channel_id)
}
}
impl<T> Drop for SendPermit<'_, T> {
fn drop(&mut self) {
if !self.sent {
self.sent = true;
let _wake = self.release_capacity();
if let Some(token) = self.obligation.take() {
let _ = token.abort(crate::record::ObligationAbortReason::Cancel);
}
}
}
}
pub struct Receiver<T> {
shared: Arc<ChannelShared<T>>,
}
impl<T: std::fmt::Debug> std::fmt::Debug for Receiver<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Receiver")
.field("shared", &self.shared)
.finish()
}
}
impl<T> Receiver<T> {
pub(crate) fn clear_recv_waker(&mut self) {
let retired_waker = self.shared.inner.lock().recv_waker.take();
drop(retired_waker);
}
pub fn close(&mut self) {
let wakers = {
let mut inner = self.shared.inner.lock();
if self.shared.receiver_dropped.load(Ordering::Relaxed) {
return;
}
let wakers = inner.drain_sender_wakers();
self.shared.receiver_dropped.store(true, Ordering::Release);
drop(inner);
wakers
};
for waker in wakers {
waker.wake_by_ref();
}
}
#[inline]
#[must_use]
pub fn recv<'a, Caps>(&'a mut self, cx: &'a Cx<Caps>) -> Recv<'a, T, Caps> {
Recv {
receiver: self,
cx,
polled: false,
}
}
#[inline]
#[must_use]
pub fn recv_many<'a, Caps>(
&'a mut self,
cx: &'a Cx<Caps>,
buffer: &'a mut Vec<T>,
limit: usize,
) -> RecvMany<'a, T, Caps> {
RecvMany {
receiver: self,
cx,
buffer,
limit,
polled: false,
}
}
#[inline]
pub fn poll_recv<Caps>(
&mut self,
cx: &Cx<Caps>,
task_cx: &mut Context<'_>,
) -> Poll<Result<T, RecvError>> {
let mut prepared_waker: Option<PreparedReceiverWaker> = None;
loop {
if cx.checkpoint().is_err() {
cx.trace("mpsc::recv cancelled");
let retired_waker = {
let mut inner = self.shared.inner.lock();
let retired_waker = inner.recv_waker.take();
inner.record_cancellation();
retired_waker
};
drop(retired_waker);
drop(prepared_waker);
return Poll::Ready(Err(RecvError::Cancelled));
}
let mut inner = self.shared.inner.lock();
if let Some(value) = inner.queue.pop_front() {
let retired_waker = inner.recv_waker.take();
let next_waker = inner.take_next_sender_waker();
drop(inner);
drop(retired_waker);
drop(prepared_waker);
if let Some(waker) = next_waker {
waker.wake_by_ref();
}
return Poll::Ready(Ok(value));
}
if self.shared.sender_count.load(Ordering::Acquire) == 0
|| self.shared.receiver_dropped.load(Ordering::Relaxed)
{
let retired_waker = inner.recv_waker.take();
drop(inner);
drop(retired_waker);
drop(prepared_waker);
return Poll::Ready(Err(RecvError::Disconnected));
}
if inner
.recv_waker
.as_ref()
.is_some_and(|waker| waker.will_wake(task_cx.waker()))
{
drop(inner);
drop(prepared_waker);
return Poll::Pending;
}
let Some(prepared) = prepared_waker.as_ref() else {
let wake_epoch = inner.recv_wake_epoch;
drop(inner);
prepared_waker = Some(PreparedReceiverWaker {
registration: RegisteredWaker::new(task_cx.waker()),
wake_epoch,
});
continue;
};
let replay_wake = inner.recv_wake_epoch != prepared.wake_epoch;
let retired_waker = inner.recv_waker.replace(Arc::clone(&prepared.registration));
drop(inner);
let prepared = prepared_waker
.take()
.expect("prepared receiver waker remains owned until after unlock");
drop(retired_waker);
if replay_wake {
prepared.registration.wake_by_ref();
}
drop(prepared);
return Poll::Pending;
}
}
#[inline]
pub fn poll_recv_many<Caps>(
&mut self,
cx: &Cx<Caps>,
buffer: &mut Vec<T>,
limit: usize,
task_cx: &mut Context<'_>,
) -> Poll<Result<usize, RecvError>> {
if limit == 0 {
return Poll::Ready(Ok(0));
}
let mut prepared_waker: Option<PreparedReceiverWaker> = None;
loop {
if cx.checkpoint().is_err() {
cx.trace("mpsc::recv_many cancelled");
let retired_waker = {
let mut inner = self.shared.inner.lock();
let retired_waker = inner.recv_waker.take();
inner.record_cancellation();
retired_waker
};
drop(retired_waker);
drop(prepared_waker);
return Poll::Ready(Err(RecvError::Cancelled));
}
let mut inner = self.shared.inner.lock();
let target = limit.min(inner.queue.len());
if target > 0 {
buffer.extend(inner.queue.drain(..target));
let sender_wakers =
inner.sender_wakers_for_freed_slots(target, self.shared.capacity);
let retired_waker = inner.recv_waker.take();
drop(inner);
drop(retired_waker);
drop(prepared_waker);
for waker in sender_wakers {
waker.wake_by_ref();
}
return Poll::Ready(Ok(target));
}
if self.shared.sender_count.load(Ordering::Acquire) == 0
|| self.shared.receiver_dropped.load(Ordering::Relaxed)
{
let retired_waker = inner.recv_waker.take();
drop(inner);
drop(retired_waker);
drop(prepared_waker);
return Poll::Ready(Ok(0));
}
if inner
.recv_waker
.as_ref()
.is_some_and(|waker| waker.will_wake(task_cx.waker()))
{
drop(inner);
drop(prepared_waker);
return Poll::Pending;
}
let Some(prepared) = prepared_waker.as_ref() else {
let wake_epoch = inner.recv_wake_epoch;
drop(inner);
prepared_waker = Some(PreparedReceiverWaker {
registration: RegisteredWaker::new(task_cx.waker()),
wake_epoch,
});
continue;
};
let replay_wake = inner.recv_wake_epoch != prepared.wake_epoch;
let retired_waker = inner.recv_waker.replace(Arc::clone(&prepared.registration));
drop(inner);
let prepared = prepared_waker
.take()
.expect("prepared receiver waker remains owned until after unlock");
drop(retired_waker);
if replay_wake {
prepared.registration.wake_by_ref();
}
drop(prepared);
return Poll::Pending;
}
}
#[inline]
pub fn try_recv(&mut self) -> Result<T, RecvError> {
let mut inner = self.shared.inner.lock();
if let Some(value) = inner.queue.pop_front() {
let retired_waker = inner.recv_waker.take();
let next_waker = inner.take_next_sender_waker();
drop(inner);
drop(retired_waker);
if let Some(w) = next_waker {
w.wake_by_ref();
}
Ok(value)
} else {
let disconnected = self.shared.sender_count.load(Ordering::Acquire) == 0
|| self.shared.receiver_dropped.load(Ordering::Relaxed);
let retired_waker = if disconnected {
inner.recv_waker.take()
} else {
None
};
drop(inner);
drop(retired_waker);
if disconnected {
Err(RecvError::Disconnected)
} else {
Err(RecvError::Empty)
}
}
}
#[inline]
#[must_use]
pub fn is_closed(&self) -> bool {
self.shared.sender_count.load(Ordering::Acquire) == 0
}
#[inline]
#[must_use]
pub fn has_messages(&self) -> bool {
!self.shared.inner.lock().queue.is_empty()
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.shared.inner.lock().queue.len()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.shared.inner.lock().queue.is_empty()
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.shared.capacity
}
#[inline]
#[must_use]
pub fn telemetry_snapshot(&self, channel_id: u64) -> MpscTelemetrySnapshot {
self.shared.telemetry_snapshot(channel_id)
}
}
pub struct Recv<'a, T, Caps = crate::cx::cap::All> {
receiver: &'a mut Receiver<T>,
cx: &'a Cx<Caps>,
polled: bool,
}
impl<T, Caps> Future for Recv<'_, T, Caps> {
type Output = Result<T, RecvError>;
#[inline]
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
this.polled = true;
this.receiver.poll_recv(this.cx, ctx)
}
}
impl<T, Caps> Drop for Recv<'_, T, Caps> {
fn drop(&mut self) {
if self.polled {
let retired_waker = self.receiver.shared.inner.lock().recv_waker.take();
drop(retired_waker);
}
}
}
pub struct RecvMany<'a, T, Caps = crate::cx::cap::All> {
receiver: &'a mut Receiver<T>,
cx: &'a Cx<Caps>,
buffer: &'a mut Vec<T>,
limit: usize,
polled: bool,
}
impl<T, Caps> Future for RecvMany<'_, T, Caps> {
type Output = Result<usize, RecvError>;
#[inline]
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
this.polled = true;
this.receiver
.poll_recv_many(this.cx, this.buffer, this.limit, ctx)
}
}
impl<T, Caps> Drop for RecvMany<'_, T, Caps> {
fn drop(&mut self) {
if self.polled {
let retired_waker = self.receiver.shared.inner.lock().recv_waker.take();
drop(retired_waker);
}
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
let (wakers, _items, recv_waker) = {
let mut inner = self.shared.inner.lock();
let wakers = inner.drain_sender_wakers();
self.shared.receiver_dropped.store(true, Ordering::Release);
let recv_waker = inner.recv_waker.take();
let items = std::mem::take(&mut inner.queue);
drop(inner);
(wakers, items, recv_waker)
};
drop(recv_waker);
for waker in wakers {
waker.wake_by_ref();
}
}
}
pub struct UnboundedReceiver<T> {
inner: Receiver<T>,
}
impl<T: std::fmt::Debug> std::fmt::Debug for UnboundedReceiver<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("UnboundedReceiver")
.field("inner", &self.inner)
.finish()
}
}
impl<T> UnboundedReceiver<T> {
#[inline]
pub fn close(&mut self) {
self.inner.close();
}
#[inline]
#[must_use]
pub fn recv<'a, Caps>(&'a mut self, cx: &'a Cx<Caps>) -> Recv<'a, T, Caps> {
self.inner.recv(cx)
}
#[inline]
#[must_use]
pub fn recv_many<'a, Caps>(
&'a mut self,
cx: &'a Cx<Caps>,
buffer: &'a mut Vec<T>,
limit: usize,
) -> RecvMany<'a, T, Caps> {
self.inner.recv_many(cx, buffer, limit)
}
#[inline]
pub fn poll_recv<Caps>(
&mut self,
cx: &Cx<Caps>,
task_cx: &mut Context<'_>,
) -> Poll<Result<T, RecvError>> {
self.inner.poll_recv(cx, task_cx)
}
#[inline]
pub fn poll_recv_many<Caps>(
&mut self,
cx: &Cx<Caps>,
buffer: &mut Vec<T>,
limit: usize,
task_cx: &mut Context<'_>,
) -> Poll<Result<usize, RecvError>> {
self.inner.poll_recv_many(cx, buffer, limit, task_cx)
}
#[inline]
pub fn try_recv(&mut self) -> Result<T, RecvError> {
self.inner.try_recv()
}
#[inline]
#[must_use]
pub fn is_closed(&self) -> bool {
self.inner.is_closed()
}
#[inline]
#[must_use]
pub fn has_messages(&self) -> bool {
self.inner.has_messages()
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.inner.len()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
#[inline]
#[must_use]
pub fn telemetry_snapshot(&self, channel_id: u64) -> MpscTelemetrySnapshot {
self.inner.telemetry_snapshot(channel_id)
}
}
#[cfg(test)]
include!("mpsc_tests.rs");