Skip to main content

nuclei/sync/mpsc/
permit.rs

1//! Reserved capacity of the bounded channel: [`Permit`], [`PermitIterator`]
2//! and [`OwnedPermit`].
3//!
4//! A permit stands for one slot of the channel that its holder took out of
5//! the semaphore. Sending through it pushes the value into the slot, which the
6//! receiver gives back when it takes the value; dropping it unused gives the
7//! slot back at once. Either way the receiver is woken if the slot's return
8//! leaves a closed channel idle (see `Chan::give_back`).
9
10#![allow(unsafe_code)]
11
12use core::fmt;
13use core::iter::FusedIterator;
14use core::mem::{self, ManuallyDrop};
15use core::ptr;
16
17use super::bounded::{Bounded, Sender};
18use super::chan::Chan;
19
20/// Permits to send one value into the channel.
21///
22/// Returned by [`Sender::reserve`] and [`Sender::try_reserve`]; it guarantees
23/// room for one message before the message exists. The send through it never
24/// waits and never fails, even when the receiver was closed in the meantime
25/// (see [`Receiver::close`](super::Receiver::close)). Dropping it without
26/// sending gives the slot back.
27///
28/// # Progress
29///
30/// [`send`](Self::send) is lock-free, not wait-free: it pushes onto the
31/// message queue, which retries when it loses a slot to another sender.
32/// Dropping the permit is one atomic add on the semaphore when no sender
33/// waits, and lock-free when it serves waiting senders.
34///
35/// ```
36/// use nuclei::sync::mpsc;
37///
38/// let (tx, mut rx) = mpsc::channel(1);
39/// let permit = tx.try_reserve().unwrap();
40/// permit.send("reserved");
41/// assert_eq!(rx.try_recv(), Ok("reserved"));
42/// ```
43#[must_use = "dropping a permit gives its slot back unused"]
44pub struct Permit<'a, T> {
45    chan: &'a Chan<T, Bounded>,
46}
47
48impl<'a, T> Permit<'a, T> {
49    pub(super) fn new(chan: &'a Chan<T, Bounded>) -> Self {
50        Self { chan }
51    }
52
53    /// Sends a value through the reserved slot, consuming the permit.
54    ///
55    /// The send succeeds even if the receiver was closed after the slot was
56    /// reserved: closing keeps what is reserved receivable, so a clean
57    /// shutdown loses nothing. (If the receiver was dropped, the value is
58    /// dropped when the last sender is.)
59    ///
60    /// ```
61    /// use nuclei::sync::mpsc;
62    ///
63    /// let (tx, mut rx) = mpsc::channel(1);
64    /// let permit = tx.try_reserve().unwrap();
65    /// rx.close();
66    /// permit.send(456);
67    /// assert_eq!(rx.try_recv(), Ok(456));
68    /// ```
69    pub fn send(self, value: T) {
70        let chan = self.chan;
71        // The slot goes to the value, not back to the semaphore.
72        mem::forget(self);
73        chan.send(value);
74    }
75}
76
77impl<T> Drop for Permit<'_, T> {
78    fn drop(&mut self) {
79        self.chan.give_back(1);
80    }
81}
82
83impl<T> fmt::Debug for Permit<'_, T> {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        f.debug_struct("Permit").finish_non_exhaustive()
86    }
87}
88
89/// An [`Iterator`] of [`Permit`]s that holds `n` slots of the channel.
90///
91/// Returned by [`Sender::reserve_many`] and [`Sender::try_reserve_many`]. Each
92/// item is one permit; dropping the iterator before it is exhausted gives the
93/// remaining slots back. It knows its length.
94///
95/// # Progress
96///
97/// `next`, `len` and `size_hint` touch no shared state and are wait-free.
98/// Dropping the iterator returns all its remaining slots with one semaphore
99/// release: one atomic add when no sender waits, lock-free when it serves
100/// waiting senders.
101///
102/// ```
103/// use nuclei::sync::mpsc;
104///
105/// let (tx, mut rx) = mpsc::channel(3);
106/// let mut permits = tx.try_reserve_many(3).unwrap();
107/// assert_eq!(permits.len(), 3);
108/// permits.next().unwrap().send(1);
109/// assert_eq!(tx.capacity(), 0);
110/// drop(permits);
111/// assert_eq!(tx.capacity(), 2, "the two unused slots came back");
112/// assert_eq!(rx.try_recv(), Ok(1));
113/// ```
114#[must_use = "dropping the iterator gives its slots back unused"]
115pub struct PermitIterator<'a, T> {
116    chan: &'a Chan<T, Bounded>,
117    n: usize,
118}
119
120impl<'a, T> PermitIterator<'a, T> {
121    pub(super) fn new(chan: &'a Chan<T, Bounded>, n: usize) -> Self {
122        Self { chan, n }
123    }
124}
125
126impl<'a, T> Iterator for PermitIterator<'a, T> {
127    type Item = Permit<'a, T>;
128
129    fn next(&mut self) -> Option<Self::Item> {
130        if self.n == 0 {
131            return None;
132        }
133        self.n -= 1;
134        Some(Permit { chan: self.chan })
135    }
136
137    fn size_hint(&self) -> (usize, Option<usize>) {
138        (self.n, Some(self.n))
139    }
140}
141
142impl<T> ExactSizeIterator for PermitIterator<'_, T> {}
143
144impl<T> FusedIterator for PermitIterator<'_, T> {}
145
146impl<T> Drop for PermitIterator<'_, T> {
147    fn drop(&mut self) {
148        if self.n > 0 {
149            self.chan.give_back(self.n);
150        }
151    }
152}
153
154impl<T> fmt::Debug for PermitIterator<'_, T> {
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        f.debug_struct("PermitIterator")
157            .field("remaining", &self.n)
158            .finish()
159    }
160}
161
162/// An owned permit to send one value into the channel.
163///
164/// The same as [`Permit`], except that it holds the [`Sender`] it was reserved
165/// from instead of borrowing it, so it has no lifetime. Returned by
166/// [`Sender::reserve_owned`] and [`Sender::try_reserve_owned`]. It counts as a
167/// sender while it lives, so the channel does not end for the receiver while a
168/// permit is held. [`send`](Self::send) and [`release`](Self::release) hand
169/// the sender back; dropping the permit unused gives the slot back and drops
170/// the sender.
171///
172/// # Progress
173///
174/// [`send`](Self::send) is lock-free, not wait-free, for the reason
175/// [`Permit::send`] is: it pushes onto the message queue. [`release`](Self::release)
176/// and the drop return the slot as dropping a [`Permit`] does (one atomic add
177/// when no sender waits, lock-free otherwise), and the drop then counts the
178/// sender out, which is wait-free. [`same_channel`](Self::same_channel) and
179/// [`same_channel_as_sender`](Self::same_channel_as_sender) are wait-free.
180///
181/// ```
182/// use nuclei::sync::mpsc;
183///
184/// let (tx, mut rx) = mpsc::channel(1);
185/// let permit = tx.try_reserve_owned().unwrap();
186/// let tx = permit.send(123);
187/// assert_eq!(rx.try_recv(), Ok(123));
188/// tx.try_send(456).unwrap();
189/// ```
190#[must_use = "dropping a permit gives its slot back unused"]
191pub struct OwnedPermit<T> {
192    sender: Sender<T>,
193}
194
195impl<T> OwnedPermit<T> {
196    pub(super) fn new(sender: Sender<T>) -> Self {
197        Self { sender }
198    }
199
200    /// The sender, moved out of a permit that is consumed without running its
201    /// drop (which would give the slot back).
202    fn into_sender(self) -> Sender<T> {
203        let this = ManuallyDrop::new(self);
204        // SAFETY: `this` is never used or dropped again, so the sender is
205        // moved out exactly once, and the permit's `Drop` (which would return
206        // the slot) never runs.
207        unsafe { ptr::read(&this.sender) }
208    }
209
210    /// Sends a value through the reserved slot, returning the sender the
211    /// permit was reserved from.
212    ///
213    /// As for [`Permit::send`], it succeeds even if the receiver was closed
214    /// after the reservation.
215    ///
216    /// ```
217    /// use nuclei::sync::mpsc;
218    ///
219    /// let (tx, mut rx) = mpsc::channel(1);
220    /// let permit = tx.try_reserve_owned().unwrap();
221    /// let tx = permit.send(456);
222    /// assert_eq!(rx.try_recv(), Ok(456));
223    /// tx.try_send(789).unwrap();
224    /// ```
225    pub fn send(self, value: T) -> Sender<T> {
226        let sender = self.into_sender();
227        sender.chan.send(value);
228        sender
229    }
230
231    /// Gives the reserved slot back without sending, returning the sender.
232    ///
233    /// ```
234    /// use nuclei::sync::mpsc;
235    ///
236    /// let (tx, _rx) = mpsc::channel(1);
237    /// let permit = tx.clone().try_reserve_owned().unwrap();
238    /// assert!(tx.try_send(123).is_err(), "the permit holds the only slot");
239    /// let tx2 = permit.release();
240    /// tx.try_send(789).unwrap();
241    /// drop(tx2);
242    /// ```
243    pub fn release(self) -> Sender<T> {
244        let sender = self.into_sender();
245        sender.chan.give_back(1);
246        sender
247    }
248
249    /// Whether two permits belong to the same channel.
250    ///
251    /// ```
252    /// use nuclei::sync::mpsc;
253    ///
254    /// let (tx, _rx) = mpsc::channel::<()>(2);
255    /// let a = tx.clone().try_reserve_owned().unwrap();
256    /// let b = tx.clone().try_reserve_owned().unwrap();
257    /// assert!(a.same_channel(&b));
258    ///
259    /// let (tx2, _rx2) = mpsc::channel::<()>(1);
260    /// let c = tx2.try_reserve_owned().unwrap();
261    /// assert!(!c.same_channel(&a));
262    /// ```
263    pub fn same_channel(&self, other: &Self) -> bool {
264        self.sender.same_channel(&other.sender)
265    }
266
267    /// Whether this permit belongs to the same channel as `sender`.
268    ///
269    /// ```
270    /// use nuclei::sync::mpsc;
271    ///
272    /// let (tx, _rx) = mpsc::channel::<()>(1);
273    /// let permit = tx.clone().try_reserve_owned().unwrap();
274    /// assert!(permit.same_channel_as_sender(&tx));
275    ///
276    /// let (tx2, _rx2) = mpsc::channel::<()>(1);
277    /// assert!(!permit.same_channel_as_sender(&tx2));
278    /// ```
279    pub fn same_channel_as_sender(&self, sender: &Sender<T>) -> bool {
280        self.sender.same_channel(sender)
281    }
282}
283
284impl<T> Drop for OwnedPermit<T> {
285    fn drop(&mut self) {
286        // The sender field drops after this, which counts the sender out.
287        self.sender.chan.give_back(1);
288    }
289}
290
291impl<T> fmt::Debug for OwnedPermit<T> {
292    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293        f.debug_struct("OwnedPermit").finish_non_exhaustive()
294    }
295}