1use std::ops::Drop;
2
3struct ScopeExit<'a> {
4 call_: Box<dyn FnMut() + 'a>,
5}
6
7impl<'a> ScopeExit<'a> {
8 pub fn new<F>(call: F) -> Self
9 where
10 F: FnMut() + 'a,
11 {
12 ScopeExit {
13 call_: Box::<F>::new(call),
14 }
15 }
16}
17
18impl<'a> Drop for ScopeExit<'a> {
19 fn drop(&mut self) {
20 (self.call_)()
21 }
22}
23
24macro_rules! scope_exit {
25 ($call: block) => {
26 let _scope_exit = ScopeExit::new(|| $call);
27 };
28 ($call: stmt) => {
29 let _scope_exit = ScopeExit::new(|| $call);
30 };
31}
32
33macro_rules! defer {
34 ($call: block) => {
35 let _scope_exit = ScopeExit::new(|| $call);
36 };
37 ($call: stmt) => {
38 let _scope_exit = ScopeExit::new(|| $call);
39 };
40}
41
42#[cfg(test)]
43mod test {
44 use crate::ScopeExit;
47 #[test]
48 fn modify_local_variable_test() {
49 let mut i = 0;
50 {
51 let call = || {
52 i = 2;
53 };
54 let _scope_exit = ScopeExit::new(Box::new(call));
55 }
56 assert_eq!(i, 2);
57 }
58
59 #[test]
60 fn modify_local_variable_by_macro_test() {
61 let mut i = 0;
62 let mut j = 0;
63 {
64 scope_exit!({
65 i = 1;
66 });
67
68 scope_exit!(j = 2);
69 }
72 assert_eq!(i, 1);
73 assert_eq!(j, 2);
74 }
75
76 #[test]
77 fn modify_local_variable_by_macro_defer_test() {
78 let mut i = 0;
79 let mut j = 0;
80 {
81 defer!({
82 i = 1;
83 });
84
85 defer!(j = 2);
86 }
89 assert_eq!(i, 1);
90 assert_eq!(j, 2);
91 }
92}