log_tree/
lib.rs

1#![doc = include_str!("../README.md")]
2
3pub type Childs<'a, T> = Box<dyn AsRef<[T]> + 'a>;
4
5
6pub trait LogTree: Sized {
7    /// Add a node to the tree.
8    /// 
9    /// - Returns `None` if the node should not be added.
10    /// - Returns `Some((key, childs))` if the node should be added.
11    /// - where `childs` can be empty, if the node is a leaf node.
12    /// 
13    /// The `lvl` parameter is the depth of the node in the tree.
14    fn add_node(&self, lvl: u8) -> Option<(String, Childs<Self>)>;
15
16    ///  Decorators is an array of 4 strings, used to decorate the tree.
17    fn decorators(&self, lvl: u8) -> [&str; 4] {
18        match lvl {
19            0 => ["├─╼ ", "│  ", "└─╼ ", "   "],
20            _ => ["├─> ", "│  ", "╰─> ", "   "],
21        }
22    }
23
24    /// format the tree, and return the formatted string.
25    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    /// Same as fmt_tree, but return the formatted string as child of tree.
39    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}