Skip to main content

compact_waitgroup/
wait_group.rs

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