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}