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}