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