1 use std::sync::{Arc, Mutex};
2
3 #[macro_use]
4 pub mod default;
5 mod internal;
6 pub mod scoped_branch;
7
8 pub mod defer;
9 mod test;
10 pub mod tree_config;
11
12 pub use default::default_tree;
13 use once_cell::sync::Lazy;
14 use scoped_branch::ScopedBranch;
15 use std::collections::BTreeMap;
16 use std::fs::File;
17 use std::io::Write;
18
19 pub use crate::tree_config::*;
20
21 /// Reference wrapper for `TreeBuilderBase`
22 #[derive(Debug, Clone)]
23 pub struct TreeBuilder(Arc<Mutex<internal::TreeBuilderBase>>);
24
25 impl 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 /// ```
new() -> TreeBuilder34 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 /// ```
set_config_override(&self, config: TreeConfig)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
remove_config_override(&self)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 /// ```
update_config_override<F: Fn(&mut TreeConfig)>(&self, update: F)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.
get_config_override(&self) -> Option<TreeConfig>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.
has_config_override(&self) -> bool131 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 /// ```
add_branch(&self, text: &str) -> ScopedBranch179 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 /// ```
enter_scoped(&self) -> ScopedBranch229 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 /// ```
add_leaf(&self, text: &str)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 /// ```
enter(&self)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 /// ```
exit(&self) -> bool295 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 /// ```
depth(&self) -> usize318 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 /// ```
peek_print(&self)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 /// ```
print(&self)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 /// ```
peek_string(&self) -> String370 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 /// ```
string(&self) -> String386 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 /// ```
peek_write(&self, path: &str) -> std::io::Result<()>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 /// ```
write(&self, path: &str) -> std::io::Result<()>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 /// ```
clear(&self)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 /// ```
set_enabled(&self, enabled: bool)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 /// ```
is_enabled(&self) -> bool480 pub fn is_enabled(&self) -> bool {
481 self.0.lock().unwrap().is_enabled()
482 }
483 }
484
485 pub trait AsTree {
as_tree(&self) -> TreeBuilder486 fn as_tree(&self) -> TreeBuilder;
is_tree_enabled(&self) -> bool487 fn is_tree_enabled(&self) -> bool {
488 self.as_tree().is_enabled()
489 }
490 }
491
492 impl AsTree for TreeBuilder {
as_tree(&self) -> TreeBuilder493 fn as_tree(&self) -> TreeBuilder {
494 self.clone()
495 }
496 }
497
get_or_add_tree<T: AsRef<str>>(name: T) -> TreeBuilder498 pub(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
get_tree<T: AsRef<str>>(name: T) -> Option<TreeBuilder>510 pub(crate) fn get_tree<T: AsRef<str>>(name: T) -> Option<TreeBuilder> {
511 TREE_MAP.lock().unwrap().get(name.as_ref()).cloned()
512 }
513
514 type TreeMap = BTreeMap<String, TreeBuilder>;
515
516 static 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 ///
set_enabled<T: AsRef<str>>(name: T, enabled: bool)525 pub 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
537 impl<T: AsRef<str>> AsTree for T {
as_tree(&self) -> TreeBuilder538 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 ///
is_tree_enabled(&self) -> bool547 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.
tree<T: AsTree>(tree: T) -> TreeBuilder554 pub 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.
is_tree_enabled<T: AsTree>(tree: &T) -> bool560 pub 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
clear<T: AsRef<str>>(name: T)566 pub 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
string<T: AsRef<str>>(name: T) -> String572 pub 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
peek_string<T: AsRef<str>>(name: T) -> String578 pub 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
print<T: AsRef<str>>(name: T)584 pub 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
peek_print<T: AsRef<str>>(name: T)590 pub 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
write<T: AsRef<str>, P: AsRef<str>>(name: T, path: P) -> std::io::Result<()>596 pub 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
peek_write<T: AsRef<str>, P: AsRef<str>>(name: T, path: P) -> std::io::Result<()>602 pub 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]
624 macro_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]
650 macro_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]
689 macro_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]
711 macro_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]
738 macro_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]
754 macro_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]
770 macro_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]
790 macro_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 }
806