#![no_std]
#![warn(missing_docs)]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::explicit_auto_deref))]
use core::{ptr, mem};
#[cfg(feature = "std")]
mod async_scope;
#[cfg(feature = "std")]
pub use async_scope::{async_scope, CatchUnwindFut};
pub struct Scope<T, F: FnOnce(T)> {
val: mem::ManuallyDrop<T>,
dtor: mem::ManuallyDrop<F>
}
impl<T, F: FnOnce(T)> Scope<T, F> {
#[inline(always)]
pub fn new(val: T, dtor: F) -> Self {
Self {
val: mem::ManuallyDrop::new(val),
dtor: mem::ManuallyDrop::new(dtor),
}
}
#[inline(always)]
fn get_value(&self) -> T {
unsafe {
ptr::read(&*self.val)
}
}
#[inline(always)]
fn get_dtor(&self) -> F {
unsafe {
ptr::read(&*self.dtor)
}
}
#[inline]
pub fn into_inner(self) -> T {
let value = self.get_value();
self.forget();
value
}
#[inline]
pub fn forget(self) {
self.get_dtor();
mem::forget(self);
}
}
impl<T, F: FnOnce(T)> Scope<T, F> {
pub fn stack<NF: FnOnce(&mut T)>(self, dtor: NF) -> Scope<T, impl FnOnce(T)> {
let current_dtor = self.get_dtor();
let value = self.get_value();
mem::forget(self);
Scope::new(value, move |mut value| {
dtor(&mut value);
current_dtor(value)
})
}
}
impl<T, F: FnOnce(T)> core::ops::Deref for Scope<T, F> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.val
}
}
impl<T, F: FnOnce(T)> core::ops::DerefMut for Scope<T, F> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.val
}
}
impl<T, F: FnOnce(T)> Drop for Scope<T, F> {
#[inline(always)]
fn drop(&mut self) {
let val = self.get_value();
let func = self.get_dtor();
func(val);
}
}
#[macro_export]
macro_rules! scope_guard {
($dtor:expr) => {
$crate::Scope::new((), |_| $dtor())
};
($dtor:expr, $arg:expr) => {
$crate::Scope::new($arg, $dtor)
};
($dtor:expr, $($args:expr),+) => {
$crate::Scope::new(($($args),+), $dtor)
};
}