Skip to content

Commit

Permalink
feat(simple): remove static requirement by using async-scoped
Browse files Browse the repository at this point in the history
This commit introduces `async-scoped` in order to remove the `'static`
lifetime bounds on the async_drop task.

Co-authored-by: Linken Quy Dinh <[email protected]>
  • Loading branch information
t3hmrman and beckend committed Jan 31, 2024
1 parent 7ff6cee commit d2d8345
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 21 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ members = [

[workspace.dependencies]
async-std = "1.12.0"
async-scoped = "0.9.0"
tokio = "1.33.0"
async-trait = "0.1.74"
proc-macro2 = "1.0.69"
Expand Down
5 changes: 3 additions & 2 deletions crates/async-dropper-simple/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ A simple struct-wrapper (i.e. AsyncDropper<T>) based implementation of AsyncDrop

[features]
default = []
tokio = ["dep:tokio"]
async-std = ["dep:async-std"]
tokio = ["dep:tokio", "dep:async-scoped", "async-scoped/use-tokio"]
async-std = ["dep:async-std", "dep:async-scoped", "async-scoped/use-async-std"]

[dependencies]
async-scoped = { workspace = true, optional = true }
async-std = { workspace = true, optional = true }
tokio = { workspace = true, optional = true, features = [
"time",
Expand Down
56 changes: 37 additions & 19 deletions crates/async-dropper-simple/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ pub trait AsyncDrop {

#[derive(Default)]
#[allow(dead_code)]
pub struct AsyncDropper<T: AsyncDrop + Default + Send + 'static> {
pub struct AsyncDropper<T: AsyncDrop + Default + Send> {
dropped: bool,
timeout: Option<Duration>,
inner: T,
}

impl<T: AsyncDrop + Default + Send + 'static> AsyncDropper<T> {
impl<T: AsyncDrop + Default + Send> AsyncDropper<T> {
pub fn new(inner: T) -> Self {
Self {
dropped: false,
Expand All @@ -36,7 +36,7 @@ impl<T: AsyncDrop + Default + Send + 'static> AsyncDropper<T> {
}

#[cfg(all(not(feature = "tokio"), not(feature = "async-std")))]
impl<T: AsyncDrop + Default + Send + 'static> Drop for AsyncDropper<T> {
impl<T: AsyncDrop + Default + Send> Drop for AsyncDropper<T> {
fn drop(&mut self) {
compile_error!(
"either 'async-std' or 'tokio' features must be enabled for the async-dropper crate"
Expand All @@ -45,7 +45,7 @@ impl<T: AsyncDrop + Default + Send + 'static> Drop for AsyncDropper<T> {
}

#[cfg(all(feature = "async-std", feature = "tokio"))]
impl<T: AsyncDrop + Default + Send + 'static> Drop for AsyncDropper<T> {
impl<T: AsyncDrop + Default + Send> Drop for AsyncDropper<T> {
fn drop(&mut self) {
compile_error!(
"'async-std' and 'tokio' features cannot both be specified for the async-dropper crate"
Expand All @@ -55,52 +55,70 @@ impl<T: AsyncDrop + Default + Send + 'static> Drop for AsyncDropper<T> {

#[cfg(all(feature = "tokio", not(feature = "async-std")))]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
impl<T: AsyncDrop + Default + Send + 'static> Drop for AsyncDropper<T> {
impl<T: AsyncDrop + Default + Send> Drop for AsyncDropper<T> {
fn drop(&mut self) {
if !self.dropped {
use async_scoped::TokioScope;

let mut this = std::mem::take(self);
this.dropped = true;

// Create task
let timeout = self.timeout;
let task = tokio::spawn(async move {
this.inner.async_drop().await;
});

tokio::task::block_in_place(|| match timeout {
match timeout {
// If a timeout was specified, use it when performing async_drop
Some(d) => {
let _ = futures::executor::block_on(tokio::time::timeout(d, task));
TokioScope::scope_and_block(|s| {
s.spawn(tokio::time::timeout(d, async move {
this.inner.async_drop().await;
}))
});
}
// If no timeout was specified, perform async_drop() indefinitely
None => {
let _ = futures::executor::block_on(task);
TokioScope::scope_and_block(|s| {
s.spawn(async move {
this.inner.async_drop().await;
})
});
}
});
}
}
}
}

#[cfg(all(feature = "async-std", not(feature = "tokio")))]
#[cfg_attr(docsrs, doc(cfg(feature = "async-std")))]
impl<T: AsyncDrop + Default + Send + 'static> Drop for AsyncDropper<T> {
impl<T: AsyncDrop + Default + Send> Drop for AsyncDropper<T> {
fn drop(&mut self) {
if !self.dropped {
use async_scoped::AsyncStdScope;

let mut this = std::mem::take(self);
this.dropped = true;

// Create task
let timeout = self.timeout.clone();
let task = async_std::task::spawn(async move {
this.inner.async_drop().await;
});

match timeout {
// If a timeout was specified, use it when performing async_drop
Some(d) => {
let _ = futures::executor::block_on(async_std::future::timeout(d, task));
AsyncStdScope::scope_and_block(|s| {
s.spawn(async_std::future::timeout(d, async move {
this.inner.async_drop().await;
}))
});
}
// If no timeout was specified, perform async_drop() indefinitely
None => {
let _ = futures::executor::block_on(task);
AsyncStdScope::scope_and_block(|s| {
s.spawn(async move {
this.inner.async_drop().await;
})
});
}
};
}
}
}
}

0 comments on commit d2d8345

Please sign in to comment.