use crate::cx::{CancelWakerToken, Cx};
use parking_lot::Mutex;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll, Waker};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SendError<T> {
Disconnected(T),
Cancelled(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 oneshot channel"),
Self::Cancelled(_) => write!(f, "sending on a cancelled cx"),
}
}
}
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> 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> {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RecvError {
Closed,
Cancelled,
PolledAfterCompletion,
}
impl std::fmt::Display for RecvError {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Closed => write!(f, "receiving on a closed oneshot channel"),
Self::Cancelled => write!(f, "[ASUP-E203] receive operation cancelled"),
Self::PolledAfterCompletion => write!(f, "oneshot recv future polled after completion"),
}
}
}
impl std::error::Error for RecvError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TryRecvError {
Empty,
Closed,
}
impl std::fmt::Display for TryRecvError {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Empty => write!(f, "oneshot channel is empty"),
Self::Closed => write!(f, "oneshot channel is closed"),
}
}
}
impl std::error::Error for TryRecvError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OneshotTelemetrySnapshot {
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,
pub closed_reason: Option<&'static str>,
}
#[derive(Debug)]
struct OneShotInner<T> {
value: Option<T>,
sender_consumed: bool,
receiver_dropped: bool,
permit_outstanding: bool,
waker: Option<Waker>,
waker_id: Option<u64>,
next_waiter_id: u64,
sender_waker: Option<Waker>,
receiver_closed_waker: Option<Waker>,
cancellation_count: u64,
closed_reason: Option<&'static str>,
}
impl<T> OneShotInner<T> {
#[inline]
fn new() -> Self {
Self {
value: None,
sender_consumed: false,
receiver_dropped: false,
permit_outstanding: false,
waker: None,
waker_id: None,
next_waiter_id: 0,
sender_waker: None,
receiver_closed_waker: None,
cancellation_count: 0,
closed_reason: None,
}
}
#[inline]
fn is_closed(&self) -> bool {
self.sender_consumed && !self.permit_outstanding && self.value.is_none()
}
#[inline]
fn is_ready(&self) -> bool {
self.value.is_some()
}
#[inline]
fn take_waker(&mut self) -> Option<Waker> {
self.waker_id = None;
self.waker.take()
}
#[inline]
fn record_cancellation(&mut self) {
self.cancellation_count = self.cancellation_count.saturating_add(1);
}
#[inline]
fn telemetry_snapshot(&self, channel_id: u64) -> OneshotTelemetrySnapshot {
let queued_messages = usize::from(self.value.is_some());
let reserved_uncommitted_obligations = usize::from(self.permit_outstanding);
let recv_waiter_count =
usize::from(self.waker.is_some()) + usize::from(self.receiver_closed_waker.is_some());
let closed = self.receiver_dropped
|| (self.sender_consumed && !self.permit_outstanding && self.value.is_none());
let receiver_health = if self.receiver_dropped {
"receiver_dropped"
} else if self.value.is_some() {
"value_ready"
} else if self.is_closed() {
"sender_closed"
} else if recv_waiter_count > 0 {
"waiting"
} else {
"open"
};
OneshotTelemetrySnapshot {
channel_id,
channel_kind: "oneshot",
capacity: 1,
queued_messages,
reserved_uncommitted_obligations,
send_waiter_count: usize::from(self.sender_waker.is_some()),
recv_waiter_count,
receiver_health,
lagged_receiver_count: None,
cancellation_count: self.cancellation_count,
closed,
closed_reason: closed.then_some(self.closed_reason).flatten(),
}
}
}
#[inline]
fn receive_waker_is_current<T>(
inner: &OneShotInner<T>,
waiter_id: Option<u64>,
task_waker: &Waker,
) -> bool {
waiter_id.is_some_and(|waiter_id| {
inner.waker_id == Some(waiter_id)
&& inner
.waker
.as_ref()
.is_some_and(|stored| stored.will_wake(task_waker))
})
}
#[inline]
fn install_receive_waker<T>(
inner: &mut OneShotInner<T>,
waiter_id: &mut Option<u64>,
task_waker: &Waker,
incoming_waker: &mut Option<Waker>,
) -> Option<Waker> {
if receive_waker_is_current(inner, *waiter_id, task_waker) {
return None;
}
let incoming_waker = incoming_waker
.take()
.expect("prepared receive Waker must be available");
if (*waiter_id).is_some_and(|waiter_id| inner.waker_id == Some(waiter_id)) {
return inner.waker.replace(incoming_waker);
}
let new_waiter_id = inner.next_waiter_id;
inner.next_waiter_id = inner.next_waiter_id.wrapping_add(1);
let retired_waker = inner.waker.replace(incoming_waker);
inner.waker_id = Some(new_waiter_id);
*waiter_id = Some(new_waiter_id);
retired_waker
}
#[inline]
fn retire_waker_after_unlock(waker: Option<Waker>) {
let Some(waker) = waker else {
return;
};
if let Err(payload) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| drop(waker))) {
std::mem::forget(payload);
}
}
#[inline]
fn wake_waker_after_unlock(waker: Option<Waker>) {
let Some(waker) = waker else {
return;
};
if let Err(payload) =
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| waker.wake_by_ref()))
{
std::mem::forget(payload);
}
retire_waker_after_unlock(Some(waker));
}
#[inline]
#[must_use]
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let inner = Arc::new(Mutex::new(OneShotInner::new()));
(
Sender {
inner: Arc::clone(&inner),
},
Receiver {
inner,
poll_waiter_id: None,
},
)
}
#[derive(Debug)]
pub struct Sender<T> {
inner: Arc<Mutex<OneShotInner<T>>>,
}
impl<T> Sender<T> {
pub fn reserve_checked(self, cx: &Cx) -> Result<SendPermit<T>, CheckedSendError<()>> {
if cx.checkpoint().is_err() {
return self.reserve(cx).map_err(CheckedSendError::Channel);
}
let obligation = cx
.try_register_obligation_checked(
crate::record::ObligationKind::SendPermit,
cx.task_id(),
)
.map_err(|error| CheckedSendError::Admission { error, value: () })?;
let permit = SendPermit {
inner: Arc::clone(&self.inner),
sent: false,
obligation,
};
{
let mut inner = self.inner.lock();
inner.sender_consumed = true;
inner.permit_outstanding = true;
}
Ok(permit)
}
pub fn send_checked(self, cx: &Cx, value: T) -> Result<(), CheckedSendError<T>> {
match self.reserve_checked(cx) {
Ok(permit) => permit.send(value).map_err(CheckedSendError::Channel),
Err(CheckedSendError::Channel(SendError::Cancelled(()))) => {
Err(CheckedSendError::Channel(SendError::Cancelled(value)))
}
Err(CheckedSendError::Channel(SendError::Disconnected(()))) => {
Err(CheckedSendError::Channel(SendError::Disconnected(value)))
}
Err(CheckedSendError::Admission { error, value: () }) => {
Err(CheckedSendError::Admission { error, value })
}
}
}
#[inline]
pub fn reserve(self, cx: &Cx) -> Result<SendPermit<T>, SendError<()>> {
if cx.checkpoint().is_err() {
cx.trace("oneshot::reserve cancelled");
let (waker, receiver_closed_waker) = {
let mut inner = self.inner.lock();
inner.sender_consumed = true;
inner.permit_outstanding = false;
inner.record_cancellation();
inner.closed_reason = Some("cancelled_reserve");
(inner.take_waker(), inner.receiver_closed_waker.take())
};
wake_waker_after_unlock(waker);
wake_waker_after_unlock(receiver_closed_waker);
return Err(SendError::Cancelled(()));
}
cx.trace("oneshot::reserve creating permit");
{
let mut inner = self.inner.lock();
inner.sender_consumed = true;
inner.permit_outstanding = true;
}
Ok(SendPermit {
inner: Arc::clone(&self.inner),
sent: false,
obligation: cx
.try_register_obligation(crate::record::ObligationKind::SendPermit, cx.task_id()),
})
}
#[inline]
pub fn send(self, cx: &Cx, value: T) -> Result<(), SendError<T>> {
match self.reserve(cx) {
Ok(permit) => permit.send(value),
Err(SendError::Cancelled(())) => Err(SendError::Cancelled(value)),
Err(SendError::Disconnected(())) => Err(SendError::Disconnected(value)),
}
}
#[inline]
pub fn send_blocking(self, value: T) -> Result<(), SendError<T>> {
let permit = {
let mut inner = self.inner.lock();
inner.sender_consumed = true;
inner.permit_outstanding = true;
SendPermit {
inner: Arc::clone(&self.inner),
sent: false,
obligation: None,
}
};
permit.send(value)
}
#[inline]
#[must_use]
pub fn is_closed(&self) -> bool {
self.inner.lock().receiver_dropped
}
#[inline]
#[must_use]
pub fn telemetry_snapshot(&self, channel_id: u64) -> OneshotTelemetrySnapshot {
self.inner.lock().telemetry_snapshot(channel_id)
}
#[inline]
pub fn poll_closed(&mut self, cx: &mut std::task::Context<'_>) -> std::task::Poll<()> {
let mut incoming_waker = None;
loop {
let mut inner = self.inner.lock();
if inner.receiver_dropped {
let retired_waker = inner.sender_waker.take();
drop(inner);
retire_waker_after_unlock(retired_waker);
retire_waker_after_unlock(incoming_waker);
return std::task::Poll::Ready(());
}
if inner
.sender_waker
.as_ref()
.is_some_and(|stored| stored.will_wake(cx.waker()))
{
drop(inner);
retire_waker_after_unlock(incoming_waker);
return std::task::Poll::Pending;
}
let Some(prepared) = incoming_waker.take() else {
drop(inner);
incoming_waker = Some(cx.waker().clone());
continue;
};
let retired_waker = inner.sender_waker.replace(prepared);
drop(inner);
retire_waker_after_unlock(retired_waker);
return std::task::Poll::Pending;
}
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
let (waker, receiver_closed_waker, retired_sender_waker) = {
let mut inner = self.inner.lock();
let retired_sender_waker = inner.sender_waker.take();
if inner.sender_consumed {
(None, None, retired_sender_waker)
} else {
inner.sender_consumed = true;
inner.closed_reason = Some("sender_drop");
let waker = inner.take_waker();
let receiver_closed_waker = inner.receiver_closed_waker.take();
(waker, receiver_closed_waker, retired_sender_waker)
}
};
retire_waker_after_unlock(retired_sender_waker);
wake_waker_after_unlock(waker);
wake_waker_after_unlock(receiver_closed_waker);
}
}
#[derive(Debug)]
pub struct SendPermit<T> {
inner: Arc<Mutex<OneShotInner<T>>>,
sent: bool,
obligation: Option<crate::runtime::obligation_mailbox::ObligationToken>,
}
struct ReleasedOneshotWake {
receiver: Option<Waker>,
closed: Option<Waker>,
retired: Option<Waker>,
}
impl Drop for ReleasedOneshotWake {
fn drop(&mut self) {
retire_waker_after_unlock(self.retired.take());
wake_waker_after_unlock(self.receiver.take());
wake_waker_after_unlock(self.closed.take());
}
}
impl<T> SendPermit<T> {
#[inline]
pub fn send(mut self, value: T) -> Result<(), SendError<T>> {
let (result, waker, retired_waker) = {
let mut inner = self.inner.lock();
if inner.receiver_dropped {
inner.permit_outstanding = false;
let retired_waker = inner.take_waker();
(Err(value), None, retired_waker)
} else {
inner.value = Some(value);
inner.permit_outstanding = false;
inner.closed_reason = None;
let waker = inner.take_waker();
(Ok(()), waker, None)
}
};
self.sent = true;
let _wake = ReleasedOneshotWake {
receiver: waker,
closed: None,
retired: retired_waker,
};
if let Some(token) = self.obligation.take() {
if result.is_ok() {
let _ = token.commit();
} else {
let _ = token.abort(crate::record::ObligationAbortReason::Error);
}
}
result.map_err(SendError::Disconnected)
}
#[inline]
pub fn abort(mut self) {
self.sent = true;
let _wake = self.release_reservation("abort");
if let Some(token) = self.obligation.take() {
let _ = token.abort(crate::record::ObligationAbortReason::Explicit);
}
}
fn release_reservation(&self, reason: &'static str) -> ReleasedOneshotWake {
let (waker, receiver_closed_waker) = {
let mut inner = self.inner.lock();
inner.permit_outstanding = false;
inner.record_cancellation();
inner.closed_reason = Some(reason);
(inner.take_waker(), inner.receiver_closed_waker.take())
};
ReleasedOneshotWake {
receiver: waker,
closed: receiver_closed_waker,
retired: None,
}
}
#[inline]
#[must_use]
pub fn is_closed(&self) -> bool {
self.inner.lock().receiver_dropped
}
#[inline]
#[must_use]
pub fn telemetry_snapshot(&self, channel_id: u64) -> OneshotTelemetrySnapshot {
self.inner.lock().telemetry_snapshot(channel_id)
}
}
impl<T> Drop for SendPermit<T> {
fn drop(&mut self) {
if !self.sent {
self.sent = true;
let _wake = self.release_reservation("permit_drop");
if let Some(token) = self.obligation.take() {
let _ = token.abort(crate::record::ObligationAbortReason::Cancel);
}
}
}
}
fn poll_recv_uninterruptible_with_waiter<T>(
channel: &Mutex<OneShotInner<T>>,
waiter_id: &mut Option<u64>,
ctx: &mut Context<'_>,
) -> Poll<Result<T, RecvError>> {
{
let mut inner = channel.lock();
if let Some(value) = inner.value.take() {
let retired_waker = inner.take_waker();
let retired_closed_waker = inner.receiver_closed_waker.take();
inner.closed_reason = Some("committed");
*waiter_id = None;
drop(inner);
retire_waker_after_unlock(retired_waker);
wake_waker_after_unlock(retired_closed_waker);
return Poll::Ready(Ok(value));
}
if inner.is_closed() {
let retired_waker = inner.take_waker();
let retired_closed_waker = inner.receiver_closed_waker.take();
*waiter_id = None;
drop(inner);
retire_waker_after_unlock(retired_waker);
wake_waker_after_unlock(retired_closed_waker);
return Poll::Ready(Err(RecvError::Closed));
}
if receive_waker_is_current(&inner, *waiter_id, ctx.waker()) {
return Poll::Pending;
}
}
let mut incoming_waker = Some(ctx.waker().clone());
let mut inner = channel.lock();
if let Some(value) = inner.value.take() {
let retired_waker = inner.take_waker();
let retired_closed_waker = inner.receiver_closed_waker.take();
inner.closed_reason = Some("committed");
*waiter_id = None;
drop(inner);
retire_waker_after_unlock(retired_waker);
wake_waker_after_unlock(retired_closed_waker);
retire_waker_after_unlock(incoming_waker);
return Poll::Ready(Ok(value));
}
if inner.is_closed() {
let retired_waker = inner.take_waker();
let retired_closed_waker = inner.receiver_closed_waker.take();
*waiter_id = None;
drop(inner);
retire_waker_after_unlock(retired_waker);
wake_waker_after_unlock(retired_closed_waker);
retire_waker_after_unlock(incoming_waker);
return Poll::Ready(Err(RecvError::Closed));
}
let retired_waker =
install_receive_waker(&mut inner, waiter_id, ctx.waker(), &mut incoming_waker);
drop(inner);
retire_waker_after_unlock(retired_waker);
retire_waker_after_unlock(incoming_waker);
Poll::Pending
}
pub(crate) struct RecvUninterruptibleFuture<'a, T> {
receiver: &'a mut Receiver<T>,
waiter_id: Option<u64>,
completed: bool,
}
impl<T> RecvUninterruptibleFuture<'_, T> {
#[must_use]
#[inline]
pub(crate) fn receiver_finished(&self) -> bool {
self.completed || self.receiver.is_ready() || self.receiver.is_closed()
}
}
impl<T> Future for RecvUninterruptibleFuture<'_, T> {
type Output = Result<T, RecvError>;
#[inline]
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
let this = &mut *self;
if this.completed {
return Poll::Ready(Err(RecvError::PolledAfterCompletion));
}
let polled =
poll_recv_uninterruptible_with_waiter(&this.receiver.inner, &mut this.waiter_id, ctx);
if polled.is_ready() {
this.completed = true;
}
polled
}
}
impl<T> Drop for RecvUninterruptibleFuture<'_, T> {
fn drop(&mut self) {
let retired_waker = {
let mut inner = self.receiver.inner.lock();
if self
.waiter_id
.is_some_and(|waiter_id| inner.waker_id == Some(waiter_id))
{
inner.take_waker()
} else {
None
}
};
retire_waker_after_unlock(retired_waker);
self.waiter_id = None;
}
}
#[derive(Debug)]
struct RegisteredCancelWaker {
waker: Waker,
token: CancelWakerToken,
}
pub struct RecvFuture<'a, T, Caps = crate::cx::cap::All> {
receiver: &'a mut Receiver<T>,
cx: &'a Cx<Caps>,
waiter_id: Option<u64>,
cancel_waker: Option<RegisteredCancelWaker>,
completed: bool,
}
impl<T, Caps> RecvFuture<'_, T, Caps> {
#[must_use]
#[allow(dead_code)] #[inline]
pub(crate) fn receiver_finished(&self) -> bool {
self.completed || self.receiver.is_ready() || self.receiver.is_closed()
}
fn refresh_cancel_waker(&mut self, waker: &Waker) {
let same_local_waker = self
.cancel_waker
.as_ref()
.is_some_and(|registered| registered.waker.will_wake(waker));
let incoming_waker = (!same_local_waker).then(|| waker.clone());
let previous_token = self
.cancel_waker
.as_ref()
.map(|registered| registered.token);
let token = self.cx.refresh_cancel_waker(previous_token, waker);
let retired_waker = if let Some(incoming_waker) = incoming_waker {
self.cancel_waker
.replace(RegisteredCancelWaker {
waker: incoming_waker,
token,
})
.map(|registered| registered.waker)
} else {
self.cancel_waker
.as_mut()
.expect("same local Waker requires an existing registration")
.token = token;
None
};
retire_waker_after_unlock(retired_waker);
}
fn clear_cancel_waker(&mut self) {
let Some(registered) = self.cancel_waker.take() else {
return;
};
self.cx.clear_cancel_waker(registered.token);
retire_waker_after_unlock(Some(registered.waker));
}
fn finish_cancelled(&mut self, incoming_waker: Option<Waker>) -> Poll<Result<T, RecvError>> {
let mut inner = self.receiver.inner.lock();
if let Some(value) = inner.value.take() {
let retired_waker = inner.take_waker();
let retired_closed_waker = inner.receiver_closed_waker.take();
inner.closed_reason = Some("committed");
self.waiter_id = None;
self.completed = true;
drop(inner);
retire_waker_after_unlock(retired_waker);
wake_waker_after_unlock(retired_closed_waker);
retire_waker_after_unlock(incoming_waker);
self.clear_cancel_waker();
self.cx.trace("oneshot::recv received value");
return Poll::Ready(Ok(value));
}
if inner.is_closed() {
let retired_waker = inner.take_waker();
let retired_closed_waker = inner.receiver_closed_waker.take();
self.waiter_id = None;
self.completed = true;
drop(inner);
retire_waker_after_unlock(retired_waker);
wake_waker_after_unlock(retired_closed_waker);
retire_waker_after_unlock(incoming_waker);
self.clear_cancel_waker();
self.cx.trace("oneshot::recv channel closed");
return Poll::Ready(Err(RecvError::Closed));
}
let retired_waker = if self
.waiter_id
.is_some_and(|waiter_id| inner.waker_id == Some(waiter_id))
{
inner.take_waker()
} else {
None
};
inner.record_cancellation();
self.waiter_id = None;
self.completed = true;
drop(inner);
retire_waker_after_unlock(retired_waker);
retire_waker_after_unlock(incoming_waker);
self.clear_cancel_waker();
self.cx.trace("oneshot::recv cancelled while waiting");
Poll::Ready(Err(RecvError::Cancelled))
}
}
impl<T, Caps> Future for RecvFuture<'_, T, Caps> {
type Output = Result<T, RecvError>;
#[inline]
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
let this = &mut *self;
if this.completed {
this.clear_cancel_waker();
return Poll::Ready(Err(RecvError::PolledAfterCompletion));
}
let needs_waker = {
let mut inner = this.receiver.inner.lock();
if let Some(value) = inner.value.take() {
let retired_waker = inner.take_waker();
let retired_closed_waker = inner.receiver_closed_waker.take();
inner.closed_reason = Some("committed");
this.waiter_id = None;
this.completed = true;
drop(inner);
retire_waker_after_unlock(retired_waker);
wake_waker_after_unlock(retired_closed_waker);
this.clear_cancel_waker();
this.cx.trace("oneshot::recv received value");
return Poll::Ready(Ok(value));
}
if inner.is_closed() {
let retired_waker = inner.take_waker();
let retired_closed_waker = inner.receiver_closed_waker.take();
this.waiter_id = None;
this.completed = true;
drop(inner);
retire_waker_after_unlock(retired_waker);
wake_waker_after_unlock(retired_closed_waker);
this.clear_cancel_waker();
this.cx.trace("oneshot::recv channel closed");
return Poll::Ready(Err(RecvError::Closed));
}
!receive_waker_is_current(&inner, this.waiter_id, ctx.waker())
};
if this.cx.checkpoint().is_err() {
return this.finish_cancelled(None);
}
let mut incoming_waker = needs_waker.then(|| ctx.waker().clone());
this.refresh_cancel_waker(ctx.waker());
if this.cx.checkpoint().is_err() {
return this.finish_cancelled(incoming_waker);
}
let mut inner = this.receiver.inner.lock();
if let Some(value) = inner.value.take() {
let retired_waker = inner.take_waker();
let retired_closed_waker = inner.receiver_closed_waker.take();
inner.closed_reason = Some("committed");
this.waiter_id = None;
this.completed = true;
drop(inner);
retire_waker_after_unlock(retired_waker);
wake_waker_after_unlock(retired_closed_waker);
retire_waker_after_unlock(incoming_waker);
this.clear_cancel_waker();
this.cx.trace("oneshot::recv received value");
return Poll::Ready(Ok(value));
}
if inner.is_closed() {
let retired_waker = inner.take_waker();
let retired_closed_waker = inner.receiver_closed_waker.take();
this.waiter_id = None;
this.completed = true;
drop(inner);
retire_waker_after_unlock(retired_waker);
wake_waker_after_unlock(retired_closed_waker);
retire_waker_after_unlock(incoming_waker);
this.clear_cancel_waker();
this.cx.trace("oneshot::recv channel closed");
return Poll::Ready(Err(RecvError::Closed));
}
if receive_waker_is_current(&inner, this.waiter_id, ctx.waker()) {
drop(inner);
retire_waker_after_unlock(incoming_waker);
return Poll::Pending;
}
let retired_waker = install_receive_waker(
&mut inner,
&mut this.waiter_id,
ctx.waker(),
&mut incoming_waker,
);
drop(inner);
retire_waker_after_unlock(retired_waker);
retire_waker_after_unlock(incoming_waker);
Poll::Pending
}
}
impl<T, Caps> Drop for RecvFuture<'_, T, Caps> {
fn drop(&mut self) {
let retired_waker = {
let mut inner = self.receiver.inner.lock();
if self
.waiter_id
.is_some_and(|waiter_id| inner.waker_id == Some(waiter_id))
{
inner.take_waker()
} else {
None
}
};
retire_waker_after_unlock(retired_waker);
self.waiter_id = None;
self.clear_cancel_waker();
}
}
#[derive(Debug)]
pub struct Receiver<T> {
inner: Arc<Mutex<OneShotInner<T>>>,
poll_waiter_id: Option<u64>,
}
impl<T> Receiver<T> {
#[inline]
#[must_use]
pub fn recv<'a, Caps>(&'a mut self, cx: &'a Cx<Caps>) -> RecvFuture<'a, T, Caps> {
RecvFuture {
receiver: self,
cx,
waiter_id: None,
cancel_waker: None,
completed: false,
}
}
#[must_use]
#[inline]
pub(crate) fn recv_uninterruptible(&mut self) -> RecvUninterruptibleFuture<'_, T> {
RecvUninterruptibleFuture {
receiver: self,
waiter_id: None,
completed: false,
}
}
#[inline]
pub(crate) fn poll_recv_uninterruptible(
&mut self,
ctx: &mut Context<'_>,
) -> Poll<Result<T, RecvError>> {
let Self {
inner,
poll_waiter_id,
} = self;
poll_recv_uninterruptible_with_waiter(inner, poll_waiter_id, ctx)
}
#[inline]
pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
let (result, retired_waker, retired_closed_waker) = {
let mut inner = self.inner.lock();
if let Some(value) = inner.value.take() {
let retired_waker = inner.take_waker();
let retired_closed_waker = inner.receiver_closed_waker.take();
inner.closed_reason = Some("committed");
(Ok(value), retired_waker, retired_closed_waker)
} else if inner.is_closed() {
let retired_waker = inner.take_waker();
let retired_closed_waker = inner.receiver_closed_waker.take();
(
Err(TryRecvError::Closed),
retired_waker,
retired_closed_waker,
)
} else {
(Err(TryRecvError::Empty), None, None)
}
};
retire_waker_after_unlock(retired_waker);
wake_waker_after_unlock(retired_closed_waker);
result
}
#[inline]
#[must_use]
pub fn is_ready(&self) -> bool {
self.inner.lock().is_ready()
}
#[inline]
#[must_use]
pub fn is_closed(&self) -> bool {
self.inner.lock().is_closed()
}
#[inline]
#[must_use]
pub fn telemetry_snapshot(&self, channel_id: u64) -> OneshotTelemetrySnapshot {
self.inner.lock().telemetry_snapshot(channel_id)
}
#[inline]
pub fn poll_closed(&mut self, cx: &mut std::task::Context<'_>) -> std::task::Poll<()> {
let mut incoming_waker = None;
loop {
let mut inner = self.inner.lock();
if inner.is_closed() {
let retired_waker = inner.receiver_closed_waker.take();
drop(inner);
retire_waker_after_unlock(retired_waker);
retire_waker_after_unlock(incoming_waker);
return std::task::Poll::Ready(());
}
if inner
.receiver_closed_waker
.as_ref()
.is_some_and(|stored| stored.will_wake(cx.waker()))
{
drop(inner);
retire_waker_after_unlock(incoming_waker);
return std::task::Poll::Pending;
}
let Some(prepared) = incoming_waker.take() else {
drop(inner);
incoming_waker = Some(cx.waker().clone());
continue;
};
let retired_waker = inner.receiver_closed_waker.replace(prepared);
drop(inner);
retire_waker_after_unlock(retired_waker);
return std::task::Poll::Pending;
}
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
let (sender_waker, retired_recv_waker, retired_closed_waker, closed_after_drop, _value) = {
let mut inner = self.inner.lock();
inner.receiver_dropped = true;
inner.closed_reason = Some("receiver_drop");
let retired_recv_waker = inner.take_waker();
let sender_waker = inner.sender_waker.take();
let retired_closed_waker = inner.receiver_closed_waker.take();
let value = inner.value.take();
let closed_after_drop = inner.is_closed();
(
sender_waker,
retired_recv_waker,
retired_closed_waker,
closed_after_drop,
value,
)
};
retire_waker_after_unlock(retired_recv_waker);
if closed_after_drop {
wake_waker_after_unlock(retired_closed_waker);
} else {
retire_waker_after_unlock(retired_closed_waker);
}
wake_waker_after_unlock(sender_waker);
}
}
#[cfg(test)]
include!("oneshot_tests.rs");