kernel/library/std/
defer.rs

1//! # Defer Module
2//!
3//! This module provides a mechanism to execute a function when the current scope is exited,
4//! similar to Go's `defer` statement or C++'s RAII pattern.
5//!
6//! The defer mechanism ensures that cleanup code is executed regardless of how a scope is exited,
7//! whether through normal control flow, early returns, or error propagation.
8//!
9//! ## Usage
10//!
11//! The module provides two ways to defer execution:
12//!
13//! 1. The `defer` function, which takes a closure and returns an object that executes 
14//!    the closure when dropped:
15//!
16//! ```
17//! let mut resource = acquire_resource();
18//! let _defer = defer(|| {
19//!     release_resource(&mut resource);
20//! });
21//!
22//! // Work with resource...
23//! // When scope ends, the defer will automatically release the resource
24//! ```
25//!
26//! 2. The `defer!` macro, which offers a more concise syntax:
27//!
28//! ```
29//! let mut resource = acquire_resource();
30//! defer! {
31//!     release_resource(&mut resource);
32//! }
33//!
34//! // Work with resource...
35//! // Resource will be released when scope ends
36//! ```
37//!
38//! ## Features
39//!
40//! - Executes deferred functions in reverse order of declaration (LIFO)
41//! - Works with early returns and panics
42//! - Helps prevent resource leaks
43//! - Simplifies cleanup logic
44//!
45//! ## Implementation Details
46//!
47//! The implementation uses Rust's RAII (Resource Acquisition Is Initialization) pattern
48//! through the `Drop` trait to ensure the deferred function is called when the returned
49//! object goes out of scope.
50//! Defer module.
51//! 
52//! This module provides a mechanism to execute a function when the current scope is exited.
53
54/// Defer a function to be executed when the current scope is exited.
55/// This function takes a closure and returns an object that will execute the closure
56/// when it is dropped.
57/// This is useful for cleanup tasks, such as releasing resources or performing
58/// finalization steps.
59///
60/// # Examples
61/// ```
62/// let mut resource = acquire_resource();
63/// let _defer = defer(|| {
64///     release_resource(&mut resource);
65/// });
66///
67#[must_use]
68#[inline]
69pub fn defer<F>(f: F) -> impl Drop
70where 
71    F: FnOnce(),
72{
73    struct Defer<F: FnOnce()> {
74        f: Option<F>,
75    }
76
77    impl<F: FnOnce()> Defer<F> {
78        fn new(f: F) -> Self {
79            Defer { f: Some(f) }
80        }
81    }
82    
83    impl<F: FnOnce()> Drop for Defer<F> {
84        fn drop(&mut self) {
85            if let Some(f) = self.f.take() {
86                f();
87            }
88        }
89    }
90    
91    Defer::new(f)
92}
93
94/// Macro to defer execution of a block of code.
95/// This macro allows you to specify a block of code that will be executed when the
96/// current scope is exited.
97/// It is similar to the `defer` function but provides a more concise syntax.
98///
99#[macro_export]
100macro_rules! defer {
101    ($($data: tt)*) => (
102        let _defer = $crate::library::std::defer::defer(|| {
103            $($data)*
104        });
105    )
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test_case]
113    fn test_simple_defer() {
114        let mut called = false;
115        {
116            let _defer = defer(|| {
117                called = true;
118            });
119        }
120        assert!(called, "Defer function was not called");
121    }
122
123    #[test_case]
124    fn test_multiple_defer() {
125        let mut called1 = false;
126        let mut called2 = false;
127        {
128            let _defer1 = defer(|| {
129                called1 = true;
130            });
131            let _defer2 = defer(|| {
132                called2 = true;
133            });
134        }
135        assert!(called1, "First defer function was not called");
136        assert!(called2, "Second defer function was not called");
137    }
138
139    #[test_case]
140    fn test_defer_with_return() {
141        let mut called = false;
142        {
143            let _defer = defer(|| {
144                called = true;
145            });
146        }
147        assert!(called, "Defer function was not called");
148    }
149
150    #[test_case]
151    fn test_defer_with_error() {
152        fn might_fail(called: &mut bool) -> Result<(), &'static str> {
153            *called = false;
154
155            let _defer = defer(|| {
156                *called = true;
157            });
158
159            Err("Error occurred")
160        }
161
162        let mut called = false;
163        let result = might_fail(&mut called);
164        assert!(result.is_err(), "Expected an error");
165        assert!(called, "Defer function was not called");
166    }
167
168    #[test_case]
169    fn test_defer_macro() {
170        let mut called = false;
171        {
172            defer!{
173                called = true;
174            }
175        }
176        assert!(called, "Defer macro function was not called");
177    }
178}