Skip to main content

compact_waitgroup/
group.rs

1use core::{
2    pin::Pin,
3    task::{Context, Poll},
4};
5
6use derive_more::{Debug, Into};
7
8use crate::{
9    layout::SharedLayout,
10    sync::{WaitGroupLayoutExt, WaitGroupWrapper},
11    twin_ref::{ClonableTwinRef, TwinRef},
12};
13
14#[cfg(feature = "compact-mono")]
15type MonoLayout = crate::layout::MonoLayout;
16#[cfg(not(feature = "compact-mono"))]
17type MonoLayout = crate::layout::SharedLayout;
18
19/// WaitGroup with clonable group tokens.
20///
21/// # Cancellation safety
22///
23/// This future is cancellation safe.
24///
25/// It is also safe to poll again after completion.
26///
27/// ```rust
28/// # use compact_waitgroup::WaitGroup;
29/// # futures_executor::block_on(async {
30/// let (wg, token) = WaitGroup::new();
31/// let mut wg = core::pin::pin!(wg);
32///
33/// assert!(!wg.is_done());
34///
35/// token.release();
36///
37/// wg.as_mut().await;
38/// assert!(wg.is_done());
39///
40/// // It is safe to await again (re-poll)
41/// wg.as_mut().await;
42/// assert!(wg.is_done());
43/// # });
44/// ```
45#[must_use]
46#[derive(Debug)]
47pub struct WaitGroup(#[debug("done: {}", _0.is_done())] WaitGroupWrapper<TwinRef<SharedLayout>>);
48
49/// WaitGroup with a single non-clonable group token.
50///
51/// # Cancellation safety
52///
53/// This future is cancellation safe.
54///
55/// It is also safe to poll again after completion.
56///
57/// ```rust
58/// # use compact_waitgroup::MonoWaitGroup;
59/// # futures_executor::block_on(async {
60/// let (wg, token) = MonoWaitGroup::new();
61/// let mut wg = core::pin::pin!(wg);
62///
63/// assert!(!wg.is_done());
64///
65/// token.release();
66///
67/// wg.as_mut().await;
68/// assert!(wg.is_done());
69///
70/// // It is safe to await again (re-poll)
71/// wg.as_mut().await;
72/// assert!(wg.is_done());
73/// # });
74/// ```
75#[must_use]
76#[derive(Debug)]
77pub struct MonoWaitGroup(#[debug("done: {}", _0.is_done())] WaitGroupWrapper<TwinRef<MonoLayout>>);
78
79/// Clonable group token.
80#[must_use]
81#[derive(Clone, Debug)]
82pub struct GroupToken(
83    #[allow(unused)]
84    #[debug("done: {}", _0.is_done())]
85    ClonableTwinRef<SharedLayout>,
86);
87
88/// Non-clonable group token.
89#[must_use]
90#[derive(Debug)]
91pub struct MonoGroupToken(#[debug("done: {}", _0.is_done())] TwinRef<MonoLayout>);
92
93/// Factory of `GroupToken`.
94#[must_use]
95#[derive(Debug, Into)]
96pub struct GroupTokenFactory(GroupToken);
97
98impl WaitGroup {
99    /// Creates a new `WaitGroup` and a `GroupTokenFactory`.
100    ///
101    /// # Examples
102    ///
103    /// ```
104    /// use compact_waitgroup::WaitGroup;
105    ///
106    /// let (wg, factory) = WaitGroup::new();
107    /// // ... distribute token with factory ...
108    /// ```
109    pub fn new() -> (Self, GroupTokenFactory) {
110        let inner = SharedLayout::new();
111        let (wg, token) = TwinRef::new_clonable(inner);
112        (
113            Self(WaitGroupWrapper::new(wg)),
114            GroupTokenFactory(GroupToken(token)),
115        )
116    }
117
118    /// Checks if the `WaitGroup` has completed.
119    ///
120    /// This returns `true` if all `GroupToken`s have been dropped.
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// use compact_waitgroup::WaitGroup;
126    ///
127    /// let (wg, token) = WaitGroup::new();
128    /// assert!(!wg.is_done());
129    ///
130    /// drop(token);
131    /// assert!(wg.is_done());
132    /// ```
133    #[inline]
134    pub fn is_done(&self) -> bool {
135        self.0.is_done()
136    }
137}
138
139impl MonoWaitGroup {
140    /// Creates a new `MonoWaitGroup` and a single `MonoGroupToken`.
141    ///
142    /// This variant is optimized for scenarios where there is exactly one
143    /// worker task. The token cannot be cloned.
144    ///
145    /// # Examples
146    ///
147    /// ```
148    /// use compact_waitgroup::MonoWaitGroup;
149    ///
150    /// let (wg, token) = MonoWaitGroup::new();
151    /// ```
152    pub fn new() -> (Self, MonoGroupToken) {
153        let inner = MonoLayout::new();
154        let (wg, token) = TwinRef::new_mono(inner);
155        (Self(WaitGroupWrapper::new(wg)), MonoGroupToken(token))
156    }
157
158    /// Checks if the `MonoWaitGroup` has completed.
159    ///
160    /// This returns `true` if the `MonoGroupToken` has been dropped.
161    ///
162    /// # Examples
163    ///
164    /// ```
165    /// use compact_waitgroup::MonoWaitGroup;
166    ///
167    /// let (wg, token) = MonoWaitGroup::new();
168    /// assert!(!wg.is_done());
169    ///
170    /// drop(token);
171    /// assert!(wg.is_done());
172    /// ```
173    #[inline]
174    pub fn is_done(&self) -> bool {
175        self.0.is_done()
176    }
177}
178
179impl Future for WaitGroup {
180    type Output = ();
181
182    #[inline]
183    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
184        Pin::new(&mut self.0).poll(cx)
185    }
186}
187
188impl Future for MonoWaitGroup {
189    type Output = ();
190
191    #[inline]
192    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
193        Pin::new(&mut self.0).poll(cx)
194    }
195}
196
197impl GroupTokenFactory {
198    /// Consumes the inner token.
199    ///
200    /// This is equivalent to dropping the factory.
201    #[inline]
202    pub fn release(self) {
203        drop(self);
204    }
205
206    #[inline]
207    pub fn into_token(self) -> GroupToken {
208        self.0
209    }
210
211    #[inline]
212    pub fn scope<T, F: FnOnce(GroupToken) -> T>(self, func: F) -> T {
213        func(self.into_token())
214    }
215}
216
217impl GroupToken {
218    /// Consumes the token.
219    ///
220    /// This is equivalent to dropping the token.
221    #[inline]
222    pub fn release(self) {
223        drop(self);
224    }
225}
226
227impl MonoGroupToken {
228    /// Consumes the token.
229    ///
230    /// This is equivalent to dropping the token.
231    #[inline]
232    pub fn release(self) {
233        drop(self);
234    }
235
236    #[inline]
237    pub fn into_token(self) -> Self {
238        self
239    }
240
241    #[inline]
242    pub fn scope<T, F: FnOnce(MonoGroupToken) -> T>(self, func: F) -> T {
243        func(self.into_token())
244    }
245}
246
247impl Drop for MonoGroupToken {
248    #[inline]
249    fn drop(&mut self) {
250        unsafe {
251            self.0.send_done();
252        }
253    }
254}