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}