/rust/registry/src/index.crates.io-1949cf8c6b5b557f/scopeguard-1.2.0/src/lib.rs
Line | Count | Source |
1 | | #![cfg_attr(not(any(test, feature = "use_std")), no_std)] |
2 | | #![doc(html_root_url = "https://docs.rs/scopeguard/1/")] |
3 | | |
4 | | //! A scope guard will run a given closure when it goes out of scope, |
5 | | //! even if the code between panics. |
6 | | //! (as long as panic doesn't abort) |
7 | | //! |
8 | | //! # Examples |
9 | | //! |
10 | | //! ## Hello World |
11 | | //! |
12 | | //! This example creates a scope guard with an example function: |
13 | | //! |
14 | | //! ``` |
15 | | //! extern crate scopeguard; |
16 | | //! |
17 | | //! fn f() { |
18 | | //! let _guard = scopeguard::guard((), |_| { |
19 | | //! println!("Hello Scope Exit!"); |
20 | | //! }); |
21 | | //! |
22 | | //! // rest of the code here. |
23 | | //! |
24 | | //! // Here, at the end of `_guard`'s scope, the guard's closure is called. |
25 | | //! // It is also called if we exit this scope through unwinding instead. |
26 | | //! } |
27 | | //! # fn main() { |
28 | | //! # f(); |
29 | | //! # } |
30 | | //! ``` |
31 | | //! |
32 | | //! ## `defer!` |
33 | | //! |
34 | | //! Use the `defer` macro to run an operation at scope exit, |
35 | | //! either regular scope exit or during unwinding from a panic. |
36 | | //! |
37 | | //! ``` |
38 | | //! #[macro_use(defer)] extern crate scopeguard; |
39 | | //! |
40 | | //! use std::cell::Cell; |
41 | | //! |
42 | | //! fn main() { |
43 | | //! // use a cell to observe drops during and after the scope guard is active |
44 | | //! let drop_counter = Cell::new(0); |
45 | | //! { |
46 | | //! // Create a scope guard using `defer!` for the current scope |
47 | | //! defer! { |
48 | | //! drop_counter.set(1 + drop_counter.get()); |
49 | | //! } |
50 | | //! |
51 | | //! // Do regular operations here in the meantime. |
52 | | //! |
53 | | //! // Just before scope exit: it hasn't run yet. |
54 | | //! assert_eq!(drop_counter.get(), 0); |
55 | | //! |
56 | | //! // The following scope end is where the defer closure is called |
57 | | //! } |
58 | | //! assert_eq!(drop_counter.get(), 1); |
59 | | //! } |
60 | | //! ``` |
61 | | //! |
62 | | //! ## Scope Guard with Value |
63 | | //! |
64 | | //! If the scope guard closure needs to access an outer value that is also |
65 | | //! mutated outside of the scope guard, then you may want to use the scope guard |
66 | | //! with a value. The guard works like a smart pointer, so the inner value can |
67 | | //! be accessed by reference or by mutable reference. |
68 | | //! |
69 | | //! ### 1. The guard owns a file |
70 | | //! |
71 | | //! In this example, the scope guard owns a file and ensures pending writes are |
72 | | //! synced at scope exit. |
73 | | //! |
74 | | //! ``` |
75 | | //! extern crate scopeguard; |
76 | | //! |
77 | | //! use std::fs::*; |
78 | | //! use std::io::{self, Write}; |
79 | | //! # // Mock file so that we don't actually write a file |
80 | | //! # struct MockFile; |
81 | | //! # impl MockFile { |
82 | | //! # fn create(_s: &str) -> io::Result<Self> { Ok(MockFile) } |
83 | | //! # fn write_all(&self, _b: &[u8]) -> io::Result<()> { Ok(()) } |
84 | | //! # fn sync_all(&self) -> io::Result<()> { Ok(()) } |
85 | | //! # } |
86 | | //! # use self::MockFile as File; |
87 | | //! |
88 | | //! fn try_main() -> io::Result<()> { |
89 | | //! let f = File::create("newfile.txt")?; |
90 | | //! let mut file = scopeguard::guard(f, |f| { |
91 | | //! // ensure we flush file at return or panic |
92 | | //! let _ = f.sync_all(); |
93 | | //! }); |
94 | | //! // Access the file through the scope guard itself |
95 | | //! file.write_all(b"test me\n").map(|_| ()) |
96 | | //! } |
97 | | //! |
98 | | //! fn main() { |
99 | | //! try_main().unwrap(); |
100 | | //! } |
101 | | //! |
102 | | //! ``` |
103 | | //! |
104 | | //! ### 2. The guard restores an invariant on scope exit |
105 | | //! |
106 | | //! ``` |
107 | | //! extern crate scopeguard; |
108 | | //! |
109 | | //! use std::mem::ManuallyDrop; |
110 | | //! use std::ptr; |
111 | | //! |
112 | | //! // This function, just for this example, takes the first element |
113 | | //! // and inserts it into the assumed sorted tail of the vector. |
114 | | //! // |
115 | | //! // For optimization purposes we temporarily violate an invariant of the |
116 | | //! // Vec, that it owns all of its elements. |
117 | | //! // |
118 | | //! // The safe approach is to use swap, which means two writes to memory, |
119 | | //! // the optimization is to use a “hole” which uses only one write of memory |
120 | | //! // for each position it moves. |
121 | | //! // |
122 | | //! // We *must* use a scope guard to run this code safely. We |
123 | | //! // are running arbitrary user code (comparison operators) that may panic. |
124 | | //! // The scope guard ensures we restore the invariant after successful |
125 | | //! // exit or during unwinding from panic. |
126 | | //! fn insertion_sort_first<T>(v: &mut Vec<T>) |
127 | | //! where T: PartialOrd |
128 | | //! { |
129 | | //! struct Hole<'a, T: 'a> { |
130 | | //! v: &'a mut Vec<T>, |
131 | | //! index: usize, |
132 | | //! value: ManuallyDrop<T>, |
133 | | //! } |
134 | | //! |
135 | | //! unsafe { |
136 | | //! // Create a moved-from location in the vector, a “hole”. |
137 | | //! let value = ptr::read(&v[0]); |
138 | | //! let mut hole = Hole { v: v, index: 0, value: ManuallyDrop::new(value) }; |
139 | | //! |
140 | | //! // Use a scope guard with a value. |
141 | | //! // At scope exit, plug the hole so that the vector is fully |
142 | | //! // initialized again. |
143 | | //! // The scope guard owns the hole, but we can access it through the guard. |
144 | | //! let mut hole_guard = scopeguard::guard(hole, |hole| { |
145 | | //! // plug the hole in the vector with the value that was // taken out |
146 | | //! let index = hole.index; |
147 | | //! ptr::copy_nonoverlapping(&*hole.value, &mut hole.v[index], 1); |
148 | | //! }); |
149 | | //! |
150 | | //! // run algorithm that moves the hole in the vector here |
151 | | //! // move the hole until it's in a sorted position |
152 | | //! for i in 1..hole_guard.v.len() { |
153 | | //! if *hole_guard.value >= hole_guard.v[i] { |
154 | | //! // move the element back and the hole forward |
155 | | //! let index = hole_guard.index; |
156 | | //! hole_guard.v.swap(index, index + 1); |
157 | | //! hole_guard.index += 1; |
158 | | //! } else { |
159 | | //! break; |
160 | | //! } |
161 | | //! } |
162 | | //! |
163 | | //! // When the scope exits here, the Vec becomes whole again! |
164 | | //! } |
165 | | //! } |
166 | | //! |
167 | | //! fn main() { |
168 | | //! let string = String::from; |
169 | | //! let mut data = vec![string("c"), string("a"), string("b"), string("d")]; |
170 | | //! insertion_sort_first(&mut data); |
171 | | //! assert_eq!(data, vec!["a", "b", "c", "d"]); |
172 | | //! } |
173 | | //! |
174 | | //! ``` |
175 | | //! |
176 | | //! |
177 | | //! # Crate Features |
178 | | //! |
179 | | //! - `use_std` |
180 | | //! + Enabled by default. Enables the `OnUnwind` and `OnSuccess` strategies. |
181 | | //! + Disable to use `no_std`. |
182 | | //! |
183 | | //! # Rust Version |
184 | | //! |
185 | | //! This version of the crate requires Rust 1.20 or later. |
186 | | //! |
187 | | //! The scopeguard 1.x release series will use a carefully considered version |
188 | | //! upgrade policy, where in a later 1.x version, we will raise the minimum |
189 | | //! required Rust version. |
190 | | |
191 | | #[cfg(not(any(test, feature = "use_std")))] |
192 | | extern crate core as std; |
193 | | |
194 | | use std::fmt; |
195 | | use std::marker::PhantomData; |
196 | | use std::mem::ManuallyDrop; |
197 | | use std::ops::{Deref, DerefMut}; |
198 | | use std::ptr; |
199 | | |
200 | | /// Controls in which cases the associated code should be run |
201 | | pub trait Strategy { |
202 | | /// Return `true` if the guard’s associated code should run |
203 | | /// (in the context where this method is called). |
204 | | fn should_run() -> bool; |
205 | | } |
206 | | |
207 | | /// Always run on scope exit. |
208 | | /// |
209 | | /// “Always” run: on regular exit from a scope or on unwinding from a panic. |
210 | | /// Can not run on abort, process exit, and other catastrophic events where |
211 | | /// destructors don’t run. |
212 | | #[derive(Debug)] |
213 | | pub enum Always {} |
214 | | |
215 | | /// Run on scope exit through unwinding. |
216 | | /// |
217 | | /// Requires crate feature `use_std`. |
218 | | #[cfg(feature = "use_std")] |
219 | | #[derive(Debug)] |
220 | | pub enum OnUnwind {} |
221 | | |
222 | | /// Run on regular scope exit, when not unwinding. |
223 | | /// |
224 | | /// Requires crate feature `use_std`. |
225 | | #[cfg(feature = "use_std")] |
226 | | #[derive(Debug)] |
227 | | pub enum OnSuccess {} |
228 | | |
229 | | impl Strategy for Always { |
230 | | #[inline(always)] |
231 | | fn should_run() -> bool { |
232 | | true |
233 | | } |
234 | | } |
235 | | |
236 | | #[cfg(feature = "use_std")] |
237 | | impl Strategy for OnUnwind { |
238 | | #[inline] |
239 | | fn should_run() -> bool { |
240 | | std::thread::panicking() |
241 | | } |
242 | | } |
243 | | |
244 | | #[cfg(feature = "use_std")] |
245 | | impl Strategy for OnSuccess { |
246 | | #[inline] |
247 | | fn should_run() -> bool { |
248 | | !std::thread::panicking() |
249 | | } |
250 | | } |
251 | | |
252 | | /// Macro to create a `ScopeGuard` (always run). |
253 | | /// |
254 | | /// The macro takes statements, which are the body of a closure |
255 | | /// that will run when the scope is exited. |
256 | | #[macro_export] |
257 | | macro_rules! defer { |
258 | | ($($t:tt)*) => { |
259 | 0 | let _guard = $crate::guard((), |()| { $($t)* });Unexecuted instantiation: <lock_api::mutex::MutexGuard<_, _>>::unlocked::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::mutex::MutexGuard<_, _>>::unlocked_fair::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::rwlock::RwLockReadGuard<_, _>>::unlocked::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::rwlock::RwLockReadGuard<_, _>>::unlocked_fair::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::remutex::ReentrantMutexGuard<_, _, _>>::unlocked::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::remutex::ReentrantMutexGuard<_, _, _>>::unlocked_fair::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::rwlock::RwLockWriteGuard<_, _>>::unlocked::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::rwlock::RwLockWriteGuard<_, _>>::unlocked_fair::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::rwlock::RwLockUpgradableReadGuard<_, _>>::unlocked::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::rwlock::RwLockUpgradableReadGuard<_, _>>::unlocked_fair::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::rwlock::RwLockUpgradableReadGuard<_, _>>::with_upgraded::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::rwlock::RwLockUpgradableReadGuard<_, _>>::try_with_upgraded::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::rwlock::RwLockUpgradableReadGuard<_, _>>::try_with_upgraded_for::<_, _>::{closure#0}Unexecuted instantiation: <lock_api::rwlock::RwLockUpgradableReadGuard<_, _>>::try_with_upgraded_until::<_, _>::{closure#0} |
260 | | }; |
261 | | } |
262 | | |
263 | | /// Macro to create a `ScopeGuard` (run on successful scope exit). |
264 | | /// |
265 | | /// The macro takes statements, which are the body of a closure |
266 | | /// that will run when the scope is exited. |
267 | | /// |
268 | | /// Requires crate feature `use_std`. |
269 | | #[cfg(feature = "use_std")] |
270 | | #[macro_export] |
271 | | macro_rules! defer_on_success { |
272 | | ($($t:tt)*) => { |
273 | | let _guard = $crate::guard_on_success((), |()| { $($t)* }); |
274 | | }; |
275 | | } |
276 | | |
277 | | /// Macro to create a `ScopeGuard` (run on unwinding from panic). |
278 | | /// |
279 | | /// The macro takes statements, which are the body of a closure |
280 | | /// that will run when the scope is exited. |
281 | | /// |
282 | | /// Requires crate feature `use_std`. |
283 | | #[cfg(feature = "use_std")] |
284 | | #[macro_export] |
285 | | macro_rules! defer_on_unwind { |
286 | | ($($t:tt)*) => { |
287 | | let _guard = $crate::guard_on_unwind((), |()| { $($t)* }); |
288 | | }; |
289 | | } |
290 | | |
291 | | /// `ScopeGuard` is a scope guard that may own a protected value. |
292 | | /// |
293 | | /// If you place a guard in a local variable, the closure can |
294 | | /// run regardless how you leave the scope — through regular return or panic |
295 | | /// (except if panic or other code aborts; so as long as destructors run). |
296 | | /// It is run only once. |
297 | | /// |
298 | | /// The `S` parameter for [`Strategy`](trait.Strategy.html) determines if |
299 | | /// the closure actually runs. |
300 | | /// |
301 | | /// The guard's closure will be called with the held value in the destructor. |
302 | | /// |
303 | | /// The `ScopeGuard` implements `Deref` so that you can access the inner value. |
304 | | pub struct ScopeGuard<T, F, S = Always> |
305 | | where |
306 | | F: FnOnce(T), |
307 | | S: Strategy, |
308 | | { |
309 | | value: ManuallyDrop<T>, |
310 | | dropfn: ManuallyDrop<F>, |
311 | | // fn(S) -> S is used, so that the S is not taken into account for auto traits. |
312 | | strategy: PhantomData<fn(S) -> S>, |
313 | | } |
314 | | |
315 | | impl<T, F, S> ScopeGuard<T, F, S> |
316 | | where |
317 | | F: FnOnce(T), |
318 | | S: Strategy, |
319 | | { |
320 | | /// Create a `ScopeGuard` that owns `v` (accessible through deref) and calls |
321 | | /// `dropfn` when its destructor runs. |
322 | | /// |
323 | | /// The `Strategy` decides whether the scope guard's closure should run. |
324 | | #[inline] |
325 | | #[must_use] |
326 | | pub fn with_strategy(v: T, dropfn: F) -> ScopeGuard<T, F, S> { |
327 | | ScopeGuard { |
328 | | value: ManuallyDrop::new(v), |
329 | | dropfn: ManuallyDrop::new(dropfn), |
330 | | strategy: PhantomData, |
331 | | } |
332 | | } |
333 | | |
334 | | /// “Defuse” the guard and extract the value without calling the closure. |
335 | | /// |
336 | | /// ``` |
337 | | /// extern crate scopeguard; |
338 | | /// |
339 | | /// use scopeguard::{guard, ScopeGuard}; |
340 | | /// |
341 | | /// fn conditional() -> bool { true } |
342 | | /// |
343 | | /// fn main() { |
344 | | /// let mut guard = guard(Vec::new(), |mut v| v.clear()); |
345 | | /// guard.push(1); |
346 | | /// |
347 | | /// if conditional() { |
348 | | /// // a condition maybe makes us decide to |
349 | | /// // “defuse” the guard and get back its inner parts |
350 | | /// let value = ScopeGuard::into_inner(guard); |
351 | | /// } else { |
352 | | /// // guard still exists in this branch |
353 | | /// } |
354 | | /// } |
355 | | /// ``` |
356 | | #[inline] |
357 | | pub fn into_inner(guard: Self) -> T { |
358 | | // Cannot move out of `Drop`-implementing types, |
359 | | // so `ptr::read` the value and forget the guard. |
360 | | let mut guard = ManuallyDrop::new(guard); |
361 | | unsafe { |
362 | | let value = ptr::read(&*guard.value); |
363 | | // Drop the closure after `value` has been read, so that if the |
364 | | // closure's `drop` function panics, unwinding still tries to drop |
365 | | // `value`. |
366 | | ManuallyDrop::drop(&mut guard.dropfn); |
367 | | value |
368 | | } |
369 | | } |
370 | | } |
371 | | |
372 | | /// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. |
373 | | #[inline] |
374 | | #[must_use] |
375 | | pub fn guard<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, Always> |
376 | | where |
377 | | F: FnOnce(T), |
378 | | { |
379 | | ScopeGuard::with_strategy(v, dropfn) |
380 | | } |
381 | | |
382 | | /// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. |
383 | | /// |
384 | | /// Requires crate feature `use_std`. |
385 | | #[cfg(feature = "use_std")] |
386 | | #[inline] |
387 | | #[must_use] |
388 | | pub fn guard_on_success<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, OnSuccess> |
389 | | where |
390 | | F: FnOnce(T), |
391 | | { |
392 | | ScopeGuard::with_strategy(v, dropfn) |
393 | | } |
394 | | |
395 | | /// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. |
396 | | /// |
397 | | /// Requires crate feature `use_std`. |
398 | | /// |
399 | | /// ## Examples |
400 | | /// |
401 | | /// For performance reasons, or to emulate “only run guard on unwind” in |
402 | | /// no-std environments, we can also use the default guard and simply manually |
403 | | /// defuse it at the end of scope like the following example. (The performance |
404 | | /// reason would be if the [`OnUnwind`]'s call to [std::thread::panicking()] is |
405 | | /// an issue.) |
406 | | /// |
407 | | /// ``` |
408 | | /// extern crate scopeguard; |
409 | | /// |
410 | | /// use scopeguard::ScopeGuard; |
411 | | /// # fn main() { |
412 | | /// { |
413 | | /// let guard = scopeguard::guard((), |_| {}); |
414 | | /// |
415 | | /// // rest of the code here |
416 | | /// |
417 | | /// // we reached the end of scope without unwinding - defuse it |
418 | | /// ScopeGuard::into_inner(guard); |
419 | | /// } |
420 | | /// # } |
421 | | /// ``` |
422 | | #[cfg(feature = "use_std")] |
423 | | #[inline] |
424 | | #[must_use] |
425 | | pub fn guard_on_unwind<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, OnUnwind> |
426 | | where |
427 | | F: FnOnce(T), |
428 | | { |
429 | | ScopeGuard::with_strategy(v, dropfn) |
430 | | } |
431 | | |
432 | | // ScopeGuard can be Sync even if F isn't because the closure is |
433 | | // not accessible from references. |
434 | | // The guard does not store any instance of S, so it is also irrelevant. |
435 | | unsafe impl<T, F, S> Sync for ScopeGuard<T, F, S> |
436 | | where |
437 | | T: Sync, |
438 | | F: FnOnce(T), |
439 | | S: Strategy, |
440 | | { |
441 | | } |
442 | | |
443 | | impl<T, F, S> Deref for ScopeGuard<T, F, S> |
444 | | where |
445 | | F: FnOnce(T), |
446 | | S: Strategy, |
447 | | { |
448 | | type Target = T; |
449 | | |
450 | | fn deref(&self) -> &T { |
451 | | &*self.value |
452 | | } |
453 | | } |
454 | | |
455 | | impl<T, F, S> DerefMut for ScopeGuard<T, F, S> |
456 | | where |
457 | | F: FnOnce(T), |
458 | | S: Strategy, |
459 | | { |
460 | | fn deref_mut(&mut self) -> &mut T { |
461 | | &mut *self.value |
462 | | } |
463 | | } |
464 | | |
465 | | impl<T, F, S> Drop for ScopeGuard<T, F, S> |
466 | | where |
467 | | F: FnOnce(T), |
468 | | S: Strategy, |
469 | | { |
470 | | fn drop(&mut self) { |
471 | | // This is OK because the fields are `ManuallyDrop`s |
472 | | // which will not be dropped by the compiler. |
473 | | let (value, dropfn) = unsafe { (ptr::read(&*self.value), ptr::read(&*self.dropfn)) }; |
474 | | if S::should_run() { |
475 | | dropfn(value); |
476 | | } |
477 | | } |
478 | | } |
479 | | |
480 | | impl<T, F, S> fmt::Debug for ScopeGuard<T, F, S> |
481 | | where |
482 | | T: fmt::Debug, |
483 | | F: FnOnce(T), |
484 | | S: Strategy, |
485 | | { |
486 | | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
487 | | f.debug_struct(stringify!(ScopeGuard)) |
488 | | .field("value", &*self.value) |
489 | | .finish() |
490 | | } |
491 | | } |
492 | | |
493 | | #[cfg(test)] |
494 | | mod tests { |
495 | | use super::*; |
496 | | use std::cell::Cell; |
497 | | use std::panic::catch_unwind; |
498 | | use std::panic::AssertUnwindSafe; |
499 | | |
500 | | #[test] |
501 | | fn test_defer() { |
502 | | let drops = Cell::new(0); |
503 | | defer!(drops.set(1000)); |
504 | | assert_eq!(drops.get(), 0); |
505 | | } |
506 | | |
507 | | #[cfg(feature = "use_std")] |
508 | | #[test] |
509 | | fn test_defer_success_1() { |
510 | | let drops = Cell::new(0); |
511 | | { |
512 | | defer_on_success!(drops.set(1)); |
513 | | assert_eq!(drops.get(), 0); |
514 | | } |
515 | | assert_eq!(drops.get(), 1); |
516 | | } |
517 | | |
518 | | #[cfg(feature = "use_std")] |
519 | | #[test] |
520 | | fn test_defer_success_2() { |
521 | | let drops = Cell::new(0); |
522 | | let _ = catch_unwind(AssertUnwindSafe(|| { |
523 | | defer_on_success!(drops.set(1)); |
524 | | panic!("failure") |
525 | | })); |
526 | | assert_eq!(drops.get(), 0); |
527 | | } |
528 | | |
529 | | #[cfg(feature = "use_std")] |
530 | | #[test] |
531 | | fn test_defer_unwind_1() { |
532 | | let drops = Cell::new(0); |
533 | | let _ = catch_unwind(AssertUnwindSafe(|| { |
534 | | defer_on_unwind!(drops.set(1)); |
535 | | assert_eq!(drops.get(), 0); |
536 | | panic!("failure") |
537 | | })); |
538 | | assert_eq!(drops.get(), 1); |
539 | | } |
540 | | |
541 | | #[cfg(feature = "use_std")] |
542 | | #[test] |
543 | | fn test_defer_unwind_2() { |
544 | | let drops = Cell::new(0); |
545 | | { |
546 | | defer_on_unwind!(drops.set(1)); |
547 | | } |
548 | | assert_eq!(drops.get(), 0); |
549 | | } |
550 | | |
551 | | #[test] |
552 | | fn test_only_dropped_by_closure_when_run() { |
553 | | let value_drops = Cell::new(0); |
554 | | let value = guard((), |()| value_drops.set(1 + value_drops.get())); |
555 | | let closure_drops = Cell::new(0); |
556 | | let guard = guard(value, |_| closure_drops.set(1 + closure_drops.get())); |
557 | | assert_eq!(value_drops.get(), 0); |
558 | | assert_eq!(closure_drops.get(), 0); |
559 | | drop(guard); |
560 | | assert_eq!(value_drops.get(), 1); |
561 | | assert_eq!(closure_drops.get(), 1); |
562 | | } |
563 | | |
564 | | #[cfg(feature = "use_std")] |
565 | | #[test] |
566 | | fn test_dropped_once_when_not_run() { |
567 | | let value_drops = Cell::new(0); |
568 | | let value = guard((), |()| value_drops.set(1 + value_drops.get())); |
569 | | let captured_drops = Cell::new(0); |
570 | | let captured = guard((), |()| captured_drops.set(1 + captured_drops.get())); |
571 | | let closure_drops = Cell::new(0); |
572 | | let guard = guard_on_unwind(value, |value| { |
573 | | drop(value); |
574 | | drop(captured); |
575 | | closure_drops.set(1 + closure_drops.get()) |
576 | | }); |
577 | | assert_eq!(value_drops.get(), 0); |
578 | | assert_eq!(captured_drops.get(), 0); |
579 | | assert_eq!(closure_drops.get(), 0); |
580 | | drop(guard); |
581 | | assert_eq!(value_drops.get(), 1); |
582 | | assert_eq!(captured_drops.get(), 1); |
583 | | assert_eq!(closure_drops.get(), 0); |
584 | | } |
585 | | |
586 | | #[test] |
587 | | fn test_into_inner() { |
588 | | let dropped = Cell::new(false); |
589 | | let value = guard(42, |_| dropped.set(true)); |
590 | | let guard = guard(value, |_| dropped.set(true)); |
591 | | let inner = ScopeGuard::into_inner(guard); |
592 | | assert_eq!(dropped.get(), false); |
593 | | assert_eq!(*inner, 42); |
594 | | } |
595 | | } |