treeline/
lib.rs

1use std::fmt::{self, Display};
2
3/// a simple recursive type which is able to render its
4/// components in a tree-like format
5#[derive(Debug)]
6pub struct Tree<D: Display>(D, Vec<Tree<D>>);
7
8impl<D: Display> Tree<D> {
9    pub fn new(root: D, leaves: Vec<Tree<D>>) -> Tree<D> {
10        Tree(root, leaves)
11    }
12
13    pub fn root(root: D) -> Tree<D> {
14        Tree(root, Vec::new())
15    }
16
17    pub fn push(&mut self, leaf: Tree<D>) -> &mut Self {
18        self.1.push(leaf);
19        self
20    }
21
22    fn display_leaves(f: &mut fmt::Formatter,
23                      leaves: &Vec<Tree<D>>,
24                      spaces: Vec<bool>)
25                      -> fmt::Result {
26        for (i, leaf) in leaves.iter().enumerate() {
27            let last = i >= leaves.len() - 1;
28            let mut clone = spaces.clone();
29            // print single line
30            for s in &spaces {
31                if *s {
32                    let _ = write!(f, "    ");
33                } else {
34                    let _ = write!(f, "|   ");
35                }
36            }
37            if last {
38                let _ = writeln!(f, "└── {}", leaf.0);
39            } else {
40                let _ = writeln!(f, "├── {}", leaf.0);
41            }
42
43            // recurse
44            if !leaf.1.is_empty() {
45                clone.push(last);
46                let _ = Self::display_leaves(f, &leaf.1, clone);
47            }
48        }
49        write!(f, "")
50    }
51}
52
53impl<D: Display> Display for Tree<D> {
54    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55        let _ = writeln!(f, "{}", self.0);
56        Self::display_leaves(f, &self.1, Vec::new())
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::Tree;
63    #[test]
64    fn render_tree_root() {
65        let tree = Tree::root("foo");
66        assert_eq!(format!("{}", tree), "foo\n")
67    }
68
69    #[test]
70    fn render_tree_with_leaves() {
71        let tree = Tree::new(
72            "foo", vec![
73               Tree::new(
74                   "bar", vec![
75                    Tree::root("baz")
76                   ]
77               )
78            ]
79        );
80        assert_eq!(format!("{}", tree), r#"foo
81└── bar
82    └── baz
83"#)
84    }
85}