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