Pretty Print Tree in Rust
The following snippet is a simple function for pretty printing trees and other hierarchical data, such as HTML and ASTs.
There's also a version written in Python.
Output Example
`- Root
|- Node 1
| |- Node 1.1
| | `- Node 1.1.1
| | |- Node 1.1.1.1
| | `- Node 1.1.1.2
| |- Node 1.2
| |- Node 1.3
| | `- Node 1.3.1
| `- Node 1.4
| |- Node 1.4.1
| `- Node 1.4.2
| |- Node 1.4.2.1
| `- Node 1.4.2.2
| `- Node 1.4.2.2.1
|- Node 2
| |- Node 2.1
| `- Node 2.2
`- Node 3
Snippet
The pprint_tree
function is implemented using an inner function as a way to hide temporary parameters from the user. The pprint_tree
function requires something that implements std::fmt::Display
as well as providing a children
field of type Vec<Node>
. In the complete example, Node
is implemented as a struct, but could be implemented as a trait.
fn pprint_tree(node: &Node) {
fn pprint_tree(node: &Node, prefix: String, last: bool) {
let prefix_current = if last { "`- " } else { "|- " };
println!("{}{}{}", prefix, prefix_current, node);
let prefix_child = if last { " " } else { "| " };
let prefix = prefix + prefix_child;
if !node.children.is_empty() {
let last_child = node.children.len() - 1;
for (i, child) in node.children.iter().enumerate() {
pprint_tree(&child, prefix.to_string(), i == last_child);
}
}
}
pprint_tree(node, "".to_string(), true);
}
Complete Example
use std::fmt;
struct Node {
name: &'static str,
children: Vec<Node>,
}
impl Node {
fn new(name: &'static str, children: Vec<Node>) -> Node {
Node { name, children }
}
}
impl fmt::Display for Node {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
}
fn pprint_tree(node: &Node) {
fn pprint_tree(node: &Node, prefix: String, last: bool) {
let prefix_current = if last { "`- " } else { "|- " };
println!("{}{}{}", prefix, prefix_current, node);
let prefix_child = if last { " " } else { "| " };
let prefix = prefix + prefix_child;
if !node.children.is_empty() {
let last_child = node.children.len() - 1;
for (i, child) in node.children.iter().enumerate() {
pprint_tree(&child, prefix.to_string(), i == last_child);
}
}
}
pprint_tree(node, "".to_string(), true);
}
fn main() {
let tree = Node::new("Root", vec![
Node::new("Node 1", vec![
Node::new("Node 1.1", vec![
Node::new("Node 1.1.1", vec![
Node::new("Node 1.1.1.1", vec![]),
Node::new("Node 1.1.1.2", vec![]),
]),
]),
Node::new("Node 1.2", vec![]),
Node::new("Node 1.3", vec![
Node::new("Node 1.3.1", vec![]),
]),
Node::new("Node 1.4", vec![
Node::new("Node 1.4.1", vec![]),
Node::new("Node 1.4.2", vec![
Node::new("Node 1.4.2.1", vec![]),
Node::new("Node 1.4.2.2", vec![
Node::new("Node 1.4.2.2.1", vec![]),
]),
]),
]),
]),
Node::new("Node 2", vec![
Node::new("Node 2.1", vec![]),
Node::new("Node 2.2", vec![]),
]),
Node::new("Node 3", vec![]),
]);
pprint_tree(&tree);
}