Skip to main content

nuclei/sync/local/mpsc/
bounded.rs

1//! The bounded single-shard channel: a queue plus a slot semaphore.
2//!
3//! A send acquires one slot (waiting in line when none is free), pushes its
4//! value and wakes the receiver; a receive pops a value and gives its slot
5//! back, which serves the first waiting send.
6
7use core::fmt;
8use core::future::Future;
9use core::mem;
10use core::pin::Pin;
11use core::task::{Context, Poll};
12use std::rc::Rc;
13
14use super::chan::{Chan, Limit};
15use crate::sync::TryAcquireError;
16use crate::sync::local::semaphore::{Acquire, Semaphore};
17use crate::sync::mpsc::error::{SendError, TrySendError};
18
19pub(super) struct Bounded {
20    slots: Semaphore,
21    max: usize,
22}
23
24impl Limit for Bounded {
25    fn release(&self, n: usize) {
26        if n > 0 {
27            self.slots.add_permits(n);
28        }
29    }
30
31    fn is_idle(&self) -> bool {
32        self.slots.available_permits() == self.max
33    }
34
35    fn close(&self) {
36        self.slots.close();
37    }
38}
39
40/// Creates a bounded channel that holds at most `buffer` messages, and
41/// answers its two halves.
42///
43/// The halves belong to the tasks of one shard: they are `!Send`. A send on a
44/// full channel waits in line for room.
45///
46/// # Panics
47///
48/// When `buffer` is zero, or more than [`Semaphore::MAX_PERMITS`].
49///
50/// ```
51/// use nuclei::sync::local::mpsc;
52///
53/// let (tx, mut rx) = mpsc::channel(2);
54/// tx.try_send(1).unwrap();
55/// tx.try_send(2).unwrap();
56/// assert!(tx.try_send(3).is_err());
57/// assert_eq!(rx.try_recv(), Ok(1));
58/// ```
59#[track_caller]
60pub fn channel<T>(buffer: usize) -> (Sender<T>, Receiver<T>) {
61    assert!(buffer > 0, "mpsc bounded channel requires buffer > 0");
62    let chan = Rc::new(Chan::new(Bounded {
63        slots: Semaphore::new(buffer),
64        max: buffer,
65    }));
66    let tx = Sender {
67        chan: Rc::clone(&chan),
68    };
69    (tx, Receiver { chan })
70}
71
72/// Sends values to the associated [`Receiver`].
73///
74/// Created by [`channel`]. Cloning it counts one more sender.
75pub struct Sender<T> {
76    chan: Rc<Chan<T, Bounded>>,
77}
78
79impl<T> Sender<T> {
80    /// Sends a value, waiting in line for room if the channel is full.
81    ///
82    /// # Errors
83    ///
84    /// A [`SendError`] holding the value when the receiver is closed or gone.
85    ///
86    /// # Cancel safety
87    ///
88    /// A dropped future sent nothing and drops its value; it holds no slot.
89    ///
90    /// ```
91    /// use nuclei::sync::local::mpsc;
92    ///
93    /// nuclei::runtime::block_on(async {
94    ///     let (tx, mut rx) = mpsc::channel(1);
95    ///     tx.send(1).await.unwrap();
96    ///     assert_eq!(rx.recv().await, Some(1));
97    /// });
98    /// ```
99    pub async fn send(&self, value: T) -> Result<(), SendError<T>> {
100        match self.reserve().await {
101            Ok(permit) => {
102                permit.send(value);
103                Ok(())
104            }
105            Err(_) => Err(SendError(value)),
106        }
107    }
108
109    /// Sends a value at once, or says why it cannot be sent. It never takes
110    /// a slot ahead of a send or reservation that is waiting.
111    ///
112    /// # Errors
113    ///
114    /// [`TrySendError::Full`] if no slot is free or a send is waiting,
115    /// [`TrySendError::Closed`] if the receiver closed or was dropped. Both
116    /// hold the value back.
117    pub fn try_send(&self, value: T) -> Result<(), TrySendError<T>> {
118        match self.try_reserve() {
119            Ok(permit) => {
120                permit.send(value);
121                Ok(())
122            }
123            Err(TrySendError::Full(())) => Err(TrySendError::Full(value)),
124            Err(TrySendError::Closed(())) => Err(TrySendError::Closed(value)),
125        }
126    }
127
128    /// Waits in line for a slot and reserves it: the send through the
129    /// [`Permit`] never waits and never fails.
130    ///
131    /// # Errors
132    ///
133    /// A [`SendError`] when the receiver is closed or gone.
134    ///
135    /// # Cancel safety
136    ///
137    /// A dropped future holds no slot.
138    pub async fn reserve(&self) -> Result<Permit<'_, T>, SendError<()>> {
139        Reserve {
140            chan: &self.chan,
141            acquire: self.chan.limit.slots.acquire(),
142        }
143        .await
144    }
145
146    /// Reserves a slot at once if one is free and nobody waits.
147    ///
148    /// # Errors
149    ///
150    /// [`TrySendError::Full`] if no slot is free or a send is waiting,
151    /// [`TrySendError::Closed`] if the receiver closed or was dropped.
152    pub fn try_reserve(&self) -> Result<Permit<'_, T>, TrySendError<()>> {
153        match self.chan.limit.slots.try_acquire() {
154            Ok(permit) => {
155                permit.forget();
156                Ok(Permit { chan: &self.chan })
157            }
158            Err(TryAcquireError::NoPermits) => Err(TrySendError::Full(())),
159            Err(TryAcquireError::Closed) => Err(TrySendError::Closed(())),
160        }
161    }
162
163    /// Completes when the receiver has been closed or dropped. Cancel safe;
164    /// once the channel is closed every call completes at once.
165    pub async fn closed(&self) {
166        self.chan.closed().await;
167    }
168
169    /// Whether the receiver has been closed or dropped.
170    pub fn is_closed(&self) -> bool {
171        self.chan.is_closed()
172    }
173
174    /// Whether both senders send to the same channel.
175    pub fn same_channel(&self, other: &Self) -> bool {
176        Rc::ptr_eq(&self.chan, &other.chan)
177    }
178
179    /// The channel's current capacity: the slots that are free.
180    pub fn capacity(&self) -> usize {
181        self.chan.limit.slots.available_permits()
182    }
183
184    /// The channel's maximum capacity: the `buffer` it was created with.
185    pub fn max_capacity(&self) -> usize {
186        self.chan.limit.max
187    }
188}
189
190impl<T> Clone for Sender<T> {
191    fn clone(&self) -> Self {
192        self.chan.add_sender();
193        Self {
194            chan: Rc::clone(&self.chan),
195        }
196    }
197}
198
199impl<T> Drop for Sender<T> {
200    fn drop(&mut self) {
201        self.chan.drop_sender();
202    }
203}
204
205impl<T> fmt::Debug for Sender<T> {
206    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207        f.debug_struct("Sender")
208            .field("capacity", &self.capacity())
209            .field("max_capacity", &self.max_capacity())
210            .field("closed", &self.is_closed())
211            .finish()
212    }
213}
214
215/// The wait of [`Sender::reserve`]. Its drop passes on a slot that was
216/// granted and not yet taken, and tells a receiver that waits for the
217/// channel to go idle.
218struct Reserve<'a, T> {
219    chan: &'a Chan<T, Bounded>,
220    acquire: Acquire<'a>,
221}
222
223impl<'a, T> Future for Reserve<'a, T> {
224    type Output = Result<Permit<'a, T>, SendError<()>>;
225
226    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
227        let this = self.get_mut();
228        match Pin::new(&mut this.acquire).poll(cx) {
229            Poll::Ready(Ok(permit)) => {
230                permit.forget();
231                Poll::Ready(Ok(Permit { chan: this.chan }))
232            }
233            Poll::Ready(Err(_)) => Poll::Ready(Err(SendError(()))),
234            Poll::Pending => Poll::Pending,
235        }
236    }
237}
238
239impl<T> Drop for Reserve<'_, T> {
240    fn drop(&mut self) {
241        self.acquire.cancel();
242        self.chan.wake_if_finished();
243    }
244}
245
246/// Room for one message, reserved before the message exists.
247///
248/// The send through it never waits and never fails, even when the receiver
249/// was closed in the meantime. Dropping it without sending gives the slot
250/// back.
251///
252/// ```
253/// use nuclei::sync::local::mpsc;
254///
255/// let (tx, mut rx) = mpsc::channel(1);
256/// let permit = tx.try_reserve().unwrap();
257/// permit.send("reserved");
258/// assert_eq!(rx.try_recv(), Ok("reserved"));
259/// ```
260#[must_use = "dropping a permit gives its slot back unused"]
261pub struct Permit<'a, T> {
262    chan: &'a Chan<T, Bounded>,
263}
264
265impl<T> Permit<'_, T> {
266    /// Sends a value through the reserved slot, consuming the permit.
267    pub fn send(self, value: T) {
268        let chan = self.chan;
269        // The slot goes to the value, not back to the semaphore.
270        mem::forget(self);
271        chan.push(value);
272    }
273}
274
275impl<T> Drop for Permit<'_, T> {
276    fn drop(&mut self) {
277        self.chan.give_back(1);
278    }
279}
280
281impl<T> fmt::Debug for Permit<'_, T> {
282    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283        f.debug_struct("Permit").finish_non_exhaustive()
284    }
285}
286
287/// Receives values from the associated [`Sender`]s.
288///
289/// Created by [`channel`]. Dropping it closes the channel and drops the
290/// values still queued.
291pub struct Receiver<T> {
292    chan: Rc<Chan<T, Bounded>>,
293}
294
295impl<T> Receiver<T> {
296    receiver_methods!();
297
298    /// The channel's current capacity: the slots that are free.
299    pub fn capacity(&self) -> usize {
300        self.chan.limit.slots.available_permits()
301    }
302
303    /// The channel's maximum capacity: the `buffer` it was created with.
304    pub fn max_capacity(&self) -> usize {
305        self.chan.limit.max
306    }
307}
308
309impl<T> Drop for Receiver<T> {
310    fn drop(&mut self) {
311        self.chan.drop_rx();
312    }
313}
314
315impl<T> fmt::Debug for Receiver<T> {
316    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317        f.debug_struct("Receiver")
318            .field("len", &self.len())
319            .field("closed", &self.is_closed())
320            .finish()
321    }
322}