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}