scope_guard/
lib.rs

1//! Simple RAII scope guard
2//!
3//! ## Usage:
4//!
5//! #### No argument guard
6//! ```
7//! use scope_guard::scope_guard;
8//!
9//! let mut is_run = false;
10//! {
11//!      scope_guard!(|| {
12//!          is_run = true;
13//!      });
14//! }
15//! assert!(is_run);
16//! ```
17//!
18//! #### Single argument guard
19//!
20//! ```
21//! use scope_guard::scope_guard;
22//!
23//! fn do_stuff(val: &mut u32)  {
24//!     let old_val = *val;
25//!     let mut val = scope_guard!(|val| {
26//!         *val = old_val;
27//!     }, val);
28//!
29//!     **val += 1; //Double * to deref &mut u32
30//!
31//!     let is_ok = false;//doing some computations
32//!     if is_ok {
33//!         val.forget();
34//!     }
35//! }
36//!
37//! let mut val = 0;
38//! do_stuff(&mut val);
39//! assert_eq!(val, 0);
40//!
41//! let mut guard = scope_guard!(|val| {
42//!     *val = 1;
43//! }, &mut val);
44//! drop(guard);
45//! assert_eq!(val, 1);
46//! ```
47//!
48//! #### Stacked destructor calls
49//!
50//! ```
51//! use scope_guard::scope_guard;
52//!
53//! fn do_stuff(val: &mut u32)  {
54//!     let old_value = *val;
55//!     let val = scope_guard!(|val| {
56//!         assert_eq!(*val, old_value);
57//!         //Do nothing
58//!     }, val);
59//!
60//!     let mut val = val.stack(|val| {
61//!         **val = old_value;
62//!     });
63//!
64//!     **val += 1; //Double * to deref &mut u32
65//! }
66//!
67//! let mut val = 0;
68//! do_stuff(&mut val);
69//! assert_eq!(val, 0);
70//! ```
71//!
72//! #### Multiple argument guard
73//!
74//! ```
75//! use scope_guard::scope_guard;
76//!
77//! fn do_stuff(val: &mut u32, is_run: &mut bool)  {
78//!     let old_val = *val;
79//!     let mut guard = scope_guard!(|(val, is_run)| {
80//!         *val = old_val;
81//!         *is_run = false;
82//!     }, val, is_run);
83//!
84//!     *guard.0 += 1;
85//!     *guard.1 = true;
86//!
87//!     let is_ok = false; //doing some computations
88//!     if is_ok {
89//!         let (_val, _is_run) = guard.into_inner(); //analogues to forget
90//!     }
91//! }
92//!
93//! let mut is_run = false;
94//! let mut val = 0;
95//! do_stuff(&mut val, &mut is_run);
96//! assert_eq!(val, 0);
97//! assert!(!is_run);
98//!
99//! let mut guard = scope_guard!(|(val, is_run)| {
100//!     *val = 1;
101//!     *is_run = true;
102//! }, &mut val, &mut is_run);
103//!
104//! drop(guard);
105//! assert_eq!(val, 1);
106//! assert!(is_run);
107//! ```
108
109#![no_std]
110#![warn(missing_docs)]
111#![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
112#![cfg_attr(feature = "cargo-clippy", allow(clippy::explicit_auto_deref))]
113
114use core::{ptr, mem};
115
116#[cfg(feature = "std")]
117mod async_scope;
118#[cfg(feature = "std")]
119pub use async_scope::{async_scope, CatchUnwindFut};
120
121///RAII Scope, running closure in destructor.
122pub struct Scope<T, F: FnOnce(T)> {
123    val: mem::ManuallyDrop<T>,
124    dtor: mem::ManuallyDrop<F>
125}
126
127impl<T, F: FnOnce(T)> Scope<T, F> {
128    #[inline(always)]
129    ///Creates new instance
130    pub fn new(val: T, dtor: F) -> Self {
131        Self {
132            val: mem::ManuallyDrop::new(val),
133            dtor: mem::ManuallyDrop::new(dtor),
134        }
135    }
136
137    #[inline(always)]
138    fn get_value(&self) -> T {
139        unsafe {
140            ptr::read(&*self.val)
141        }
142    }
143
144    #[inline(always)]
145    fn get_dtor(&self) -> F {
146        unsafe {
147            ptr::read(&*self.dtor)
148        }
149    }
150
151    #[inline]
152    ///Returns underlying data, without executing destructor;
153    pub fn into_inner(self) -> T {
154        let value = self.get_value();
155        self.forget();
156        value
157    }
158
159    #[inline]
160    ///Forgets self, preventing closure from running
161    pub fn forget(self) {
162        self.get_dtor();
163        mem::forget(self);
164    }
165}
166
167impl<T, F: FnOnce(T)> Scope<T, F> {
168    ///Adds new function to be invoked in scope of the guard.
169    ///
170    ///This function is executed before current one.
171    ///Similarly to how stack variables dtors are invoked in reverse order.
172    ///
173    ///Note that stacked function cannot take guarded by value, only original function will retain
174    ///owned value.
175    pub fn stack<NF: FnOnce(&mut T)>(self, dtor: NF) -> Scope<T, impl FnOnce(T)> {
176        let current_dtor = self.get_dtor();
177        let value = self.get_value();
178        mem::forget(self);
179        Scope::new(value, move |mut value| {
180            dtor(&mut value);
181            current_dtor(value)
182        })
183    }
184}
185
186impl<T, F: FnOnce(T)> core::ops::Deref for Scope<T, F> {
187    type Target = T;
188
189    fn deref(&self) -> &Self::Target {
190        &*self.val
191    }
192}
193
194impl<T, F: FnOnce(T)> core::ops::DerefMut for Scope<T, F> {
195    fn deref_mut(&mut self) -> &mut Self::Target {
196        &mut *self.val
197    }
198}
199
200impl<T, F: FnOnce(T)> Drop for Scope<T, F> {
201    #[inline(always)]
202    fn drop(&mut self) {
203        let val = self.get_value();
204        let func = self.get_dtor();
205        func(val);
206    }
207}
208
209#[macro_export]
210///Creates scope guard, allowing to supply plain function with arguments in addition to
211///closures.
212macro_rules! scope_guard {
213    ($dtor:expr) => {
214        $crate::Scope::new((), |_| $dtor())
215    };
216    ($dtor:expr, $arg:expr) => {
217        $crate::Scope::new($arg, $dtor)
218    };
219    ($dtor:expr, $($args:expr),+) => {
220        $crate::Scope::new(($($args),+), $dtor)
221    };
222}