Skip to main content

xtk_core/
defer.rs

1//! Defer macro
2
3/// A type that calls a function when dropped
4///
5/// This is like the `defer` keyword found in some languages.
6///
7/// # Examples
8///
9/// ```
10/// use xtk_core::{defer, defer::{Defer}};
11///
12/// let _d1 = defer!(|| println!("Hello!"));
13/// let _d2 = defer!(|| println!("Defer order works, unless manually drop()'d"));
14///
15/// println!("This will print before the deferred code!");
16/// ```
17pub struct Defer<F: FnOnce()> {
18    callback: core::mem::ManuallyDrop<F>,
19}
20
21impl<F: FnOnce()> Defer<F> {
22    /// Construct a [Defer]
23    ///
24    /// The return value must be stored in a temporary variable so the deferred function will run at
25    /// the correct time.
26    #[must_use = "Defers won't run unless assigned to a variable"]
27    pub const fn new(f: F) -> Self {
28        Self {
29            callback: core::mem::ManuallyDrop::new(f),
30        }
31    }
32}
33
34impl<F: FnOnce()> Drop for Defer<F> {
35    fn drop(&mut self) {
36        // SAFETY: this is implemented in `Drop` so it doesn't matter
37        unsafe {
38            core::mem::ManuallyDrop::take(&mut self.callback)();
39        }
40    }
41}
42
43/// Shorthand for [Defer::new]
44///
45/// See [Defer] for more information.
46#[macro_export]
47macro_rules! defer {
48    ($body:block) => {
49        $crate::defer::Defer::new(|| $body)
50    };
51
52    ($func:expr) => {
53        $crate::defer::Defer::new($func)
54    };
55}
56
57#[cfg(test)]
58mod tests {
59    #[test]
60    fn defer_test() {
61        let _d1 = defer!({ println!("This is defered") });
62        let _d2 = defer!(|| println!("Goodbye"));
63
64        fn funcptr() {
65            println!("Callback from a function pointer");
66        }
67        let _d3 = defer!(funcptr);
68
69        println!("Hey!");
70    }
71}