async_safe_defer/
async_scope.rs1use alloc::{boxed::Box, vec::Vec};
2use core::{
3 fmt,
4 future::Future,
5 pin::Pin,
6 task::{Context, Poll},
7};
8
9type LocalFuture<'a> = Pin<Box<dyn Future<Output = ()> + 'a>>;
10type SendFuture<'a> = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
11
12fn poll_tasks<F>(tasks: &mut Vec<Pin<Box<F>>>, context: &mut Context<'_>) -> Poll<()>
13where
14 F: Future<Output = ()> + ?Sized,
15{
16 loop {
17 let Some(mut future) = tasks.pop() else {
18 return Poll::Ready(());
19 };
20
21 match future.as_mut().poll(context) {
22 Poll::Pending => {
23 tasks.push(future);
24 return Poll::Pending;
25 }
26 Poll::Ready(()) => {}
27 }
28 }
29}
30
31#[must_use = "call run().await or finish().await to execute registered cleanup actions"]
41pub struct LocalAsyncScope<'a> {
42 tasks: Vec<LocalFuture<'a>>,
43}
44
45#[must_use = "futures do nothing unless polled or awaited"]
47pub struct LocalRun<'scope, 'task> {
48 scope: &'scope mut LocalAsyncScope<'task>,
49}
50
51impl Future for LocalRun<'_, '_> {
52 type Output = ();
53
54 fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
55 poll_tasks(&mut self.scope.tasks, context)
56 }
57}
58
59impl<'a> LocalAsyncScope<'a> {
60 #[inline]
62 pub const fn new() -> Self {
63 Self { tasks: Vec::new() }
64 }
65
66 #[inline]
68 pub fn with_capacity(capacity: usize) -> Self {
69 Self {
70 tasks: Vec::with_capacity(capacity),
71 }
72 }
73
74 #[inline]
76 pub fn defer<F, Fut>(&mut self, action: F)
77 where
78 F: FnOnce() -> Fut + 'a,
79 Fut: Future<Output = ()> + 'a,
80 {
81 self.tasks.push(Box::pin(async move { action().await }));
82 }
83
84 #[inline]
86 pub fn len(&self) -> usize {
87 self.tasks.len()
88 }
89
90 #[inline]
92 pub fn capacity(&self) -> usize {
93 self.tasks.capacity()
94 }
95
96 #[inline]
98 pub fn is_empty(&self) -> bool {
99 self.tasks.is_empty()
100 }
101
102 #[inline]
104 pub fn clear(&mut self) {
105 self.tasks.clear();
106 }
107
108 #[inline]
110 pub fn run(&mut self) -> LocalRun<'_, 'a> {
111 LocalRun { scope: self }
112 }
113
114 #[inline]
118 pub async fn finish(mut self) {
119 self.run().await;
120 }
121}
122
123impl Default for LocalAsyncScope<'_> {
124 fn default() -> Self {
125 Self::new()
126 }
127}
128
129impl fmt::Debug for LocalAsyncScope<'_> {
130 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
131 formatter
132 .debug_struct("LocalAsyncScope")
133 .field("pending", &self.tasks.len())
134 .finish()
135 }
136}
137
138pub use LocalAsyncScope as AsyncScope;
142
143#[must_use = "call run().await or finish().await to execute registered cleanup actions"]
148pub struct SendAsyncScope<'a> {
149 tasks: Vec<SendFuture<'a>>,
150}
151
152#[must_use = "futures do nothing unless polled or awaited"]
154pub struct SendRun<'scope, 'task> {
155 scope: &'scope mut SendAsyncScope<'task>,
156}
157
158impl Future for SendRun<'_, '_> {
159 type Output = ();
160
161 fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
162 poll_tasks(&mut self.scope.tasks, context)
163 }
164}
165
166impl<'a> SendAsyncScope<'a> {
167 #[inline]
169 pub const fn new() -> Self {
170 Self { tasks: Vec::new() }
171 }
172
173 #[inline]
175 pub fn with_capacity(capacity: usize) -> Self {
176 Self {
177 tasks: Vec::with_capacity(capacity),
178 }
179 }
180
181 #[inline]
183 pub fn defer<F, Fut>(&mut self, action: F)
184 where
185 F: FnOnce() -> Fut + Send + 'a,
186 Fut: Future<Output = ()> + Send + 'a,
187 {
188 self.tasks.push(Box::pin(async move { action().await }));
189 }
190
191 #[inline]
193 pub fn len(&self) -> usize {
194 self.tasks.len()
195 }
196
197 #[inline]
199 pub fn capacity(&self) -> usize {
200 self.tasks.capacity()
201 }
202
203 #[inline]
205 pub fn is_empty(&self) -> bool {
206 self.tasks.is_empty()
207 }
208
209 #[inline]
211 pub fn clear(&mut self) {
212 self.tasks.clear();
213 }
214
215 #[inline]
217 pub fn run(&mut self) -> SendRun<'_, 'a> {
218 SendRun { scope: self }
219 }
220
221 #[inline]
225 pub async fn finish(mut self) {
226 self.run().await;
227 }
228}
229
230impl Default for SendAsyncScope<'_> {
231 fn default() -> Self {
232 Self::new()
233 }
234}
235
236impl fmt::Debug for SendAsyncScope<'_> {
237 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
238 formatter
239 .debug_struct("SendAsyncScope")
240 .field("pending", &self.tasks.len())
241 .finish()
242 }
243}