rs42/scope_guard.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
use std::{
mem::ManuallyDrop,
ops::{Deref, DerefMut},
};
/// Structure that wraps a value and calls a callback function when it exits scope
pub struct ScopeGuard<T, F>
where
F: FnOnce(T),
{
content: ManuallyDrop<T>,
callback: ManuallyDrop<F>,
}
impl<T, F> ScopeGuard<T, F>
where
F: FnOnce(T),
{
/// Wraps content in a ScopeGuard and calls callback when the returned value exits scope
///
/// # Example
/// ```
/// use rs42::scope_guard::ScopeGuard;
/// use std::cell::Cell;
///
/// let nb = Cell::new(0_i32);
/// {
/// let _scope_guard = ScopeGuard::new(42, |e| nb.set(e));
/// assert_eq!(nb.get(), 0);
/// }
/// assert_eq!(nb.get(), 42);
/// ```
#[allow(dead_code)]
#[must_use]
pub fn new(content: T, callback: F) -> Self {
ScopeGuard {
content: ManuallyDrop::new(content),
callback: ManuallyDrop::new(callback),
}
}
/// Returns the scope guard content and cancels the call to callback
///
/// # Example
/// ```
/// use rs42::scope_guard::ScopeGuard;
/// use std::cell::Cell;
///
/// let nb = Cell::new(0_i32);
/// {
/// let scope_guard = ScopeGuard::new(42, |e| nb.set(e));
/// let _ = ScopeGuard::into_inner(scope_guard);
/// }
/// assert_eq!(nb.get(), 0);
/// ```
#[allow(dead_code)]
#[must_use]
pub fn into_inner(mut scope_guard: Self) -> T {
unsafe {
ManuallyDrop::drop(&mut scope_guard.callback);
let content = ManuallyDrop::take(&mut scope_guard.content);
let _ = ManuallyDrop::new(scope_guard);
content
}
}
}
impl<T, F> Deref for ScopeGuard<T, F>
where
F: FnOnce(T),
{
type Target = T;
/// Returns a reference to the wrapped value
fn deref(&self) -> &T {
&self.content
}
}
impl<T, F> DerefMut for ScopeGuard<T, F>
where
F: FnOnce(T),
{
/// Returns a mutable reference to the wrapped value
fn deref_mut(&mut self) -> &mut T {
&mut self.content
}
}
impl<T, F> Drop for ScopeGuard<T, F>
where
F: FnOnce(T),
{
/// Calls the callback and drops the wrapped value
fn drop(&mut self) {
unsafe {
let callback = ManuallyDrop::take(&mut self.callback);
let content = ManuallyDrop::take(&mut self.content);
callback(content);
}
}
}
/// Calls the given closure at the end of the current scope
/// # Example
/// ```
/// use rs42::defer;
/// use std::cell::Cell;
///
/// let nb = Cell::new(0);
/// {
/// defer!(nb.set(1));
/// assert_eq!(nb.get(), 0);
/// }
/// assert_eq!(nb.get(), 1);
/// ```
#[macro_export]
macro_rules! defer {
($($t:tt)*) => {
let _scope_guard = $crate::scope_guard::ScopeGuard::new((), |_| { $($t)* });
};
}
/// Wraps self in a ScopeGuard and calls callback when the returned value exits scope
#[allow(dead_code)]
pub trait Defer: Sized {
/// Wraps self in a ScopeGuard and calls callback when the returned value exits scope
///
/// # Example
/// ```
/// use rs42::scope_guard::Defer;
/// use std::cell::Cell;
///
/// let nb = Cell::new(0_i32);
/// {
/// let _scope_guard = 42_i32.defer(|e| nb.set(e));
/// assert_eq!(nb.get(), 0);
/// }
/// assert_eq!(nb.get(), 42);
/// ```
fn defer<F>(self, callback: F) -> ScopeGuard<Self, F>
where
F: FnOnce(Self),
{
ScopeGuard::new(self, callback)
}
}
impl<T> Defer for T {}