use alloc::{boxed::Box, vec::Vec};
use core::{
fmt,
future::Future,
pin::Pin,
task::{Context, Poll},
};
type LocalFuture<'a> = Pin<Box<dyn Future<Output = ()> + 'a>>;
type SendFuture<'a> = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
fn poll_tasks<F>(tasks: &mut Vec<Pin<Box<F>>>, context: &mut Context<'_>) -> Poll<()>
where
F: Future<Output = ()> + ?Sized,
{
loop {
let Some(mut future) = tasks.pop() else {
return Poll::Ready(());
};
match future.as_mut().poll(context) {
Poll::Pending => {
tasks.push(future);
return Poll::Pending;
}
Poll::Ready(()) => {}
}
}
}
#[must_use = "call run().await or finish().await to execute registered cleanup actions"]
pub struct LocalAsyncScope<'a> {
tasks: Vec<LocalFuture<'a>>,
}
#[must_use = "futures do nothing unless polled or awaited"]
pub struct LocalRun<'scope, 'task> {
scope: &'scope mut LocalAsyncScope<'task>,
}
impl Future for LocalRun<'_, '_> {
type Output = ();
fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
poll_tasks(&mut self.scope.tasks, context)
}
}
impl<'a> LocalAsyncScope<'a> {
#[inline]
pub const fn new() -> Self {
Self { tasks: Vec::new() }
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
tasks: Vec::with_capacity(capacity),
}
}
#[inline]
pub fn defer<F, Fut>(&mut self, action: F)
where
F: FnOnce() -> Fut + 'a,
Fut: Future<Output = ()> + 'a,
{
self.tasks.push(Box::pin(async move { action().await }));
}
#[inline]
pub fn len(&self) -> usize {
self.tasks.len()
}
#[inline]
pub fn capacity(&self) -> usize {
self.tasks.capacity()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.tasks.is_empty()
}
#[inline]
pub fn clear(&mut self) {
self.tasks.clear();
}
#[inline]
pub fn run(&mut self) -> LocalRun<'_, 'a> {
LocalRun { scope: self }
}
#[inline]
pub async fn finish(mut self) {
self.run().await;
}
}
impl Default for LocalAsyncScope<'_> {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for LocalAsyncScope<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("LocalAsyncScope")
.field("pending", &self.tasks.len())
.finish()
}
}
pub use LocalAsyncScope as AsyncScope;
#[must_use = "call run().await or finish().await to execute registered cleanup actions"]
pub struct SendAsyncScope<'a> {
tasks: Vec<SendFuture<'a>>,
}
#[must_use = "futures do nothing unless polled or awaited"]
pub struct SendRun<'scope, 'task> {
scope: &'scope mut SendAsyncScope<'task>,
}
impl Future for SendRun<'_, '_> {
type Output = ();
fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
poll_tasks(&mut self.scope.tasks, context)
}
}
impl<'a> SendAsyncScope<'a> {
#[inline]
pub const fn new() -> Self {
Self { tasks: Vec::new() }
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
tasks: Vec::with_capacity(capacity),
}
}
#[inline]
pub fn defer<F, Fut>(&mut self, action: F)
where
F: FnOnce() -> Fut + Send + 'a,
Fut: Future<Output = ()> + Send + 'a,
{
self.tasks.push(Box::pin(async move { action().await }));
}
#[inline]
pub fn len(&self) -> usize {
self.tasks.len()
}
#[inline]
pub fn capacity(&self) -> usize {
self.tasks.capacity()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.tasks.is_empty()
}
#[inline]
pub fn clear(&mut self) {
self.tasks.clear();
}
#[inline]
pub fn run(&mut self) -> SendRun<'_, 'a> {
SendRun { scope: self }
}
#[inline]
pub async fn finish(mut self) {
self.run().await;
}
}
impl Default for SendAsyncScope<'_> {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for SendAsyncScope<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("SendAsyncScope")
.field("pending", &self.tasks.len())
.finish()
}
}