nya-core 0.2.0

nya core library
Documentation
//! Defer macro

/// A type that calls a function when dropped
///
/// This is like the `defer` keyword found in some languages.
///
/// # Examples
///
/// ```
/// use nya_core::{defer, defer::{Defer}};
///
/// let _d1 = defer!(|| println!("Hello!"));
/// let _d2 = defer!(|| println!("Defer order works, unless manually drop()'d"));
///
/// println!("This will print before the deferred code!");
/// ```
pub struct Defer<F: FnOnce()> {
    callback: core::mem::ManuallyDrop<F>,
}

impl<F: FnOnce()> Defer<F> {
    /// Construct a [Defer]
    ///
    /// The return value must be stored in a temporary variable so the deferred function will run at
    /// the correct time.
    #[must_use = "Defers won't run unless assigned to a variable"]
    pub const fn new(f: F) -> Self {
        Self {
            callback: core::mem::ManuallyDrop::new(f),
        }
    }
}

impl<F: FnOnce()> Drop for Defer<F> {
    fn drop(&mut self) {
        // SAFETY: this is implemented in `Drop` so it doesn't matter
        unsafe {
            core::mem::ManuallyDrop::take(&mut self.callback)();
        }
    }
}

/// Shorthand for [Defer::new]
///
/// See [Defer] for more information.
#[macro_export]
macro_rules! defer {
    ($body:block) => {
        $crate::defer::Defer::new(|| $body)
    };

    ($func:expr) => {
        $crate::defer::Defer::new($func)
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn defer_test() {
        let _d1 = defer!({ println!("This is defered") });
        let _d2 = defer!(|| println!("Goodbye"));

        fn funcptr() {
            println!("Callback from a function pointer");
        }
        let _d3 = defer!(funcptr);

        println!("Hey!");
    }
}