1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
//! The `mpmc` channel handles, [`Sender`] and [`Receiver`], shared by both flavors.
use core::{
cell::Cell,
pin::Pin,
task::{Context, Poll},
};
use std::rc::Rc;
use futures_core::stream::{FusedStream, Stream};
use super::{
chan::Chan,
error::{TryRecvError, TrySendError},
recv::Recv,
send::Send,
};
/// The sending half of an `mpmc` channel. Cloneable — every clone is another
/// producer.
pub struct Sender<T> {
chan: Rc<Chan<T>>,
}
impl<T> Sender<T> {
#[inline(always)]
pub(super) fn new(chan: Rc<Chan<T>>) -> Self {
Self { chan }
}
/// Pushes an item without waiting. Returns [`TrySendError::Full`] when the channel
/// is at capacity, or [`TrySendError::Closed`] when every receiver is gone; either
/// way the item is carried back.
#[inline(always)]
pub fn try_send(&self, item: T) -> Result<(), TrySendError<T>> {
if !self.chan.receiver_alive() || self.chan.is_closed() {
return Err(TrySendError::Closed(item));
}
match self.chan.try_push(item) {
Ok(()) => {
self.chan.wake_receivers();
Ok(())
}
Err(item) => Err(TrySendError::Full(item)),
}
}
/// The channel's capacity, or `None` if the channel is unbounded.
///
/// A bounded channel buffers at most this many items. A receive interrupted by a
/// panicking sender waker keeps its one recovered item in transit until the next
/// receive, so the channel can momentarily hold `capacity() + 1` and
/// [`len`](Self::len) can briefly exceed this — never by more than one.
#[inline(always)]
pub fn capacity(&self) -> Option<usize> {
self.chan.cap()
}
/// The number of items currently in the channel.
///
/// Counts a recovered in-transit item left by a receive interrupted by a panicking
/// sender waker, so for a bounded channel this can briefly be `capacity() + 1`.
#[inline(always)]
pub fn len(&self) -> usize {
self.chan.len()
}
/// Returns `true` if the channel has no items left to receive.
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.chan.is_empty()
}
/// Returns `true` if the channel is at capacity.
#[inline(always)]
pub fn is_full(&self) -> bool {
self.chan.is_full()
}
/// Returns `true` once every receiver has been dropped or the channel has been
/// [`close`](Self::close)d.
#[inline(always)]
pub fn is_closed(&self) -> bool {
!self.chan.receiver_alive() || self.chan.is_closed()
}
/// Closes the channel. Every subsequent send fails closed, and receivers observe
/// disconnect once they have drained what is already queued. Returns `true` if this
/// call closed a still-open channel — `false` if it was already closed, whether by a
/// prior `close` or by every receiver dropping. Callable through any clone.
#[inline(always)]
pub fn close(&self) -> bool {
if self.is_closed() {
return false;
}
self.chan.close();
true
}
/// Returns a future that sends `item`, awaiting capacity when a bounded channel is
/// full. Resolves to [`SendError`](super::SendError) (carrying the item) if every
/// receiver is gone. The future is `FusedFuture` (and `Unpin` when `T: Unpin`).
#[inline(always)]
pub fn send(&self, item: T) -> Send<'_, T> {
Send::new(self, item)
}
#[inline(always)]
pub(super) fn chan(&self) -> &Chan<T> {
&self.chan
}
}
impl<T> Clone for Sender<T> {
#[inline]
fn clone(&self) -> Self {
self.chan.incr_senders();
Self {
chan: self.chan.clone(),
}
}
}
impl<T> Drop for Sender<T> {
#[inline]
fn drop(&mut self) {
if self.chan.decr_senders() == 1 {
// Last sender gone: wake every parked receiver so each observes disconnect.
self.chan.wake_receivers();
}
}
}
/// The receiving half of an `mpmc` channel. Cloneable — every clone is another
/// consumer, and the channel stays open for sends until the last one drops.
pub struct Receiver<T> {
chan: Rc<Chan<T>>,
/// This receiver's stream-registration id, used by the [`Stream`] impl so repeated
/// `poll_next` calls replace the registration rather than accumulate entries. Each
/// clone is an independent consumer with its own slot.
stream_waker_id: Cell<Option<u64>>,
}
impl<T> Receiver<T> {
#[inline(always)]
pub(super) fn new(chan: Rc<Chan<T>>) -> Self {
Self {
chan,
stream_waker_id: Cell::new(None),
}
}
/// Pops an item without waiting. Returns [`TryRecvError::Empty`] when nothing is
/// queued, or [`TryRecvError::Disconnected`] when the queue is empty and every
/// sender has dropped.
#[inline(always)]
pub fn try_recv(&self) -> Result<T, TryRecvError> {
match self.chan.try_take() {
Some(item) => Ok(item),
None if self.chan.senders() == 0 || self.chan.is_closed() => Err(TryRecvError::Disconnected),
None => Err(TryRecvError::Empty),
}
}
/// Returns a future that resolves to the next item, or `None` once the channel is
/// empty and every sender has dropped. The future is `Unpin` + `FusedFuture`.
///
/// Several consumers may await concurrently: a delivered item goes to exactly one of
/// them, while the rest stay parked.
#[inline(always)]
pub fn recv(&self) -> Recv<'_, T> {
Recv::new(self)
}
/// Returns an iterator over the items currently queued, without waiting: it yields
/// each ready item and stops at the first empty-or-disconnected poll.
#[inline]
pub fn try_iter(&self) -> TryIter<'_, T> {
TryIter(self)
}
/// The shared recv state machine, used by the [`Recv`] future and the [`Stream`]
/// impl. Pops an item (waking parked senders), reports `None` once disconnected, or
/// registers `cx`'s waker (threading the caller's `waker_id` slot so a re-poll
/// replaces rather than accumulates) and rechecks — `Recv`'s golden panic-safe path.
#[inline]
pub(super) fn poll_recv(
&self,
cx: &mut Context<'_>,
waker_id: &Cell<Option<u64>>,
) -> Poll<Option<T>> {
let chan = &self.chan;
// Drop a stale registration from a prior park BEFORE popping: its waker drop runs
// user code, but no item has been read out yet, so a panic loses nothing (the
// future simply re-polls). Guarded so the common first-poll ready path (no prior
// registration) skips the list scan.
if let Some(old) = waker_id.take() {
chan.remove_recv_waker(old);
}
if let Some(item) = chan.try_take() {
// `try_take` pops then wakes parked senders with the item parked in the redelivery
// slot, so a panicking sender waker re-queues it rather than dropping a stack local.
return Poll::Ready(Some(item));
}
if chan.senders() == 0 || chan.is_closed() {
// Empty and either every sender is gone or the channel was closed — disconnected.
return Poll::Ready(None);
}
let id = chan.add_recv_waker(cx.waker());
// Record the id through the shared `Cell` BEFORE the recheck below, so even if a later
// step unwinds, the caller still knows which registration to remove — the id is never
// orphaned in `recv_wakers`.
waker_id.set(Some(id));
// RECHECK: add_recv_waker's clone/drop callbacks may have pushed an item or dropped
// the last sender; re-check so a wake delivered during registration is not lost. On the
// ready-item branch we do NOT remove the just-registered waker — dropping it could
// panic and lose the popped item — so it is stale only on that rare re-entrant path and
// is removed at a safe point (the next poll's top, the future's `Drop`, or the
// receiver's `Drop`). On the disconnect branch, however, NO item is in flight, so we
// remove it here: a side-effecting waker clone can drop the last sender during
// registration, and otherwise a terminal `Recv`/`FusedStream` would retain the waker.
if let Some(item) = chan.try_take() {
return Poll::Ready(Some(item));
}
if chan.senders() == 0 || chan.is_closed() {
if let Some(id) = waker_id.take() {
chan.remove_recv_waker(id);
}
return Poll::Ready(None);
}
Poll::Pending
}
#[inline(always)]
pub(super) fn chan(&self) -> &Chan<T> {
&self.chan
}
/// The number of items currently in the channel.
///
/// Counts a recovered in-transit item left by a receive interrupted by a panicking
/// sender waker, so for a bounded channel this can briefly be `capacity() + 1`.
#[inline(always)]
pub fn len(&self) -> usize {
self.chan.len()
}
/// Returns `true` if the channel has no items left to receive.
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.chan.is_empty()
}
/// Returns `true` once every sender has been dropped or the channel has been
/// [`close`](Self::close)d. Items may still be queued for draining.
#[inline(always)]
pub fn is_closed(&self) -> bool {
self.chan.senders() == 0 || self.chan.is_closed()
}
/// Closes the channel. Every subsequent send fails closed; receivers can still drain
/// what is already queued, after which they observe disconnect. Returns `true` if this
/// call closed a still-open channel — `false` if it was already closed, whether by a
/// prior `close` or by every sender dropping. Callable through any clone.
#[inline(always)]
pub fn close(&self) -> bool {
if self.is_closed() {
return false;
}
self.chan.close();
true
}
}
impl<T> Clone for Receiver<T> {
#[inline]
fn clone(&self) -> Self {
self.chan.incr_receivers();
Self {
chan: self.chan.clone(),
stream_waker_id: Cell::new(None),
}
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
// Decrement the receiver count FIRST, before the stream-waker drop below (user
// code). Two reasons: once this is the last receiver, `receiver_alive()` is false,
// so a re-entrant `try_send` from a panicking waker drop fails closed instead of
// queuing an item the drain would silently discard; and a panic in that drop cannot
// skip the decrement, which would leave senders believing a receiver is still alive.
let was_last = self.chan.decr_receivers() == 1;
if !was_last {
// Other receivers remain: the channel stays open and they own the queue. Remove
// only this receiver's own stream registration.
if let Some(id) = self.stream_waker_id.take() {
self.chan.remove_recv_waker(id);
}
return;
}
// Last receiver gone. Arm a guard that frees the queue AND removes this receiver's
// stream registration, so an unwind from the `wake_senders` below skips NEITHER: a
// queued payload may own a `Sender` (an `Rc` cycle through `Chan`), and the stream
// registration would otherwise be retained in `recv_wakers` while a live `Sender`
// keeps `Chan` alive. The id is captured BEFORE the wake so the wake cannot skip it.
// (A second panic during the guard — a payload, or the stream waker drop itself —
// aborts: the same multi-panic limit documented on `wake_all`.)
struct Cleanup<'a, T> {
chan: &'a Chan<T>,
stream_id: Option<u64>,
}
impl<T> Drop for Cleanup<'_, T> {
fn drop(&mut self) {
// Remove the stream registration in its OWN guard, armed BEFORE `drain` below, so
// a panicking payload drop inside `drain` (which `drain` resumes after continuing)
// still removes it on the unwind rather than leaking it in `recv_wakers`.
struct RemoveStream<'a, T> {
chan: &'a Chan<T>,
id: Option<u64>,
}
impl<T> Drop for RemoveStream<'_, T> {
fn drop(&mut self) {
if let Some(id) = self.id.take() {
self.chan.remove_recv_waker(id);
}
}
}
let _remove = RemoveStream {
chan: self.chan,
id: self.stream_id.take(),
};
// Drain the queue; its own guard continues past a panicking payload, so the `Rc`
// cycle is always broken. `_remove` then removes the stream registration — on the
// normal path or on a drain unwind.
self.chan.drain();
}
}
let cleanup = Cleanup {
chan: &self.chan,
stream_id: self.stream_waker_id.take(),
};
// Wake parked senders so each observes disconnect — before the guard's payload/waker
// drops, so a panicking one cannot strand them parked.
self.chan.wake_senders();
drop(cleanup);
}
}
impl<T> Stream for Receiver<T> {
type Item = T;
/// Polls for the next item — equivalent to polling [`Receiver::recv`]; yields `None`
/// once the channel is empty and every sender has dropped.
#[inline]
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
let this = self.get_mut();
// Pass the `Cell` straight through so `poll_recv` records the registration id into it
// directly — no copy-out then write-back that a panic in between could skip, which
// would orphan the just-registered waker in `recv_wakers`.
this.poll_recv(cx, &this.stream_waker_id)
}
}
impl<T> FusedStream for Receiver<T> {
/// Terminated once the channel is drained and every sender has dropped — past that,
/// `poll_next` only returns `None`.
///
/// Stays non-terminal while a stream-waker registration is still outstanding, even when
/// drained and sender-less: a recheck-Ready poll can deliver the final item while leaving
/// its waker registered (it cannot be removed there without risking the popped item), so
/// reporting termination then would let a `FusedStream` consumer stop polling and strand
/// that waker. One more poll clears it at the poll-top stale-remove and returns `None`.
#[inline]
fn is_terminated(&self) -> bool {
self.stream_waker_id.get().is_none()
&& (self.chan.senders() == 0 || self.chan.is_closed())
&& self.chan.is_empty()
}
}
/// A non-blocking iterator over the currently-available items of a [`Receiver`],
/// returned by [`Receiver::try_iter`]. `next` yields each queued item and stops at the
/// first empty-or-disconnected poll.
pub struct TryIter<'a, T>(&'a Receiver<T>);
impl<T> Iterator for TryIter<'_, T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
self.0.try_recv().ok()
}
}