debug_tree/
lib.rs

1use std::sync::{Arc, Mutex};
2
3#[macro_use]
4pub mod default;
5mod internal;
6pub mod scoped_branch;
7
8pub mod defer;
9mod test;
10pub mod tree_config;
11
12pub use default::default_tree;
13use once_cell::sync::Lazy;
14use scoped_branch::ScopedBranch;
15use std::collections::BTreeMap;
16use std::fs::File;
17use std::io::Write;
18
19pub use crate::tree_config::*;
20
21/// Reference wrapper for `TreeBuilderBase`
22#[derive(Debug, Clone)]
23pub struct TreeBuilder(Arc<Mutex<internal::TreeBuilderBase>>);
24
25impl TreeBuilder {
26    /// Returns a new `TreeBuilder` with an empty `Tree`.
27    ///
28    /// # Example
29    ///
30    /// ```
31    /// use debug_tree::TreeBuilder;
32    /// let tree = TreeBuilder::new();
33    /// ```
34    pub fn new() -> TreeBuilder {
35        TreeBuilder {
36            0: Arc::new(Mutex::new(internal::TreeBuilderBase::new())),
37        }
38    }
39
40    /// Set the configuration override for displaying trees
41    ///
42    /// # Example
43    ///
44    /// ```
45    /// use debug_tree::{TreeBuilder, add_branch_to, add_leaf_to, TreeSymbols, TreeConfig};
46    /// let tree = TreeBuilder::new();
47    /// {
48    ///     add_branch_to!(tree, "1");
49    ///     {
50    ///         add_branch_to!(tree, "1.1");
51    ///         add_leaf_to!(tree, "1.1.1");
52    ///         add_leaf_to!(tree, "1.1.2");
53    ///     }
54    ///     add_leaf_to!(tree, "1.2");
55    /// }
56    /// add_leaf_to!(tree, "2");
57    /// tree.set_config_override(TreeConfig::new()
58    ///     .show_first_level()
59    ///     .symbols(TreeSymbols::with_rounded()));
60    /// tree.peek_print();
61    /// assert_eq!("\
62    /// ├╼ 1
63    /// │ ├╼ 1.1
64    /// │ │ ├╼ 1.1.1
65    /// │ │ ╰╼ 1.1.2
66    /// │ ╰╼ 1.2
67    /// ╰╼ 2" , &tree.string());
68    /// ```
69    pub fn set_config_override(&self, config: TreeConfig) {
70        let mut lock = self.0.lock().unwrap();
71        lock.set_config_override(Some(config))
72    }
73
74    /// Remove the configuration override
75    /// The default configuration will be used instead
76    pub fn remove_config_override(&self) {
77        self.0.lock().unwrap().set_config_override(None);
78    }
79
80    /// Update the configuration override for displaying trees
81    /// If an override doesn't yet exist, it is created.
82    ///
83    /// # Example
84    ///
85    /// ```
86    /// use debug_tree::{TreeBuilder, add_branch_to, add_leaf_to, TreeSymbols};
87    /// let tree = TreeBuilder::new();
88    /// {
89    ///     add_branch_to!(tree, "1");
90    ///     {
91    ///         add_branch_to!(tree, "1.1");
92    ///         add_leaf_to!(tree, "1.1.1");
93    ///         add_leaf_to!(tree, "1.1.2");
94    ///     }
95    ///     add_leaf_to!(tree, "1.2");
96    /// }
97    /// add_leaf_to!(tree, "2");
98    /// tree.update_config_override(|x|{
99    ///     x.indent = 3;
100    ///     x.symbols = TreeSymbols::with_rounded();
101    ///     x.show_first_level = true;
102    /// });
103    /// tree.peek_print();
104    /// assert_eq!("\
105    /// ├─╼ 1
106    /// │  ├─╼ 1.1
107    /// │  │  ├─╼ 1.1.1
108    /// │  │  ╰─╼ 1.1.2
109    /// │  ╰─╼ 1.2
110    /// ╰─╼ 2" , &tree.string());
111    /// ```
112    pub fn update_config_override<F: Fn(&mut TreeConfig)>(&self, update: F) {
113        let mut lock = self.0.lock().unwrap();
114        match lock.config_override_mut() {
115            Some(x) => update(x),
116            None => {
117                let mut x = TreeConfig::default();
118                update(&mut x);
119                lock.set_config_override(Some(x));
120            }
121        }
122    }
123
124    /// Returns the optional configuration override.
125    pub fn get_config_override(&self) -> Option<TreeConfig> {
126        let lock = self.0.lock().unwrap();
127        lock.config_override().clone()
128    }
129
130    /// Returns whether a configuration override is set.
131    pub fn has_config_override(&self) -> bool {
132        let lock = self.0.lock().unwrap();
133        lock.config_override().is_some()
134    }
135
136    /// Adds a new branch with text, `text` and returns a `ScopedBranch`.
137    /// When the returned `ScopedBranch` goes out of scope, (likely the end of the current block),
138    /// or if its `release()` method is called, the tree will step back out of the added branch.
139    ///
140    /// # Arguments
141    /// * `text` - A string slice to use as the newly added branch's text.
142    ///
143    /// # Examples
144    ///
145    /// Exiting branch when end of scope is reached.
146    /// ```
147    /// use debug_tree::TreeBuilder;
148    /// let tree = TreeBuilder::new();
149    /// {
150    ///     let _branch = tree.add_branch("Branch"); // _branch enters scope
151    ///     // tree is now pointed inside new branch.
152    ///     tree.add_leaf("Child of Branch");
153    ///     // _branch leaves scope, tree moves up to parent branch.
154    /// }
155    /// tree.add_leaf("Sibling of Branch");
156    /// assert_eq!("\
157    /// Branch
158    /// └╼ Child of Branch
159    /// Sibling of Branch" , &tree.string());
160    /// ```
161    ///
162    /// Using `release()` before out of scope.
163    /// ```
164    /// use debug_tree::TreeBuilder;
165    /// let tree = TreeBuilder::new();
166    /// {
167    ///     let mut branch = tree.add_branch("Branch"); // branch enters scope
168    ///     // tree is now pointed inside new branch.
169    ///     tree.add_leaf("Child of Branch");
170    ///     branch.release();
171    ///     tree.add_leaf("Sibling of Branch");
172    ///     // branch leaves scope, but no effect because its `release()` method has already been called
173    /// }
174    /// assert_eq!("\
175    /// Branch
176    /// └╼ Child of Branch
177    /// Sibling of Branch", &tree.string());
178    /// ```
179    pub fn add_branch(&self, text: &str) -> ScopedBranch {
180        self.add_leaf(text);
181        ScopedBranch::new(self.clone())
182    }
183
184    /// Adds a new branch with text, `text` and returns a `ScopedBranch`.
185    /// When the returned `ScopedBranch` goes out of scope, (likely the end of the current block),
186    /// or if its `release()` method is called, the tree tree will step back out of the added branch.
187    ///
188    /// # Arguments
189    /// * `text` - A string slice to use as the newly added branch's text.
190    ///
191    /// # Examples
192    ///
193    /// Stepping out of branch when end of scope is reached.
194    /// ```
195    /// use debug_tree::TreeBuilder;
196    /// let tree = TreeBuilder::new();
197    /// {
198    ///     tree.add_leaf("Branch");
199    ///     let _branch = tree.enter_scoped(); // _branch enters scope
200    ///     // tree is now pointed inside new branch.
201    ///     tree.add_leaf("Child of Branch");
202    ///     // _branch leaves scope, tree moves up to parent branch.
203    /// }
204    /// tree.add_leaf("Sibling of Branch");
205    /// assert_eq!("\
206    /// Branch
207    /// └╼ Child of Branch
208    /// Sibling of Branch", &tree.string());
209    /// ```
210    ///
211    /// Using `release()` before out of scope.
212    /// ```
213    /// use debug_tree::TreeBuilder;
214    /// let tree = TreeBuilder::new();
215    /// {
216    ///     tree.add_leaf("Branch");
217    ///     let mut branch = tree.enter_scoped(); // branch enters scope
218    ///     // tree is now pointed inside new branch.
219    ///     tree.add_leaf("Child of Branch");
220    ///     branch.release();
221    ///     tree.add_leaf("Sibling of Branch");
222    ///     // branch leaves scope, but no effect because its `release()` method has already been called
223    /// }
224    /// assert_eq!("\
225    /// Branch
226    /// └╼ Child of Branch
227    /// Sibling of Branch", &tree.string());
228    /// ```
229    pub fn enter_scoped(&self) -> ScopedBranch {
230        if self.is_enabled() {
231            ScopedBranch::new(self.clone())
232        } else {
233            ScopedBranch::none()
234        }
235    }
236
237    /// Adds a leaf to current branch with the given text, `text`.
238    ///
239    /// # Arguments
240    /// * `text` - A string slice to use as the newly added leaf's text.
241    ///
242    /// # Example
243    ///
244    /// ```
245    /// use debug_tree::TreeBuilder;
246    /// let tree = TreeBuilder::new();
247    /// tree.add_leaf("New leaf");
248    /// ```
249    pub fn add_leaf(&self, text: &str) {
250        let mut x = self.0.lock().unwrap();
251        if x.is_enabled() {
252            x.add_leaf(&text);
253        }
254    }
255
256    /// Steps into a new child branch.
257    /// Stepping out of the branch requires calling `exit()`.
258    ///
259    /// # Example
260    /// ```
261    /// use debug_tree::TreeBuilder;
262    /// let tree = TreeBuilder::new();
263    /// tree.add_leaf("Branch");
264    /// tree.enter();
265    /// tree.add_leaf("Child of Branch");
266    /// assert_eq!("\
267    /// Branch
268    /// └╼ Child of Branch", &tree.string());
269    /// ```
270    pub fn enter(&self) {
271        let mut x = self.0.lock().unwrap();
272        if x.is_enabled() {
273            x.enter();
274        }
275    }
276
277    /// Exits the current branch, to the parent branch.
278    /// If no parent branch exists, no action is taken
279    ///
280    /// # Example
281    ///
282    /// ```
283    /// use debug_tree::TreeBuilder;
284    /// let tree = TreeBuilder::new();
285    /// tree.add_leaf("Branch");
286    /// tree.enter();
287    /// tree.add_leaf("Child of Branch");
288    /// tree.exit();
289    /// tree.add_leaf("Sibling of Branch");
290    /// assert_eq!("\
291    /// Branch
292    /// └╼ Child of Branch
293    /// Sibling of Branch", &tree.string());
294    /// ```
295    pub fn exit(&self) -> bool {
296        let mut x = self.0.lock().unwrap();
297        if x.is_enabled() {
298            x.exit()
299        } else {
300            false
301        }
302    }
303
304    /// Returns the depth of the current branch
305    /// The initial depth when no branches have been adeed is 0.
306    ///
307    /// # Example
308    ///
309    /// ```
310    /// use debug_tree::TreeBuilder;
311    /// let tree = TreeBuilder::new();
312    /// assert_eq!(0, tree.depth());
313    /// let _b = tree.add_branch("Branch");
314    /// assert_eq!(1, tree.depth());
315    /// let _b = tree.add_branch("Child branch");
316    /// assert_eq!(2, tree.depth());
317    /// ```
318    pub fn depth(&self) -> usize {
319        self.0.lock().unwrap().depth()
320    }
321
322    /// Prints the tree without clearing.
323    ///
324    /// # Example
325    ///
326    /// ```
327    /// use debug_tree::TreeBuilder;
328    /// let tree = TreeBuilder::new();
329    /// tree.add_leaf("Leaf");
330    /// tree.peek_print();
331    /// // Leaf
332    /// tree.peek_print();
333    /// // Leaf
334    /// // Leaf 2
335    /// ```
336    pub fn peek_print(&self) {
337        self.0.lock().unwrap().peek_print();
338    }
339
340    /// Prints the tree and then clears it.
341    ///
342    /// # Example
343    ///
344    /// ```
345    /// use debug_tree::TreeBuilder;
346    /// let tree = TreeBuilder::new();
347    /// tree.add_leaf("Leaf");
348    /// tree.print();
349    /// // Leaf
350    /// tree.add_leaf("Leaf 2");
351    /// tree.print();
352    /// // Leaf 2
353    /// ```
354    pub fn print(&self) {
355        self.0.lock().unwrap().print();
356    }
357
358    /// Returns the tree as a string without clearing the tree.
359    ///
360    /// # Example
361    ///
362    /// ```
363    /// use debug_tree::TreeBuilder;
364    /// let tree = TreeBuilder::new();
365    /// tree.add_leaf("Leaf");
366    /// assert_eq!("Leaf", tree.peek_string());
367    /// tree.add_leaf("Leaf 2");
368    /// assert_eq!("Leaf\nLeaf 2", tree.peek_string());
369    /// ```
370    pub fn peek_string(&self) -> String {
371        self.0.lock().unwrap().peek_string()
372    }
373
374    /// Returns the tree as a string and clears the tree.
375    ///
376    /// # Example
377    ///
378    /// ```
379    /// use debug_tree::TreeBuilder;
380    /// let tree = TreeBuilder::new();
381    /// tree.add_leaf("Leaf");
382    /// assert_eq!("Leaf", tree.string());
383    /// tree.add_leaf("Leaf 2");
384    /// assert_eq!("Leaf 2", tree.string());
385    /// ```
386    pub fn string(&self) -> String {
387        self.0.lock().unwrap().string()
388    }
389
390    /// Writes the tree to file without clearing.
391    ///
392    /// # Example
393    ///
394    /// ```
395    /// use debug_tree::TreeBuilder;
396    /// use std::fs::{read_to_string, create_dir};
397    /// use std::io::Read;
398    /// let tree = TreeBuilder::new();
399    /// create_dir("test_out").ok();
400    /// tree.add_leaf("Leaf");
401    /// assert_eq!(tree.peek_string(), "Leaf");
402    /// tree.peek_write("test_out/peek_write.txt");
403    /// assert_eq!(read_to_string("test_out/peek_write.txt").unwrap(), "Leaf");
404    /// assert_eq!(tree.peek_string(), "Leaf");
405    /// ```
406    pub fn peek_write(&self, path: &str) -> std::io::Result<()> {
407        let mut file = File::create(path)?;
408        file.write_all(self.peek_string().as_bytes())
409    }
410
411    /// Writes the tree to file without clearing.
412    ///
413    /// # Example
414    ///
415    /// ```
416    /// use debug_tree::TreeBuilder;
417    /// use std::io::Read;
418    /// use std::fs::{read_to_string, create_dir};
419    /// let tree = TreeBuilder::new();
420    /// create_dir("test_out").ok();
421    /// tree.add_leaf("Leaf");
422    /// assert_eq!(tree.peek_string(), "Leaf");
423    /// tree.write("test_out/write.txt");
424    /// assert_eq!(read_to_string("test_out/write.txt").unwrap(), "Leaf");
425    /// assert_eq!(tree.peek_string(), "");
426    /// ```
427    pub fn write(&self, path: &str) -> std::io::Result<()> {
428        let mut file = File::create(path)?;
429        file.write_all(self.string().as_bytes())
430    }
431
432    /// Clears the tree.
433    ///
434    /// # Example
435    ///
436    /// ```
437    /// use debug_tree::TreeBuilder;
438    /// let tree = TreeBuilder::new();
439    /// tree.add_leaf("Leaf");
440    /// assert_eq!("Leaf", tree.peek_string());
441    /// tree.clear();
442    /// assert_eq!("", tree.peek_string());
443    /// ```
444    pub fn clear(&self) {
445        self.0.lock().unwrap().clear()
446    }
447
448    /// Sets the enabled state of the tree.
449    ///
450    /// If not enabled, the tree will not be modified by adding leaves or branches.
451    /// Additionally, if called using the `add_`... macros, arguments will not be processed.
452    /// This is particularly useful for suppressing output in production, with very little overhead.
453    ///
454    /// # Example
455    /// ```
456    /// #[macro_use]
457    /// use debug_tree::{TreeBuilder, add_leaf_to};
458    /// let mut tree = TreeBuilder::new();
459    /// tree.add_leaf("Leaf 1");
460    /// tree.set_enabled(false);
461    /// add_leaf_to!(tree, "Leaf 2");
462    /// tree.set_enabled(true);
463    /// add_leaf_to!(tree, "Leaf 3");
464    /// assert_eq!("Leaf 1\nLeaf 3", tree.peek_string());
465    /// ```
466    pub fn set_enabled(&self, enabled: bool) {
467        self.0.lock().unwrap().set_enabled(enabled);
468    }
469
470    /// Returns the enabled state of the tree.
471    ///
472    /// # Example
473    /// ```
474    /// use debug_tree::TreeBuilder;
475    /// let mut tree = TreeBuilder::new();
476    /// assert_eq!(true, tree.is_enabled());
477    /// tree.set_enabled(false);
478    /// assert_eq!(false, tree.is_enabled());
479    /// ```
480    pub fn is_enabled(&self) -> bool {
481        self.0.lock().unwrap().is_enabled()
482    }
483}
484
485pub trait AsTree {
486    fn as_tree(&self) -> TreeBuilder;
487    fn is_tree_enabled(&self) -> bool {
488        self.as_tree().is_enabled()
489    }
490}
491
492impl AsTree for TreeBuilder {
493    fn as_tree(&self) -> TreeBuilder {
494        self.clone()
495    }
496}
497
498pub(crate) fn get_or_add_tree<T: AsRef<str>>(name: T) -> TreeBuilder {
499    let mut map = TREE_MAP.lock().unwrap();
500    match map.get(name.as_ref()) {
501        Some(x) => x.clone(),
502        _ => {
503            let val = TreeBuilder::new();
504            map.insert(name.as_ref().to_string(), val.clone());
505            val
506        }
507    }
508}
509
510pub(crate) fn get_tree<T: AsRef<str>>(name: T) -> Option<TreeBuilder> {
511    TREE_MAP.lock().unwrap().get(name.as_ref()).cloned()
512}
513
514type TreeMap = BTreeMap<String, TreeBuilder>;
515
516static TREE_MAP: Lazy<Arc<Mutex<TreeMap>>> =
517    Lazy::new(|| -> Arc<Mutex<TreeMap>> { Arc::new(Mutex::new(TreeMap::new())) });
518
519/// Sets the enabled state of the tree.
520///
521/// # Arguments
522/// * `name` - The tree name
523/// * `enabled` - The enabled state
524///
525pub fn set_enabled<T: AsRef<str>>(name: T, enabled: bool) {
526    let mut map = TREE_MAP.lock().unwrap();
527    match map.get_mut(name.as_ref()) {
528        Some(x) => x.set_enabled(enabled),
529        _ => {
530            let tree = TreeBuilder::new();
531            tree.set_enabled(enabled);
532            map.insert(name.as_ref().to_string(), tree);
533        }
534    }
535}
536
537impl<T: AsRef<str>> AsTree for T {
538    fn as_tree(&self) -> TreeBuilder {
539        get_or_add_tree(self)
540    }
541    /// Check if the named tree is enabled and exists
542    /// This does not create a new tree if non-existent
543    ///
544    /// # Arguments
545    /// * `tree_name` - The tree name
546    ///
547    fn is_tree_enabled(&self) -> bool {
548        get_tree(self).map(|x| x.is_enabled()).unwrap_or(false)
549    }
550}
551
552/// Returns the tree
553/// If there is no tree then one is created and then returned.
554pub fn tree<T: AsTree>(tree: T) -> TreeBuilder {
555    tree.as_tree()
556}
557
558/// Returns the tree named `name`
559/// If there is no tree named `name` then one is created and then returned.
560pub fn is_tree_enabled<T: AsTree>(tree: &T) -> bool {
561    tree.is_tree_enabled()
562}
563
564/// Calls [clear](TreeBuilder::clear) for the tree named `name`
565/// If there is no tree named `name` then one is created
566pub fn clear<T: AsRef<str>>(name: T) {
567    name.as_tree().clear();
568}
569
570/// Returns [string](TreeBuilder::string) for the tree named `name`
571/// If there is no tree named `name` then one is created
572pub fn string<T: AsRef<str>>(name: T) -> String {
573    name.as_tree().string()
574}
575
576/// Returns [peek_string](TreeBuilder::peek_string) for the tree named `name`
577/// If there is no tree named `name` then one is created
578pub fn peek_string<T: AsRef<str>>(name: T) -> String {
579    name.as_tree().peek_string()
580}
581
582/// Calls [print](TreeBuilder::print) for the tree named `name`
583/// If there is no tree named `name` then one is created
584pub fn print<T: AsRef<str>>(name: T) {
585    name.as_tree().print();
586}
587
588/// Calls [peek_print](TreeBuilder::peek_print)  for the tree named `name`
589/// If there is no tree named `name` then one is created
590pub fn peek_print<T: AsRef<str>>(name: T) {
591    name.as_tree().peek_print();
592}
593
594/// Calls [write](TreeBuilder::write) for the tree named `name`
595/// If there is no tree named `name` then one is created
596pub fn write<T: AsRef<str>, P: AsRef<str>>(name: T, path: P) -> std::io::Result<()> {
597    name.as_tree().write(path.as_ref())
598}
599
600/// Calls [peek_print](TreeBuilder::peek_print)  for the tree named `name`
601/// If there is no tree named `name` then one is created
602pub fn peek_write<T: AsRef<str>, P: AsRef<str>>(name: T, path: P) -> std::io::Result<()> {
603    name.as_tree().peek_write(path.as_ref())
604}
605
606/// Adds a leaf to given tree with the given text and formatting arguments
607///
608/// # Arguments
609/// * `tree` - The tree that the leaf should be added to
610/// * `text...` - Formatted text arguments, as per `format!(...)`.
611///
612/// # Example
613///
614/// ```
615/// #[macro_use]
616/// use debug_tree::{TreeBuilder, add_leaf_to};
617/// fn main() {
618///     let tree = TreeBuilder::new();
619///     add_leaf_to!(tree, "A {} leaf", "new");
620///     assert_eq!("A new leaf", &tree.peek_string());
621/// }
622/// ```
623#[macro_export]
624macro_rules! add_leaf_to {
625    ($tree:expr, $($arg:tt)*) => (if $crate::is_tree_enabled(&$tree) {
626        use $crate::AsTree;
627        $tree.as_tree().add_leaf(&format!($($arg)*))
628    });
629}
630
631/// Adds a leaf to given tree with the given `value` argument
632///
633/// # Arguments
634/// * `tree` - The tree that the leaf should be added to
635/// * `value` - An expression that implements the `Display` trait.
636///
637/// # Example
638///
639/// ```
640/// #[macro_use]
641/// use debug_tree::{TreeBuilder, add_leaf_value_to};
642/// fn main() {
643///     let tree = TreeBuilder::new();
644///     let value = add_leaf_value_to!(tree, 5 * 4 * 3 * 2);
645///     assert_eq!(120, value);
646///     assert_eq!("120", &tree.peek_string());
647/// }
648/// ```
649#[macro_export]
650macro_rules! add_leaf_value_to {
651    ($tree:expr, $value:expr) => {{
652        let v = $value;
653        if $crate::is_tree_enabled(&$tree) {
654            use $crate::AsTree;
655            $tree.as_tree().add_leaf(&format!("{}", &v));
656        }
657        v
658    }};
659}
660
661/// Adds a scoped branch to given tree with the given text and formatting arguments
662/// The branch will be exited at the end of the current block.
663///
664/// # Arguments
665/// * `tree` - The tree that the leaf should be added to
666/// * `text...` - Formatted text arguments, as per `format!(...)`.
667///
668/// # Example
669///
670/// ```
671/// #[macro_use]
672/// use debug_tree::{TreeBuilder, add_branch_to, add_leaf_to};
673/// fn main() {
674///     let tree = TreeBuilder::new();
675///     {
676///         add_branch_to!(tree, "New {}", "Branch"); // _branch enters scope
677///         // tree is now pointed inside new branch.
678///         add_leaf_to!(tree, "Child of {}", "Branch");
679///         // Block ends, so tree exits the current branch.
680///     }
681///     add_leaf_to!(tree, "Sibling of {}", "Branch");
682///     assert_eq!("\
683/// New Branch
684/// └╼ Child of Branch
685/// Sibling of Branch" , &tree.string());
686/// }
687/// ```
688#[macro_export]
689macro_rules! add_branch_to {
690    ($tree:expr) => {
691        let _debug_tree_branch = if $crate::is_tree_enabled(&$tree) {
692            use $crate::AsTree;
693            $tree.as_tree().enter_scoped()
694        } else {
695            $crate::scoped_branch::ScopedBranch::none()
696        };
697    };
698    ($tree:expr, $($arg:tt)*) => {
699        let _debug_tree_branch = if $crate::is_tree_enabled(&$tree) {
700            use $crate::AsTree;
701            $tree.as_tree().add_branch(&format!($($arg)*))
702        } else {
703            $crate::scoped_branch::ScopedBranch::none()
704        };
705    };
706}
707
708/// Calls `function` with argument, `tree`, at the end of the current scope
709/// The function will only be executed if the tree is enabled when this macro is called
710#[macro_export]
711macro_rules! defer {
712    ($function:expr) => {
713        let _debug_tree_defer = {
714            use $crate::AsTree;
715            if $crate::default::default_tree().is_enabled() {
716                use $crate::AsTree;
717                $crate::defer::DeferredFn::new($crate::default::default_tree(), $function)
718            } else {
719                $crate::defer::DeferredFn::none()
720            }
721        };
722    };
723    ($tree:expr, $function:expr) => {
724        let _debug_tree_defer = {
725            use $crate::AsTree;
726            if $tree.as_tree().is_enabled() {
727                $crate::defer::DeferredFn::new($tree.as_tree(), $function)
728            } else {
729                $crate::defer::DeferredFn::none()
730            }
731        };
732    };
733}
734
735/// Calls [print](TreeBuilder::print) on `tree` at the end of the current scope.
736/// The function will only be executed if the tree is enabled when this macro is called
737#[macro_export]
738macro_rules! defer_print {
739    () => {
740        $crate::defer!(|x| {
741            x.print();
742        })
743    };
744    ($tree:expr) => {
745        $crate::defer!($tree, |x| {
746            x.print();
747        })
748    };
749}
750
751/// Calls [peek_print](TreeBuilder::peek_print) on `tree` at the end of the current scope.
752/// The function will only be executed if the tree is enabled when this macro is called
753#[macro_export]
754macro_rules! defer_peek_print {
755    () => {
756        $crate::defer!(|x| {
757            x.peek_print();
758        })
759    };
760    ($tree:expr) => {
761        $crate::defer!($tree, |x| {
762            x.peek_print();
763        })
764    };
765}
766
767/// Calls [write](TreeBuilder::write) on `tree` at the end of the current scope.
768/// The function will only be executed if the tree is enabled when this macro is called
769#[macro_export]
770macro_rules! defer_write {
771    ($tree:expr, $path:expr) => {
772        $crate::defer!($tree, |x| {
773            if let Err(err) = x.write($path) {
774                eprintln!("error during `defer_write`: {}", err);
775            }
776        })
777    };
778    ($path:expr) => {
779        $crate::defer!(|x| {
780            if let Err(err) = x.write($path) {
781                eprintln!("error during `defer_write`: {}", err);
782            }
783        })
784    };
785}
786
787/// Calls [peek_write](TreeBuilder::peek_write) on `tree` at the end of the current scope.
788/// The function will only be executed if the tree is enabled when this macro is called
789#[macro_export]
790macro_rules! defer_peek_write {
791    ($tree:expr, $path:expr) => {
792        $crate::defer!($tree, |x| {
793            if let Err(err) = x.peek_write($path) {
794                eprintln!("error during `defer_peek_write`: {}", err);
795            }
796        })
797    };
798    ($path:expr) => {
799        $crate::defer!(|x| {
800            if let Err(err) = x.peek_write($path) {
801                eprintln!("error during `defer_peek_write`: {}", err);
802            }
803        })
804    };
805}