defer_rs/lib.rs
1#![doc = include_str!("../README.md")]
2
3// This `extern` is to facilitate easier crate resolution in tests for the proc generated code
4extern crate self as defer_rs;
5
6#[cfg(not(doc))]
7pub use defer_rs_impl::{defer_scope, defer_scope_init};
8
9/// A utility struct for deferred execution of a closure.
10///
11/// The `Defer` struct allows you to execute a closure once the `Defer` instance goes out of scope.
12/// It is commonly used for resource management, cleanup, or any other deferred actions.
13///
14/// **Note: `Defer` MUST be bound to a variable to function properly; otherwise, it will be dropped immediately, executing the enclosed closure!**
15///
16/// # Example
17///
18/// ```
19/// use defer_rs::*;
20///
21/// # fn acquire_resource(){}
22/// # fn release_resource(_: ()){}
23///
24/// fn main() {
25/// let resource = acquire_resource();
26///
27/// // Create a `Defer` instance with a closure that will be executed when it goes out of scope.
28/// let cleanup = Defer::new(|| {
29/// release_resource(resource);
30/// });
31///
32/// // ... do some work ...
33///
34/// // The closure will be executed automatically when `cleanup` goes out of scope.
35/// }
36/// ```
37///
38/// See also: [`defer!`], and [`DeferGroup`].
39#[must_use = "Defer MUST be bound to a variable to function properly; otherwise, it will be dropped immediately, executing the enclosed closure!"]
40pub struct Defer<T: FnOnce()>(Option<T>);
41
42impl<T: FnOnce()> Defer<T> {
43 /// Creates a new `Defer` instance with the given deferred closure.
44 ///
45 /// The closure will be executed when the `Defer` instance goes out of scope.
46 ///
47 /// **Note: `Defer` MUST be bound to a variable to function properly; otherwise, it will be dropped immediately, executing the enclosed closure!**
48 ///
49 /// # Example
50 ///
51 /// ```rust
52 /// use defer_rs::Defer;
53 ///
54 /// let defer_instance = Defer::new(|| {
55 /// println!("Deferred action executed!");
56 /// });
57 ///
58 /// // ... other code ...
59 ///
60 /// // The deferred action will be executed when `defer_instance` goes out of scope.
61 /// ```
62 pub fn new(deferred: T) -> Self {
63 Self(Some(deferred))
64 }
65}
66
67impl<T: FnOnce()> Drop for Defer<T> {
68 fn drop(&mut self) {
69 // This is safe, as there is no way to have a `Defer` struct containing a `None` value
70 unsafe { (self.0.take().unwrap_unchecked())() }
71 }
72}
73
74/// A utility struct for explicitly scoped deferred execution of closures.
75///
76/// The `DeferGroup` allows you to add closures (functions) that will be executed
77/// when the `DeferGroup` instance goes out of scope. It is particularly useful
78/// for resource cleanup or deferred actions.
79///
80/// **Note: `DeferGroup` MUST be bound to a variable to function properly; otherwise, it will be dropped immediately, executing the enclosed closures!**
81///
82/// # Example
83///
84/// ```rust
85/// use defer_rs::DeferGroup;
86///
87/// let mut defer_group = DeferGroup::new();
88///
89/// // Add a function to be executed when `defer_group` goes out of scope
90/// defer_group.add(Box::new(|| {
91/// println!("Deferred action: Cleaning up resources...");
92/// }));
93///
94/// // Some other code...
95///
96/// // The deferred (queued) actions will be executed here, when the `defer_group` is dropped.
97/// ```
98///
99/// See also: [`defer_scope!`], [`defer_scope_init!`], [`Defer`], and [`defer!`].
100#[must_use = "DeferGroup MUST be bound to a variable to function properly; otherwise, it will be dropped immediately, executing the enclosed closure!"]
101pub struct DeferGroup<'a>(Vec<Option<Box<dyn FnOnce() + 'a>>>);
102
103impl<'a> DeferGroup<'a> {
104 /// Creates a new `DeferGroup`.
105 ///
106 /// **Note: `DeferGroup` MUST be bound to a variable to function properly; otherwise, it will be dropped immediately, executing the enclosed closures!**
107 ///
108 /// # Example
109 ///
110 /// ```
111 /// use defer_rs::DeferGroup;
112 ///
113 /// let mut defer_group = DeferGroup::new();
114 /// // Add deferred actions...
115 /// ```
116 pub fn new() -> Self {
117 Self(Vec::new())
118 }
119
120 /// Adds a deferred closure to the start (0-index) of the `DeferGroup` queue.
121 ///
122 /// The closures queued in `DeferGroup` will be executed first to last
123 /// when the the `DeferGroup` instance goes out of scope.
124 ///
125 /// # Example
126 ///
127 /// ```
128 /// use defer_rs::DeferGroup;
129 ///
130 /// let mut defer_group = DeferGroup::new();
131 /// {
132 /// defer_group.add(Box::new(|| {
133 /// println!("This will be printed 2nd");
134 /// }));
135 /// defer_group.add(Box::new(|| {
136 /// println!("This will be printed 1st");
137 /// }));
138 /// }
139 /// ```
140 pub fn add(&mut self, f: Box<dyn FnOnce() + 'a>) {
141 self.0.insert(0, Some(f));
142 }
143
144 /// Pushes a deferred closure to the end of the `DeferGroup` queue.
145 ///
146 /// The closures queued in `DeferGroup` will be executed first to last
147 /// when the the `DeferGroup` instance goes out of scope.
148 ///
149 /// # Example
150 ///
151 /// ```
152 /// use defer_rs::DeferGroup;
153 ///
154 /// let mut defer_group = DeferGroup::new();
155 /// {
156 /// defer_group.push(Box::new(|| {
157 /// println!("This will be printed 1st");
158 /// }));
159 /// defer_group.push(Box::new(|| {
160 /// println!("This will be printed 2nd");
161 /// }));
162 /// }
163 /// ```
164 pub fn push(&mut self, f: Box<dyn FnOnce() + 'a>) {
165 self.0.push(Some(f));
166 }
167}
168
169impl<'a> Drop for DeferGroup<'a> {
170 fn drop(self: &mut DeferGroup<'a>) {
171 for deferred in &mut self.0 {
172 unsafe { deferred.take().unwrap_unchecked()() };
173 }
174 }
175}
176
177/// A macro for deferring execution of code until the current scope exits.
178///
179/// The `defer!` macro allows you to specify code that should be executed when the current
180/// scope (such as a function or block) is exited, regardless of whether the exit occurs normally
181/// or due to an early return, panic, or other unwinding.
182///
183/// # Examples
184///
185/// ## Basic usage:
186///
187/// ```rust
188/// use defer_rs::defer;
189/// defer! {
190/// println!("This will be executed when the current scope exits.");
191/// }
192/// ```
193/// ### Expands to:
194/// ```rust
195/// let ___deferred_code = ::defer_rs::Defer::new( || {
196/// println!("This will be executed when the current scope exits.");
197/// });
198/// ```
199///
200/// ## Multiple statements:
201/// Multiple statements also work (enclosed in a block or not).
202///
203/// ```rust
204/// use defer_rs::defer;
205/// defer! {
206/// println!("1st statement.");
207/// println!("2nd statement.");
208/// }
209/// ```
210/// ### Expands to:
211///
212/// ```rust
213/// let ___deferred_code = ::defer_rs::Defer::new( || {
214/// println!("1st statement.");
215/// println!("2nd statement.");
216/// });
217/// ```
218///
219/// ## Move capturred values:
220/// Sometimes it's necessary to `move` the values capturred from the environment into the generated closure,
221/// in this case `move` can be added before the deferred statements and it will be added to the closure.
222///
223/// ```rust
224/// use defer_rs::defer;
225/// let val = "Variable that must be passed by value!";
226/// defer!( move {
227/// println!("`val` is captured by value!");
228/// println!("{}", val);
229/// });
230/// ```
231/// ### Expands to:
232///
233/// ```rust
234/// let val = "Variable that must be passed by value!";
235/// let ___deferred_code = ::defer_rs::Defer::new( move || {
236/// println!("`val` is captured by value!");
237/// println!("{}", val);
238/// });
239/// ```
240///
241/// ## Immmediately evaluating passed arguments:
242/// A common pattern in languages with a `defer` keyword (i.e., `Go`),
243/// is to defer a single function/method call,
244/// in that case, arguments passed to the call are usually evaluated immediately,
245/// this can be mimicked using the `defer!` macro on a single call expression,
246/// This behavior can easily be disabled by postfixing the call expression.
247///
248/// Note: `move` cannot be used when the macro is used this way,
249/// as it's implied.
250///
251/// ```rust
252/// use defer_rs::defer;
253/// use std::cell::Cell;
254///
255/// fn print(to_print: String) {
256/// println!("{to_print}");
257/// }
258///
259/// let x = Cell::new(0);
260/// // This will evaluate the arguments passed to the invoked at function at time of macro invocation (now), results in `0`
261/// defer!(print(format!("Var x now is: {}", x.get())));
262/// // This will evaluate the arguments passed to the invoked at function at call time (deferred-to time, later), results in `3`
263/// defer!(print(format!("Var x later is: {}", x.get())););
264/// x.set(3);
265/// ```
266/// ### Expands to:
267///
268/// ```rust
269/// use std::cell::Cell;
270///
271/// fn print(to_print: String) {
272/// println!("{to_print}");
273/// }
274///
275/// let x = Cell::new(0);
276/// let ___deferred_code_captured_args = (format!("Var x now is: {}", x.get()), );
277/// let ___deferred_code = ::defer_rs::Defer::new( move || {
278/// print(___deferred_code_captured_args.0);
279/// });
280/// let ___deferred_code = ::defer_rs::Defer::new(|| {
281/// print(format!("Var x later is: {}", x.get()))
282/// });
283/// x.set(3);
284/// ```
285///
286/// See also: [`Defer`], [`DeferGroup`], and [`defer_scope!`].
287#[macro_export]
288macro_rules! defer{
289 // This pattern doesn't match the code directly (unless the input is a block statement), but takes the results from the last two patterns!
290 ($(@$move_kw:ident@)? $body:block$(;)?) => {
291 let ___deferred_code =$crate::Defer::new($($move_kw)?||
292 $body
293 );
294 };
295
296 // This either matches immediately or doesn't at all!
297 ($func:ident($($arg:expr),* $(,)? )) => {
298 let ___deferred_code_captured_args = ( $( $arg, )* );
299 let ___deferred_code =$crate::Defer::new(move|| {
300 ::defer_rs_impl::call_indexed!($func($($arg),*));
301 });
302 };
303
304 // The following two patterns are only here to surround the input in a block statement and to filter the `move` keyword
305 // and pass it back (if it exists) recursively to the the first case to handle the actual code generation
306 (move $($body:tt)+ ) => {
307 defer!(@move@ {$($body)*})
308 };
309
310 ($($body:tt)+ ) => {
311 defer!({$($body)*})
312 };
313}
314
315/// A macro for deferring execution of code until the closest scope containing a previously invoked [`defer_scope_init!`] macro ends.
316///
317/// Use `defer_scope!` when you want to defer execution not to the end of the current active scope, but to the end of a larger parent scope.
318/// The specific parent scope is determined by invoking `defer_scope_init!`.
319///
320/// **Important Notes**:
321/// - The [`defer_scope_init!`] macro **must** be invoked before using `defer_scope!`, and both macros must share a scope.
322/// - You can invoke the `defer_scope!` macro multiple times for a given `defer_scope_init!` invocation.
323///
324/// # Examples
325///
326/// ## Basic usage:
327///
328/// ```rust
329/// use defer_rs::{defer_scope, defer_scope_init};
330///
331/// defer_scope_init!();
332/// defer_scope! {
333/// println!("This will be executed when `defer_scope_init!()`'s scope exits.");
334/// }
335/// ```
336/// ### Expands to:
337/// ```rust
338/// let mut ___deferred_code_group = ::defer_rs::DeferGroup::new();
339/// ___deferred_code_group.add(Box::new(( || {
340/// println!("This will be executed when `defer_scope_init!()`'s scope exits.");
341/// })));
342/// ```
343///
344/// Ignoring the ability to specify the scope and the need for invoking `defer_scope_init!` beforehand,
345/// `defer_scope!` is otherwise identical to [`defer!`].
346///
347/// For more usage examples, refer to the documentation for the [`defer!`] macro,
348/// simply replace `defer!` with `defer_scope!` and add an invocation of [`defer_scope_init!`] beforehand.
349///
350/// See also: [`DeferGroup`], [`defer_scope_init!`], and [`defer!`].
351#[cfg(doc)]
352#[macro_export]
353macro_rules! defer_scope { ($($tt:tt)*) => { ... } }
354
355/// Initializes a [DeferGroup], which is an empty collection of closures to run at the end of the scope containing the invocation.
356/// It provides no functionality by itself and should be called before any [defer_scope!] invocation(s).
357///
358/// No arguments should be passed to the macro invocation.
359///
360/// # Usage
361///
362/// ```rust
363/// defer_rs::defer_scope_init!();
364/// ```
365/// ## Expands to:
366/// ```rust
367/// let mut ___deferred_code_group = ::defer_rs::DeferGroup::new();
368/// ```
369///
370/// For more detailed examples, refer to the documentation for [defer_scope!].
371///
372/// See also: [`DeferGroup`], [`defer_scope!`], and [`defer!`].
373#[cfg(doc)]
374#[macro_export]
375macro_rules! defer_scope_init { () => { ... } }
376
377#[cfg(test)]
378#[allow(unused)]
379mod tests {
380 // use super::*;
381 use super::{defer, defer_scope, defer_scope_init, Defer, DeferGroup};
382 use std::cell::{Cell, RefCell};
383
384 use std::io::Write;
385
386 fn print(to_print: String) {
387 println!("{to_print}");
388 }
389
390 fn add_to_buffer(to_add: String, buff: &RefCell<Vec<u8>>) {
391 writeln!(buff.borrow_mut(), "{to_add}");
392 }
393
394 #[test]
395 fn test_execution_order() {
396 let buff = RefCell::new(Vec::new());
397 let val = Cell::new(0);
398
399 {
400 defer_scope_init!();
401 {
402 // This to ensure that the deferred statments are executed in the correct order
403 defer_scope!({
404 let res = b"This will be printed 1st, x is: 1\nThis will be printed 2nd\nThis will be printed 3rd\nThis will be printed 4th\nThis will be printed 5th\nThis will be printed 6th\nThis will be printed 7th\nThis will be printed 8th, x is: 3\nThis will be printed 9th\nThis will be printed 10th, x is: 0\nThis will be printed 11th\nThis will be printed 12th\nThis will be printed 13th/last\n";
405 assert_eq!(*buff.borrow(), res.to_vec());
406 });
407 // The macro deferrs execution of the code passed to it to the end of the scope of the nearest DeferGroup going up
408 defer_scope!(
409 writeln!(buff.borrow_mut(), "This will be printed 13th/last");
410 );
411
412 defer_scope!(
413 writeln!(buff.borrow_mut(), "This will be printed 12th");
414 );
415
416 {
417 let val = Cell::new(1);
418 // Define a new DeferGroup
419 defer_scope_init!();
420
421 // This will evaluate the arguments passed to the invoked at function at time of macro invocation (now), results in `0`
422 // Using `defer!` here instead of `defer_scope!` will result in identical behavior!
423 defer_scope!(add_to_buffer(
424 format!("This will be printed 1st, x is: {}", val.get()),
425 &buff
426 ));
427 val.set(3);
428 }
429
430 // `defer!` will delay the execution of code passed to it until the end of it's containg scope!
431 defer! {
432 writeln!(buff.borrow_mut(), "This will be printed 3rd");
433 writeln!(buff.borrow_mut(), "This will be printed 4th");
434 };
435
436 defer_scope! {
437 writeln!(buff.borrow_mut(), "This will be printed 11th");
438 };
439
440 defer! {
441 writeln!(buff.borrow_mut(), "This will be printed 2nd");
442 };
443 }
444 writeln!(buff.borrow_mut(), "This will be printed 5th");
445
446 // This will evaluate the arguments passed to the invoked at function at time of macro invocation (now), results in `0`
447 defer_scope!(add_to_buffer(
448 format!("This will be printed 10th, x is: {}", val.get()),
449 &buff
450 ));
451
452 // This will evaluate the arguments passed to the invoked at function at call time (deferred-to time, later), results in `3`
453 defer!({
454 add_to_buffer(
455 format!("This will be printed 8th, x is: {}", val.get()),
456 &buff,
457 )
458 });
459 val.set(3);
460
461 defer_scope! {
462 writeln!(buff.borrow_mut(), "This will be printed 9th");
463 };
464
465 writeln!(buff.borrow_mut(), "This will be printed 6th");
466
467 defer! {
468 writeln!(buff.borrow_mut(), "This will be printed 7th");
469 };
470 }
471 }
472
473 #[test]
474 fn test_defer_macro_execution() {
475 let val = Cell::new(0);
476 {
477 defer!(val.set(1));
478 assert_eq!(val.get(), 0);
479 }
480 assert_eq!(val.get(), 1);
481 }
482
483 #[test]
484 fn test_defer_struct() {
485 let val = Cell::new(0);
486 {
487 let _deferred = Defer::new(|| val.set(1));
488 assert_eq!(val.get(), 0);
489 }
490 assert_eq!(val.get(), 1);
491 }
492
493 #[test]
494 fn test_defer_scoped_macro_execution() {
495 let val = Cell::new(0);
496 {
497 defer_scope_init!();
498 {
499 defer_scope!(val.set(1));
500 assert_eq!(val.get(), 0);
501 }
502 assert_eq!(val.get(), 0);
503 }
504 assert_eq!(val.get(), 1)
505 }
506
507 #[test]
508 fn test_defer_group() {
509 let val = Cell::new(0);
510 {
511 let mut deferred = DeferGroup::new();
512 {
513 deferred.add(Box::new(|| val.set(1)));
514 assert_eq!(val.get(), 0);
515 }
516 assert_eq!(val.get(), 0);
517 }
518 assert_eq!(val.get(), 1)
519 }
520
521 #[test]
522 fn test_defer_macro_immediate_args_eval() {
523 let buff = RefCell::new(Vec::new());
524 let buff2 = RefCell::new(Vec::new());
525 let val = Cell::new(0);
526
527 defer! {
528 let res = b"x is: 3\n";
529 assert_eq!(*buff.borrow(), res.to_vec());
530
531 let res = b"x is: 0\n";
532 assert_eq!(*buff2.borrow(), res.to_vec());
533 };
534
535 // This will evaluate the arguments passed to the invoked at function at call time (deferred-to time, later), results in `3`
536 defer!(
537 add_to_buffer(
538 format!("x is: {}", val.get()),
539 &buff
540 );
541 );
542
543 // This will evaluate the arguments passed to the invoked at function at time of macro invocation (now), results in `0`
544 defer!(add_to_buffer(format!("x is: {}", val.get()), &buff2));
545 val.set(3);
546 }
547
548 #[test]
549 fn test_defer_scope_macro_immediate_args_eval() {
550 let buff = RefCell::new(Vec::new());
551 let buff2 = RefCell::new(Vec::new());
552 let val = Cell::new(0);
553 defer_scope_init!();
554 defer_scope! {
555 let res = b"x is: 3\n";
556 assert_eq!(*buff.borrow(), res.to_vec());
557
558 let res = b"x is: 0\n";
559 assert_eq!(*buff2.borrow(), res.to_vec());
560 };
561
562 // This will evaluate the arguments passed to the invoked at function at call time (deferred-to time, later), results in `3`
563 defer_scope!(
564 add_to_buffer(
565 format!("x is: {}", val.get()),
566 &buff
567 );
568 );
569
570 // This will evaluate the arguments passed to the invoked at function at time of macro invocation (now), results in `0`
571 defer_scope!(add_to_buffer(format!("x is: {}", val.get()), &buff2));
572 val.set(3);
573 }
574}
575