1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use std::io::{stdout, Stdout, Write};
6 
7 /// A struct that makes it easier to print out a pretty tree of data, which
8 /// can be visually scanned more easily.
9 pub struct PrintTree<W>
10 where
11     W: Write
12 {
13     /// The current level of recursion.
14     level: u32,
15 
16     /// An item which is queued up, so that we can determine if we need
17     /// a mid-tree prefix or a branch ending prefix.
18     queued_item: Option<String>,
19 
20     /// The sink to print to.
21     sink: W,
22 }
23 
24 /// A trait that makes it easy to describe a pretty tree of data,
25 /// regardless of the printing destination, to either print it
26 /// directly to stdout, or serialize it as in the debugger
27 pub trait PrintTreePrinter {
new_level(&mut self, title: String)28     fn new_level(&mut self, title: String);
end_level(&mut self)29     fn end_level(&mut self);
add_item(&mut self, text: String)30     fn add_item(&mut self, text: String);
31 }
32 
33 impl PrintTree<Stdout> {
new(title: &str) -> Self34     pub fn new(title: &str) -> Self {
35         PrintTree::new_with_sink(title, stdout())
36     }
37 }
38 
39 impl<W> PrintTree<W>
40 where
41     W: Write
42 {
new_with_sink(title: &str, mut sink: W) -> Self43     pub fn new_with_sink(title: &str, mut sink: W) -> Self {
44         writeln!(sink, "\u{250c} {}", title).unwrap();
45         PrintTree {
46             level: 1,
47             queued_item: None,
48             sink,
49         }
50     }
51 
print_level_prefix(&mut self)52     fn print_level_prefix(&mut self) {
53         for _ in 0 .. self.level {
54             write!(self.sink, "\u{2502}  ").unwrap();
55         }
56     }
57 
flush_queued_item(&mut self, prefix: &str)58     fn flush_queued_item(&mut self, prefix: &str) {
59         if let Some(queued_item) = self.queued_item.take() {
60             self.print_level_prefix();
61             writeln!(self.sink, "{} {}", prefix, queued_item).unwrap();
62         }
63     }
64 }
65 
66 // The default `println!` based printer
67 impl<W> PrintTreePrinter for PrintTree<W>
68 where
69     W: Write
70 {
71     /// Descend one level in the tree with the given title.
new_level(&mut self, title: String)72     fn new_level(&mut self, title: String) {
73         self.flush_queued_item("\u{251C}\u{2500}");
74 
75         self.print_level_prefix();
76         writeln!(self.sink, "\u{251C}\u{2500} {}", title).unwrap();
77 
78         self.level = self.level + 1;
79     }
80 
81     /// Ascend one level in the tree.
end_level(&mut self)82     fn end_level(&mut self) {
83         self.flush_queued_item("\u{2514}\u{2500}");
84         self.level = self.level - 1;
85     }
86 
87     /// Add an item to the current level in the tree.
add_item(&mut self, text: String)88     fn add_item(&mut self, text: String) {
89         self.flush_queued_item("\u{251C}\u{2500}");
90         self.queued_item = Some(text);
91     }
92 }
93 
94 impl<W> Drop for PrintTree<W>
95 where
96     W: Write
97 {
drop(&mut self)98     fn drop(&mut self) {
99         self.flush_queued_item("\u{9492}\u{9472}");
100     }
101 }
102 
103 pub trait PrintableTree {
print_with<T: PrintTreePrinter>(&self, pt: &mut T)104     fn print_with<T: PrintTreePrinter>(&self, pt: &mut T);
105 }
106