You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
168 lines
2.9 KiB
168 lines
2.9 KiB
#[allow(unused_imports)]
|
|
use std::{
|
|
ops::{
|
|
Drop,
|
|
Deref,
|
|
DerefMut,
|
|
},
|
|
mem::{
|
|
replace,
|
|
MaybeUninit,
|
|
},
|
|
fmt,
|
|
};
|
|
use cfg_if::cfg_if;
|
|
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
type OptFn<T,F> = MaybeUninit<(T,F)>;
|
|
#[cfg(debug_assertions)]
|
|
type OptFn<T,F> = Option<(T,F)>;
|
|
|
|
/// Allow for running function on drop, to support moving out of a larger structure.
|
|
///
|
|
/// # Notes
|
|
/// This type has a safe ABI with runtime checks when compiled with `debug_assertions`, without them an unsafe but lower cost ABI is preferred.
|
|
pub struct PhantomDrop<T,F>(OptFn<T,F>)
|
|
where F: FnOnce(T);
|
|
|
|
|
|
impl<T,F> fmt::Debug for PhantomDrop<T,F>
|
|
where F:FnOnce(T),
|
|
T: fmt::Debug,
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
{
|
|
self.deref().fmt(f)
|
|
}
|
|
}
|
|
|
|
impl<T,F> Drop for PhantomDrop<T,F>
|
|
where F:FnOnce(T)
|
|
{
|
|
fn drop(&mut self) {
|
|
cfg_if! {
|
|
if #[cfg(debug_assertions)] {
|
|
if let Some((value, func)) = replace(&mut self.0, None)
|
|
{
|
|
func(value);
|
|
} else {
|
|
panic!("Double drop?")
|
|
}
|
|
} else {
|
|
let (value, func) = unsafe {
|
|
(&mut self.0 as *mut OptFn<T,F>).read().assume_init()
|
|
};
|
|
func(value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl<T,F> PhantomDrop<T,F>
|
|
where F:FnOnce(T)
|
|
{
|
|
/// Create a new `PhantomDrop` with a drop closure and a value.
|
|
#[cfg(nightly)]
|
|
pub const fn new(value: T, func: F) -> Self
|
|
{
|
|
cfg_if! {
|
|
if #[cfg(debug_assertions)] {
|
|
Self(Some((value,func)))
|
|
} else {
|
|
Self(MaybeUninit::new((value,func)))
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Create a new `PhantomDrop` with a drop closure and a value.
|
|
#[cfg(not(nightly))]
|
|
pub fn new(value: T, func: F) -> Self
|
|
{
|
|
cfg_if! {
|
|
if #[cfg(debug_assertions)] {
|
|
Self(Some((value,func)))
|
|
} else {
|
|
Self(MaybeUninit::new((value,func)))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
#[inline]
|
|
fn get_ref<'a>(&'a self) -> &'a (T, F)
|
|
{
|
|
unsafe {
|
|
cfg_if! {
|
|
if #[cfg(nightly)] {
|
|
self.0.get_ref()
|
|
} else {
|
|
std::mem::transmute(self.0.as_ptr())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
#[inline]
|
|
fn get_mut<'a>(&'a mut self) -> &'a mut (T, F)
|
|
{
|
|
unsafe {
|
|
cfg_if! {
|
|
if #[cfg(nightly)] {
|
|
self.0.get_mut()
|
|
} else {
|
|
std::mem::transmute(self.0.as_mut_ptr())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl<T,F> Deref for PhantomDrop<T,F>
|
|
where F:FnOnce(T)
|
|
{
|
|
type Target = T;
|
|
fn deref(&self) -> &Self::Target
|
|
{
|
|
cfg_if! {
|
|
if #[cfg(debug_assertions)] {
|
|
if let Some((t, _)) = &self.0
|
|
{
|
|
t
|
|
} else {
|
|
panic!("Double drop?")
|
|
}
|
|
} else {
|
|
let (t, _) = self.get_ref();
|
|
t
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl<T,F> DerefMut for PhantomDrop<T,F>
|
|
where F:FnOnce(T)
|
|
{
|
|
fn deref_mut(&mut self) -> &mut <Self as Deref>::Target
|
|
{
|
|
cfg_if! {
|
|
if #[cfg(debug_assertions)] {
|
|
if let Some((t, _)) = &mut self.0
|
|
{
|
|
t
|
|
} else {
|
|
panic!("Double drop?")
|
|
}
|
|
} else {
|
|
let (t, _) = self.get_mut();
|
|
t
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|