1#![doc = include_str!("../README.md")]
2
3pub type Childs<'a, T> = Box<dyn AsRef<[T]> + 'a>;
4
5
6pub trait LogTree: Sized {
7 fn add_node(&self, lvl: u8) -> Option<(String, Childs<Self>)>;
15
16 fn decorators(&self, lvl: u8) -> [&str; 4] {
18 match lvl {
19 0 => ["├─╼ ", "│ ", "└─╼ ", " "],
20 _ => ["├─> ", "│ ", "╰─> ", " "],
21 }
22 }
23
24 fn fmt_tree(&self) -> String {
26 let mut out = String::new();
27 if let Some((key, childs)) = self.add_node(0) {
28 out.push_str(&key);
29 let childs = childs.as_ref().as_ref();
30 let len = childs.len();
31 for (i, child) in childs.iter().enumerate() {
32 fmt_tree(String::new(), i == len - 1, child, &mut out, 0);
33 }
34 }
35 out
36 }
37
38 fn fmt_tree_node(&self, is_last: bool) -> String {
40 let mut out = String::new();
41 fmt_tree(String::new(), is_last, self, &mut out, 0);
42 out
43 }
44}
45
46fn fmt_tree(
47 mut prefix: String,
48 is_last: bool,
49 tree: &impl LogTree,
50 out: &mut String,
51 lvl: u8,
52) {
53 let decorators = tree.decorators(lvl);
54 out.push('\n');
55 out.push_str(&prefix);
56 prefix.push_str(match is_last {
57 false => {
58 out.push_str(decorators[0]);
59 decorators[1]
60 }
61 true => {
62 out.push_str(decorators[2]);
63 decorators[3]
64 }
65 });
66 if let Some((key, childs)) = tree.add_node(lvl) {
67 out.push_str(&key);
68 let childs = childs.as_ref().as_ref();
69 let len = childs.len();
70 for (i, child) in childs.iter().enumerate() {
71 fmt_tree(prefix.clone(), i == len - 1, child, out, lvl + 1);
72 }
73 }
74}