dispose/abort.rs
1#![allow(clippy::module_name_repetitions)]
2
3use std::process::abort;
4
5use crate::{Disposable, Dispose};
6
7/// Abort the process if this value is dropped.
8///
9/// This struct is for bypassing an unwinding panic should something go horribly
10/// wrong in an application. It is the heart of [`abort_on_panic`], and for
11/// most cases does not need to be used directly.
12///
13/// [`abort_on_panic`]: ./function.abort_on_panic.html
14#[derive(Debug)]
15#[allow(missing_copy_implementations)] // Construction is trivial, copying would be dangerous
16pub struct AbortCanary(());
17
18impl AbortCanary {
19 /// Construct a new canary.
20 ///
21 /// # Panics
22 /// The value produced by this function must be passed to [`release`] in
23 /// order to avoid aborting the process.
24 ///
25 /// [`release`]: ./struct.AbortCanary.html#method.release
26 #[must_use = "Dropping this value immediately will abort the process."]
27 pub fn new() -> Disposable<Self> { Disposable::new(Self(())) }
28
29 /// Release `canary`. This will consume and drop it without aborting the
30 /// process.
31 pub fn release(canary: Disposable<Self>) { unsafe { Disposable::leak(canary) }; }
32}
33
34impl Dispose for AbortCanary {
35 fn dispose(self) { abort(); }
36}
37
38/// Abort the process if the provided closure panics.
39///
40/// This function internally constructs an [`AbortCanary`] and releases it after
41/// running `f`.
42///
43/// # Example
44/// The following panic will result in the process aborting:
45///
46/// ```should_panic
47/// # use dispose::abort_on_panic;
48/// abort_on_panic(|| panic!("oops!"));
49/// ```
50///
51/// [`AbortCanary`]: ./struct.AbortCanary.html
52pub fn abort_on_panic<T>(f: impl FnOnce() -> T) -> T {
53 let canary = AbortCanary::new();
54
55 let ret = f();
56
57 AbortCanary::release(canary);
58
59 ret
60}
61
62#[cfg(test)]
63mod test {
64 use std::panic::catch_unwind;
65
66 use super::*;
67
68 #[test]
69 fn safe_canary() {
70 let canary = AbortCanary::new();
71 AbortCanary::release(canary);
72 }
73
74 // TODO: how to test abort???
75 // I have confirmed that uncommenting the commented tests does result
76 // in the test process aborting, but currently the test runner can't
77 // deal with that properly.
78
79 // #[test]
80 // #[should_panic]
81 // fn bad_canary() { let _canary = AbortCanary::new(); }
82
83 #[test]
84 fn safe_aop() { abort_on_panic(|| ()); }
85
86 // This should NOT panic
87 #[test]
88 fn sanity_check_aop() { catch_unwind(|| panic!()).ok(); }
89
90 // // This should panic
91 // #[test]
92 // #[should_panic]
93 // fn bad_aop() { catch_unwind(|| abort_on_panic(|| panic!())).ok(); }
94}