commit 0ef7fd0e9d85f52bdd803f0cac70b354f7d270f0 Author: Avril Date: Wed Dec 30 02:01:53 2020 +0000 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..80aca69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +*~ diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..fe6a944 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "phantomdrop" +version = "0.1.0" +authors = ["Avril "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f3f3ec2 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,110 @@ +//! Small library for `defer`ing the running of function until the end of a block. + +use core::mem::MaybeUninit; +use core::ops::Drop; + +/// When dropped, the included function is ran with the argument held by the structure. +#[derive(Debug)] +pub struct PhantomDrop(MaybeUninit<(T, F)>); + +impl Clone for PhantomDrop +{ + #[inline] fn clone(&self) -> Self + { + let re = unsafe { self.value_ref() }; + Self(MaybeUninit::new((re.0.clone(), re.1.clone()))) + } +} + +impl PhantomDrop<(),F> +where F: FnOnce(()) +{ + /// Defer a function to run when this guard is dropped. + #[inline] pub fn defer(fun: F) -> Self + { + PhantomDrop::new((), fun) + } +} +impl PhantomDrop +where F: FnOnce(T) +{ + #[inline(always)] unsafe fn value_mut(&mut self) -> &mut (T, F) + { + &mut (*self.0.as_mut_ptr()) + } + #[inline(always)] unsafe fn value_ref(&self) -> &(T, F) + { + &(*self.0.as_ptr()) + } + #[inline(always)] unsafe fn into_raw_parts(self) -> (T, F) + { + let (v, f) = self.0.as_ptr().read(); + core::mem::forget(self); + (v, f) + } + + /// Defer a function to run on this stored value when this guard is + #[inline] pub fn new(value: T, fun: F) -> Self + { + Self(MaybeUninit::new((value, fun))) + } + + /// Consume the instance into its held type without running the drop closure. + #[inline] pub fn into_inner(self) -> T + { + unsafe { self.into_raw_parts() }.0 + } + + /// Get a mutable reference to the held type. + #[inline] pub fn as_mut(&mut self) -> &mut T + { + unsafe { &mut self.value_mut().0 } + } + /// Get a reference to the held type. + #[inline] pub fn as_ref(&self) -> &T + { + unsafe { &self.value_ref().0 } + } + + /// Replace the function to be ran on drop with a no-op. + #[inline] pub fn neutralise(self) -> PhantomDrop + { + PhantomDrop::new(self.into_inner(), drop) + } + +} + +impl PhantomDrop> +{ + /// Box the closure in this instance. + #[inline] pub fn boxed(self) -> PhantomDrop> + { + let (v, f) = unsafe { self.into_raw_parts() }; + PhantomDrop::new(v, Box::new(f)) + } + + /// Replace the function to be ran on drop with a no-op in place. + #[inline] pub fn neutralise_boxed(&mut self) + { + unsafe { self.value_mut().1 = Box::new(drop) }; + } +} +impl PhantomDrop +{ + /// Replace the function to be ran on drop with a no-op in place. + #[inline] pub fn neutralise_in_place(&mut self) + { + unsafe { self.value_mut().1 = drop }; + } +} + + +impl Drop for PhantomDrop +where F: FnOnce(T) +{ + #[inline] fn drop(&mut self) + { + let (v, f) = unsafe { self.0.as_ptr().read() }; + f(v); + } +}