1#[macro_export]
2macro_rules! drop_panic {
3 ($($t:tt)*) => {
4 let _drop_panic = $crate::guard(|| { $($t)* });
5 };
6}
7
8pub fn guard<F>(f: F) -> DropPanic<F>
9where
10 F: Fn(),
11{
12 DropPanic::new(f)
13}
14
15pub struct DropPanic<F>(F)
17where
18 F: Fn();
19
20impl<F> DropPanic<F>
21where
22 F: Fn(),
23{
24 pub fn new(panic_fn: F) -> Self {
25 Self(panic_fn)
26 }
27}
28
29impl<F> Drop for DropPanic<F>
30where
31 F: Fn(),
32{
33 fn drop(&mut self) {
34 if std::thread::panicking() {
35 (self.0)();
36 }
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use crate::drop_panic;
43 use std::{
44 sync::{
45 atomic::{AtomicBool, Ordering},
46 Arc,
47 },
48 thread,
49 };
50
51 #[test]
52 fn test_drop_panic() {
53 let panicked = Arc::new(AtomicBool::new(false));
54
55 let jh = thread::spawn({
56 let panicked = Arc::clone(&panicked);
57 move || {
58 drop_panic! {
59 panicked.store(true, Ordering::Release);
60 };
61
62 panic!("boom");
63 }
64 });
65
66 assert!(jh.join().is_err());
67 assert!(panicked.load(Ordering::Acquire));
68 }
69}