scope_exit/
lib.rs

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    // modify local variable
45
46    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            // The first scope_exit also called by RAII, won't be triggered
70            // by the definition of the second scope_exit.
71        }
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            // The first scope_exit also called by RAII, won't be triggered
87            // by the definition of the second scope_exit.
88        }
89        assert_eq!(i, 1);
90        assert_eq!(j, 2);
91    }
92}