commit d39c021aa6a2167ec5f91b896fb474eaf2f67b6f Author: Michael Pfaff Date: Thu May 26 10:49:13 2022 -0400 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..bfbb5e3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "drop-guard" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +[features] +tokio1 = [ "dep:tokio1" ] +tokio1-sync = [ "tokio1", "tokio1/sync" ] +tokio1-task = [ "tokio1", "tokio1/rt", "dep:futures-lite" ] +triggered = [ "dep:triggered" ] + +[dependencies] +futures-lite = { version = "1.12", default-features = false, optional = true } +tokio1 = { package = "tokio", version = "1", default-features = false, optional = true } +triggered = { version = "0.1.2", optional = true } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..cdebeb3 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,96 @@ +pub struct DropGuard { + inner: Option, +} + +impl DropGuard { + #[inline] + pub fn unguard(mut self) -> T { + self.inner.take().expect("only None in drop") + } +} + +pub trait DropGuarded { + fn cancel(self); +} + +#[cfg(feature = "tokio1-task")] +impl DropGuarded for tokio1::task::JoinHandle { + #[inline] + fn cancel(self) { + self.abort(); + } +} + +#[cfg(feature = "tokio1-sync")] +impl DropGuarded for tokio1::sync::oneshot::Sender<()> { + #[inline] + fn cancel(self) { + let _ = self.send(()); + } +} + +#[cfg(feature = "tokio1-sync")] +impl DropGuarded for std::sync::Arc { + #[inline] + fn cancel(self) { + self.close(); + } +} + +#[cfg(feature = "triggered")] +impl DropGuarded for triggered::Trigger { + #[inline] + fn cancel(self) { + self.trigger(); + } +} + +#[repr(transparent)] +pub struct ArbitraryDropGuard ()>(Option); + +impl ()> ArbitraryDropGuard { + #[inline] + pub fn new(f: F) -> Self { + Self(Some(f)) + } +} + +impl ()> DropGuarded for ArbitraryDropGuard { + fn cancel(mut self) { + if let Some(f) = self.0.take() { + f(); + } + } +} + +impl DropGuard { + #[inline] + pub fn new(guarded: T) -> Self { + Self { + inner: Some(guarded), + } + } +} + +impl Drop for DropGuard { + #[inline] + fn drop(&mut self) { + if let Some(inner) = self.inner.take() { + inner.cancel(); + } + } +} + +#[cfg(feature = "tokio1-task")] +impl std::future::Future for DropGuard> { + type Output = Result; + + fn poll( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll { + use futures_lite::future::FutureExt; + let handle = (*self).inner.as_mut().expect("can only be None in drop"); + handle.poll(cx) + } +}