Skip to content

Commit fdb5c04

Browse files
committed
rust: Add ScopeGuard to optionally run cleanup closures.
Signed-off-by: Wedson Almeida Filho <[email protected]>
1 parent 7884043 commit fdb5c04

File tree

2 files changed

+64
-1
lines changed

2 files changed

+64
-1
lines changed

rust/kernel/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ pub mod user_ptr;
7777
pub use build_error::build_error;
7878

7979
pub use crate::error::{Error, Result};
80-
pub use crate::types::Mode;
80+
pub use crate::types::{Mode, ScopeGuard};
8181

8282
/// Page size defined in terms of the `PAGE_SHIFT` macro from C.
8383
///

rust/kernel/types.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,66 @@ impl<T: PointerWrapper + Deref> PointerWrapper for Pin<T> {
9191
Pin::new_unchecked(T::from_pointer(p))
9292
}
9393
}
94+
95+
/// Runs a cleanup function/closure when dropped.
96+
///
97+
/// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running.
98+
///
99+
/// # Examples
100+
///
101+
/// In the example below, we have multiple exit paths and we want to log regardless of which one is
102+
/// taken:
103+
/// ```
104+
/// fn example1(arg: bool) {
105+
/// let _log = ScopeGuard::new(|| pr_info!("example1 completed\n"));
106+
///
107+
/// if arg {
108+
/// return;
109+
/// }
110+
///
111+
/// // Do something...
112+
/// }
113+
/// ```
114+
///
115+
/// In the example below, we want to log the same message on all early exits but a different one on
116+
/// the main exit path:
117+
/// ```
118+
/// fn example2(arg: bool) {
119+
/// let log = ScopeGuard::new(|| pr_info!("example2 returned early\n"));
120+
///
121+
/// if arg {
122+
/// return;
123+
/// }
124+
///
125+
/// // (Other early returns...)
126+
///
127+
/// log.dismiss();
128+
/// pr_info!("example2 no early return\n");
129+
/// }
130+
/// ```
131+
pub struct ScopeGuard<T: FnOnce()> {
132+
cleanup_func: Option<T>,
133+
}
134+
135+
impl<T: FnOnce()> ScopeGuard<T> {
136+
/// Creates a new cleanup object with the given cleanup function.
137+
pub fn new(cleanup_func: T) -> Self {
138+
Self {
139+
cleanup_func: Some(cleanup_func),
140+
}
141+
}
142+
143+
/// Prevents the cleanup function from running.
144+
pub fn dismiss(mut self) {
145+
self.cleanup_func.take();
146+
}
147+
}
148+
149+
impl<T: FnOnce()> Drop for ScopeGuard<T> {
150+
fn drop(&mut self) {
151+
// Run the cleanup function if one is still present.
152+
if let Some(cleanup) = self.cleanup_func.take() {
153+
cleanup();
154+
}
155+
}
156+
}

0 commit comments

Comments
 (0)