• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..--

doc/25-Apr-2025-213140

examples/25-Apr-2025-151124

patches/25-Apr-2025-2625

src/25-Apr-2025-2,1521,452

.cargo-checksum.jsonD25-Apr-20252.4 KiB11

Android.bpD25-Apr-20251.2 KiB5247

Cargo.lockD25-Apr-20255.4 KiB213189

Cargo.tomlD25-Apr-20251 KiB3430

LICENSED25-Apr-20251 KiB2016

METADATAD25-Apr-2025416 1817

MODULE_LICENSE_MITD25-Apr-20250

README.mdD25-Apr-20256.1 KiB284236

TEST_MAPPINGD25-Apr-202578 87

cargo_embargo.jsonD25-Apr-202542 54

README.md

1# Debug Tree
2
3This library allows you to build a tree one element at a time and output it as a pretty string.
4
5The tree can easily be output to a `String`, `stdout` or a file.
6
7This is particularly convenient for generating clean output from nested and recursive functions.
8
9* [Recursive Fibonacci Example](#recursive-fibonacci-example)
10* [Overview](#overview)
11* [More Examples](#more-examples)
12    * [Multiple Tagged Trees](#multiple-tagged-trees)
13    * [Nested Functions](#nested-functions)
14    * [Panic](#panics)
15    * [Without Macros](#without-macros)
16
17
18## Recursive Fibonacci Example
19
20Using the `add_branch!()` macro at the start of the `factors()` function, you can generate an entire call tree, with minimal effort.
21
22<!--{ fibonacci.rs | code: rust }-->
23```rust
24use debug_tree::*;
25
26fn factors(x: usize) {
27    add_branch!("{}", x); // <~ THE MAGIC LINE
28    for i in 1..x {
29        if x % i == 0 {
30            factors(i);
31        }
32    }
33}
34
35fn main() {
36    // output to file at the end of this block
37    defer_write!("examples/out/fibonacci.txt");
38    add_branch!("A Fibonacci Tree");
39    factors(6);
40    add_leaf!("That's All Folks!");
41}
42```
43<!--{ end }-->
44
45<!--{ out/fibonacci.txt | code }-->
46```
47A Fibonacci Tree
48├╼ 6
49│ ├╼ 1
50│ ├╼ 2
51│ │ └╼ 1
52│ └╼ 3
53│   └╼ 1
54└╼ That's All Folks!
55```
56<!--{ end }-->
57
58## Overview
59
60- Add a branch
61    - `add_branch!("Hello, {}", "World")`
62    - The branch will exit at the end of the current block
63
64- Add a leaf
65    - `add_leaf!("I am a {}", "leaf")`
66    - Added to the current scoped branch
67
68- Print a tree, or write it to file at the end of a block
69    - `defer_print!()`
70    - `defer_write!("filename.txt")`
71    - The tree will be empty after these calls
72    - To prevent clearing, use `defer_peek_print!` and `defer_peek_write!`
73
74
75- Handle multiple trees using named trees
76    - `add_branch_to!("A", "I'm a branch on tree 'A'")`
77    - `add_leaf_to!("A", "I'm a leaf on tree 'A'")`
78    - `defer_print!("A")`
79    - `defer_write!("A", "filename.txt")`
80
81- Get a named tree
82    - `tree("TREE_NAME")`
83
84- Retrieve the pretty-string from a tree
85    - `tree("TREE_NAME").string()`
86
87
88- Usage across threads
89    - `default_tree()` is local to each thread
90    - Named trees are shared between threads
91
92## More Examples
93
94### Multiple Tagged Trees
95
96If you need multiple, separated trees you can use a name tag.
97
98<!--{ multiple_trees.rs | code: rust }-->
99```rust
100use debug_tree::*;
101
102fn populate(tree_name: &str, n_children: usize) {
103    add_branch_to!(tree_name, "{} TREE", tree_name);
104    for _ in 0..n_children {
105        populate(tree_name, n_children / 2);
106    }
107}
108fn main() {
109    // Override tree config (just for "B")
110    let b_tree = tree("B");
111    b_tree.set_config_override(
112        TreeConfig::new()
113            .indent(4)
114            .symbols(TreeSymbols::with_rounded().leaf("> ")),
115    );
116    defer_write!(b_tree, "examples/out/multiple_trees_B.txt");
117    defer_write!("A", "examples/out/multiple_trees_A.txt");
118
119    populate("A", 2);
120    populate("B", 3);
121}
122```
123<!--{ end }-->
124<!--{ out/multiple_trees_A.txt | code }-->
125```
126A TREE
127├╼ A TREE
128│ └╼ A TREE
129└╼ A TREE
130  └╼ A TREE
131```
132<!--{ end }-->
133<!--{ out/multiple_trees_B.txt | code }-->
134```
135B TREE
136├──> B TREE
137│   ╰──> B TREE
138├──> B TREE
139│   ╰──> B TREE
140╰──> B TREE
141    ╰──> B TREE
142```
143<!--{ end }-->
144
145### Nested Functions
146
147Branches also make nested function calls a lot easier to follow.
148
149<!--{ nested.rs | code: rust }-->
150```rust
151use debug_tree::*;
152fn a() {
153    add_branch!("a");
154    b();
155    c();
156}
157fn b() {
158    add_branch!("b");
159    c();
160}
161fn c() {
162    add_branch!("c");
163    add_leaf!("Nothing to see here");
164}
165
166fn main() {
167    defer_write!("examples/out/nested.txt");
168    a();
169}
170```
171<!--{ end }-->
172<!--{ out/nested.txt | code }-->
173```
174a
175├╼ b
176│ └╼ c
177│   └╼ Nothing to see here
178└╼ c
179  └╼ Nothing to see here
180```
181<!--{ end }-->
182
183### Line Breaks
184
185Newlines in multi-line strings are automatically indented.
186
187<!--{ multi_line.rs | code: rust }-->
188```rust
189use debug_tree::*;
190fn main() {
191    // output to file at the end of this block
192    defer_write!("examples/out/multi_line.txt");
193    add_branch!("1");
194    add_leaf!("1.1\nAnother line...\n... and one more line");
195    add_leaf!("1.2");
196}
197```
198<!--{ end }-->
199
200<!--{ out/multi_line.txt | code }-->
201```
2021
203├╼ 1.1
204│  Another line...
205│  ... and one more line
206└╼ 1.2
207```
208<!--{ end }-->
209
210### Panics
211Even if there is a panic, the tree is not lost!
212The `defer_` functions were introduced to allow the tree
213to be printed our written to file in the case of a `panic!` or early return.
214
215<!--{ panic.rs | code: rust }-->
216```rust
217use debug_tree::*;
218
219fn i_will_panic() {
220    add_branch!("Here are my last words");
221    add_leaf!("Stay calm, and try not to panic");
222    panic!("I told you so...")
223}
224
225fn main() {
226    // output to file at the end of this block
227    defer_write!("examples/out/panic.txt");
228    // print at the end of this block
229    {
230        add_branch!("By using the 'defer_' functions");
231        add_branch!("Output will still be generated");
232        add_branch!("Otherwise you might lose your valuable tree!");
233    }
234    add_branch!("Now for something crazy...");
235    i_will_panic();
236}
237```
238<!--{ end }-->
239
240<!--{ out/panic.txt | code }-->
241```
242By using the 'defer_' functions
243└╼ Output will still be generated
244  └╼ Otherwise you might lose your valuable tree!
245Now for something crazy...
246└╼ Here are my last words
247  └╼ Stay calm, and try not to panic
248```
249<!--{ end }-->
250
251
252### Without Macros
253
254If you prefer not using macros, you can construct `TreeBuilder`s manually.
255
256<!--{ no_macros.rs | code: rust }-->
257```rust
258use debug_tree::TreeBuilder;
259
260fn main() {
261    // Make a new tree.
262    let tree = TreeBuilder::new();
263
264    // Add a scoped branch. The next item added will belong to the branch.
265    let mut branch = tree.add_branch("1 Branch");
266
267    // Add a leaf to the current branch
268    tree.add_leaf("1.1 Child");
269
270    // Leave scope early
271    branch.release();
272    tree.add_leaf("2 Sibling");
273    // output to file
274    tree.write("examples/out/no_macros.txt").ok(); // Write and flush.
275}
276```
277<!--{ end }-->
278<!--{ out/no_macros.txt | code }-->
279```
2801 Branch
281└╼ 1.1 Child
2822 Sibling
283```
284<!--{ end }-->