1#[must_use]
26pub struct DeferGuard<F: FnOnce()>(pub Option<F>);
27
28impl<F: FnOnce()> DeferGuard<F> {
29 pub fn new(f: F) -> Self {
31 Self(Some(f))
32 }
33}
34
35impl<F: FnOnce()> Drop for DeferGuard<F> {
36 fn drop(&mut self) {
37 self.0.take().map(|f| f());
38 }
39}
40
41#[macro_export]
63macro_rules! defer(
64 ( $( $code:tt )* ) => {
65 let _guard = $crate::defer::DeferGuard(Some(|| { $( $code )* }));
66 };
67);
68
69#[cfg(test)]
70mod test {
71 #[test]
72 fn defer_guard_works() {
73 let mut called = false;
74 {
75 defer!(
76 called = true;
77 );
78 }
79 assert!(called, "DeferGuard should have executed the closure");
80 }
81
82 #[test]
83 fn defer_guard_order_works() {
85 let called = std::cell::RefCell::new(1);
86
87 defer!(
88 assert_eq!(*called.borrow(), 3);
89 );
90 defer!(
91 assert_eq!(*called.borrow(), 2);
92 *called.borrow_mut() = 3;
93 );
94 defer!({
95 assert_eq!(*called.borrow(), 1);
96 *called.borrow_mut() = 2;
97 });
98 }
99
100 #[test]
101 #[allow(unused_braces)]
102 #[allow(clippy::unnecessary_operation)]
103 fn defer_guard_syntax_works() {
104 let called = std::cell::RefCell::new(0);
105 {
106 defer!(*called.borrow_mut() += 1);
107 defer!(*called.borrow_mut() += 1;); defer!({ *called.borrow_mut() += 1 });
109 defer!({ *called.borrow_mut() += 1 };); }
111 assert_eq!(*called.borrow(), 4);
112 }
113
114 #[test]
115 fn defer_guard_panic_unwind_works() {
117 use std::panic::{catch_unwind, AssertUnwindSafe};
118 let mut called = false;
119
120 let should_panic = catch_unwind(AssertUnwindSafe(|| {
121 defer!(called = true);
122 panic!();
123 }));
124
125 assert!(should_panic.is_err(), "DeferGuard should have panicked");
126 assert!(called, "DeferGuard should have executed the closure");
127 }
128
129 #[test]
130 fn defer_guard_defer_panics_unwind_works() {
132 use std::panic::{catch_unwind, AssertUnwindSafe};
133 let counter = std::cell::RefCell::new(0);
134
135 let should_panic = catch_unwind(AssertUnwindSafe(|| {
136 defer!(*counter.borrow_mut() += 1);
137 defer!(
138 *counter.borrow_mut() += 1;
139 panic!();
140 );
141 defer!(*counter.borrow_mut() += 1);
142 }));
143
144 assert!(should_panic.is_err(), "DeferGuard should have panicked");
145 assert_eq!(*counter.borrow(), 3, "DeferGuard should have executed the closure");
146 }
147}