webrender/
print_tree.rs

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
5use std::io::Write;
6use std::fmt::Write as FmtWrite;
7
8/// A struct that makes it easier to print out a pretty tree of data, which
9/// can be visually scanned more easily.
10pub struct PrintTree<W>
11where
12    W: Write
13{
14    /// The current level of recursion.
15    level: u32,
16
17    /// An item which is queued up, so that we can determine if we need
18    /// a mid-tree prefix or a branch ending prefix.
19    queued_item: Option<String>,
20
21    // We hold lines until they are done, and then output them all at
22    // once
23    line_buffer: String,
24
25    /// The sink to print to.
26    sink: W,
27}
28
29/// A trait that makes it easy to describe a pretty tree of data,
30/// regardless of the printing destination, to either print it
31/// directly to stdout, or serialize it as in the debugger
32pub trait PrintTreePrinter {
33    fn new_level(&mut self, title: String);
34    fn end_level(&mut self);
35    fn add_item(&mut self, text: String);
36}
37
38// The default does nothing but log
39impl PrintTree<std::io::Sink> {
40    pub fn new(title: &str) -> Self {
41        PrintTree::new_with_sink(title, std::io::sink())
42    }
43}
44
45impl<W> PrintTree<W>
46where
47    W: Write
48{
49    pub fn new_with_sink(title: &str, sink: W) -> Self {
50        let mut result = PrintTree {
51            level: 1,
52            queued_item: None,
53            line_buffer: String::new(),
54            sink,
55        };
56
57        writeln!(result.line_buffer, "\u{250c} {}", title).unwrap();
58        result.flush_line();
59        result
60    }
61
62    fn print_level_prefix(&mut self) {
63        for _ in 0 .. self.level {
64            write!(self.line_buffer, "\u{2502}  ").unwrap();
65        }
66    }
67
68    fn flush_queued_item(&mut self, prefix: &str) {
69        if let Some(queued_item) = self.queued_item.take() {
70            self.print_level_prefix();
71            writeln!(self.line_buffer, "{} {}", prefix, queued_item).unwrap();
72            self.flush_line();
73        }
74    }
75
76    fn flush_line(&mut self) {
77        debug!("{}", self.line_buffer);
78        self.sink.write_all(self.line_buffer.as_bytes()).unwrap();
79        self.line_buffer.clear();
80    }
81}
82
83impl<W> PrintTreePrinter for PrintTree<W>
84where
85    W: Write
86{
87    /// Descend one level in the tree with the given title.
88    fn new_level(&mut self, title: String) {
89        self.flush_queued_item("\u{251C}\u{2500}");
90
91        self.print_level_prefix();
92        writeln!(self.line_buffer, "\u{251C}\u{2500} {}", title).unwrap();
93        self.flush_line();
94
95        self.level = self.level + 1;
96    }
97
98    /// Ascend one level in the tree.
99    fn end_level(&mut self) {
100        self.flush_queued_item("\u{2514}\u{2500}");
101        self.level = self.level - 1;
102    }
103
104    /// Add an item to the current level in the tree.
105    fn add_item(&mut self, text: String) {
106        self.flush_queued_item("\u{251C}\u{2500}");
107        self.queued_item = Some(text);
108    }
109}
110
111impl<W> Drop for PrintTree<W>
112where
113    W: Write
114{
115    fn drop(&mut self) {
116        self.flush_queued_item("\u{9492}\u{9472}");
117    }
118}
119
120pub trait PrintableTree {
121    fn print_with<T: PrintTreePrinter>(&self, pt: &mut T);
122}