use core::{
fmt::{self, Debug},
mem::ManuallyDrop,
ops::{Deref, DerefMut},
};
pub(crate) struct DropGuard<T, F>
where
F: FnOnce(T),
{
inner: ManuallyDrop<T>,
func: ManuallyDrop<F>,
}
impl<T, F> DropGuard<T, F>
where
F: FnOnce(T),
{
#[must_use]
pub(crate) const fn new(inner: T, func: F) -> Self {
Self {
inner: ManuallyDrop::new(inner),
func: ManuallyDrop::new(func),
}
}
#[inline]
pub(crate) fn dismiss(guard: Self) -> T {
let mut guard = ManuallyDrop::new(guard);
let value = unsafe { ManuallyDrop::take(&mut guard.inner) };
unsafe {
ManuallyDrop::drop(&mut guard.func);
}
value
}
}
impl<T, F> Deref for DropGuard<T, F>
where
F: FnOnce(T),
{
type Target = T;
fn deref(&self) -> &T {
&self.inner
}
}
impl<T, F> DerefMut for DropGuard<T, F>
where
F: FnOnce(T),
{
fn deref_mut(&mut self) -> &mut T {
&mut self.inner
}
}
impl<T, F> Drop for DropGuard<T, F>
where
F: FnOnce(T),
{
fn drop(&mut self) {
let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
let func = unsafe { ManuallyDrop::take(&mut self.func) };
func(inner);
}
}
impl<T, F> Debug for DropGuard<T, F>
where
T: Debug,
F: FnOnce(T),
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}