use crate::{Deref, DerefMut};
#[doc = crate::_tags!(guard)]
#[doc = crate::_doc_location!("code")]
#[doc = crate::_doc!(vendor: "stated-scope-guard")]
#[derive(Debug)]
pub struct ScopeGuard<T, F: FnOnce(T, &S), S> {
value: Option<T>,
callback: Option<F>,
state: S,
}
impl<T> ScopeGuard<T, fn(T, &bool), bool> {
pub fn new<F: FnOnce(T)>(value: T, callback: F) -> ScopeGuard<T, impl FnOnce(T, &bool), bool> {
ScopeGuard::with(value, true, move |value, state: &bool| {
if *state {
callback(value);
}
})
}
}
impl<T, F: FnOnce(T, &bool)> ScopeGuard<T, F, bool> {
pub fn dismiss(&mut self) {
self.set_state(false);
}
}
impl<T, F: FnOnce(T, &S), S> ScopeGuard<T, F, S> {
pub fn with(value: T, state: S, callback: F) -> Self {
Self {
value: Some(value),
state,
callback: Some(callback),
}
}
pub fn set_state(&mut self, state: S) {
self.state = state;
}
}
#[rustfmt::skip]
impl<T, F: FnOnce(T, &S), S> Deref for ScopeGuard<T, F, S> {
type Target = T;
fn deref(&self) -> &Self::Target {
#[cfg(any(feature = "safe_code", not(feature = "unsafe_layout")))]
{ self.value.as_ref().unwrap() }
#[cfg(all(not(feature = "safe_code"), feature = "unsafe_layout"))]
unsafe { self.value.as_ref().unwrap_unchecked() }
}
}
#[rustfmt::skip]
impl<T, F: FnOnce(T, &S), S> DerefMut for ScopeGuard<T, F, S> {
fn deref_mut(&mut self) -> &mut Self::Target {
#[cfg(any(feature = "safe_code", not(feature = "unsafe_layout")))]
{ self.value.as_mut().unwrap() }
#[cfg(all(not(feature = "safe_code"), feature = "unsafe_layout"))]
unsafe { self.value.as_mut().unwrap_unchecked() }
}
}
impl<T, F: FnOnce(T, &S), S> Drop for ScopeGuard<T, F, S> {
fn drop(&mut self) {
let (value, callback) = {
#[cfg(any(feature = "safe_code", not(feature = "unsafe_layout")))]
{
let value = self.value.take().unwrap();
let callback = self.callback.take().unwrap();
(value, callback)
}
#[cfg(all(not(feature = "safe_code"), feature = "unsafe_layout"))]
{
let value = unsafe { self.value.take().unwrap_unchecked() };
let callback = unsafe { self.callback.take().unwrap_unchecked() };
(value, callback)
}
};
callback(value, &self.state);
}
}