-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(simple): add no-default-bound feature
For those who cannot easily implement `Default` (ex. a large struct), a version of the simple dropper that relies on an inner `Option<T>` can be more convenient to write. This commit adds a feature flag `no-default-bound` that removes the `Default` bound requirement. Co-authored-by: Linken Quy Dinh <[email protected]>
- Loading branch information
Showing
5 changed files
with
319 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
//! Implementation of simple AsyncDropper that does not require `Default` | ||
//! | ||
//! This implementation might be preferrable for people who cannot reasonably | ||
//! implement `Default` for their struct, but have easily accessible `Eq`,`PartialEq`, | ||
//! `Hash`, and/or `Clone` instances. | ||
#![cfg(not(feature = "no-default-bound"))] | ||
|
||
use std::time::Duration; | ||
|
||
#[async_trait::async_trait] | ||
pub trait AsyncDrop { | ||
async fn async_drop(&mut self); | ||
} | ||
|
||
/// Wrapper struct that enables `async_drop()` behavior. | ||
/// | ||
/// This version requires a `Default` implementation. | ||
#[derive(Default)] | ||
#[allow(dead_code)] | ||
pub struct AsyncDropper<T: AsyncDrop + Default + Send + 'static> { | ||
dropped: bool, | ||
timeout: Option<Duration>, | ||
inner: T, | ||
} | ||
|
||
impl<T: AsyncDrop + Default + Send + 'static> AsyncDropper<T> { | ||
pub fn new(inner: T) -> Self { | ||
Self { | ||
dropped: false, | ||
timeout: None, | ||
inner, | ||
} | ||
} | ||
|
||
pub fn with_timeout(timeout: Duration, inner: T) -> Self { | ||
Self { | ||
dropped: false, | ||
timeout: Some(timeout), | ||
inner, | ||
} | ||
} | ||
} | ||
|
||
#[cfg(all(not(feature = "tokio"), not(feature = "async-std")))] | ||
impl<T: AsyncDrop + Default + Send + 'static> Drop for AsyncDropper<T> { | ||
fn drop(&mut self) { | ||
compile_error!( | ||
"either 'async-std' or 'tokio' features must be enabled for the async-dropper crate" | ||
) | ||
} | ||
} | ||
|
||
#[cfg(all(feature = "async-std", feature = "tokio"))] | ||
impl<T: AsyncDrop + Default + Send + 'static> Drop for AsyncDropper<T> { | ||
fn drop(&mut self) { | ||
compile_error!( | ||
"'async-std' and 'tokio' features cannot both be specified for the async-dropper crate" | ||
) | ||
} | ||
} | ||
|
||
#[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> { | ||
fn drop(&mut self) { | ||
if !self.dropped { | ||
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 { | ||
Some(d) => { | ||
let _ = futures::executor::block_on(tokio::time::timeout(d, task)); | ||
} | ||
None => { | ||
let _ = futures::executor::block_on(task); | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
|
||
#[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> { | ||
fn drop(&mut self) { | ||
if !self.dropped { | ||
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 { | ||
Some(d) => { | ||
let _ = futures::executor::block_on(async_std::future::timeout(d, task)); | ||
} | ||
None => { | ||
let _ = futures::executor::block_on(task); | ||
} | ||
}; | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::AsyncDropper; | ||
use async_trait::async_trait; | ||
|
||
/// Testing struct | ||
#[derive(Default)] | ||
struct Test(String); | ||
|
||
#[async_trait] | ||
impl AsyncDrop for Test { | ||
async fn async_drop(&mut self) { | ||
tokio::time::sleep(Duration::from_secs(1)).await; | ||
} | ||
} | ||
|
||
/// Ensure that `Default`-bounded dropper works with tokio | ||
#[cfg(tokio)] | ||
#[tokio::test] | ||
async fn tokio_works() -> Result<(), Box<dyn std::error::Error>> { | ||
let start = std::time::Instant::now(); | ||
let wrapped_t = AsyncDropper::new(Test::new("no timeout".into())); | ||
drop(wrapped_t); | ||
assert!(start.elapsed(), "two seconds have passed since drop"); | ||
} | ||
|
||
/// Ensure that `Default`-bounded dropper works with async-std | ||
#[cfg(async-std)] | ||
#[tokio::test] | ||
async fn tokio_works() -> Result<(), Box<dyn std::error::Error>> { | ||
let start = std::time::Instant::now(); | ||
let wrapped_t = AsyncDropper::new(Test::new("no timeout".into())); | ||
drop(wrapped_t); | ||
assert!(start.elapsed(), "two seconds have passed since drop"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.