use std::fmt::Write;
use crate::types::ParameterCollection;
#[derive(Debug, Clone, Default)]
pub struct DumpOptions {
pub show_keys: bool,
}
#[derive(Default)]
pub struct TreeBuilder {
output: String,
indent_stack: Vec<bool>, options: DumpOptions,
}
impl TreeBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_options(options: DumpOptions) -> Self {
Self {
options,
..Self::default()
}
}
pub fn options(&self) -> &DumpOptions {
&self.options
}
pub fn show_keys(&self) -> bool {
self.options.show_keys
}
fn prefix(&self) -> String {
let mut s = String::new();
for (i, &has_more) in self.indent_stack.iter().enumerate() {
if i == self.indent_stack.len() - 1 {
if has_more {
s.push_str("├── ");
} else {
s.push_str("└── ");
}
} else if has_more {
s.push_str("│ ");
} else {
s.push_str(" ");
}
}
s
}
fn continuation_prefix(&self) -> String {
let mut s = String::new();
for &has_more in &self.indent_stack {
if has_more {
s.push_str("│ ");
} else {
s.push_str(" ");
}
}
s
}
pub fn begin_node(&mut self, title: &str) {
let prefix = self.prefix();
writeln!(&mut self.output, "{}{}", prefix, title).expect("writing to String cannot fail");
}
pub fn add_leaf(&mut self, title: &str, props: &[(&str, String)]) {
let prefix = self.prefix();
if props.is_empty() {
writeln!(&mut self.output, "{}{}", prefix, title)
.expect("writing to String cannot fail");
} else {
writeln!(&mut self.output, "{}{}", prefix, title)
.expect("writing to String cannot fail");
let cont = self.continuation_prefix();
for (name, value) in props {
writeln!(&mut self.output, "{} {} = {}", cont, name, value)
.expect("writing to String cannot fail");
}
}
}
pub fn add_leaf_with_params(
&mut self,
title: &str,
props: &[(&str, String)],
params: Option<&ParameterCollection>,
) {
let prefix = self.prefix();
writeln!(&mut self.output, "{}{}", prefix, title).expect("writing to String cannot fail");
let cont = self.continuation_prefix();
for (name, value) in props {
writeln!(&mut self.output, "{} {} = {}", cont, name, value)
.expect("writing to String cannot fail");
}
if self.options.show_keys {
if let Some(params) = params {
writeln!(&mut self.output, "{} [all keys]", cont)
.expect("writing to String cannot fail");
for (key, value) in params.iter() {
writeln!(
&mut self.output,
"{} {} = {}",
cont,
key,
value.as_str()
)
.expect("writing to String cannot fail");
}
}
}
}
pub fn push(&mut self, has_more_siblings: bool) {
self.indent_stack.push(has_more_siblings);
}
pub fn pop(&mut self) {
self.indent_stack.pop();
}
pub fn root(&mut self, title: &str) {
writeln!(&mut self.output, "{}", title).expect("writing to String cannot fail");
}
pub fn finish(self) -> String {
self.output
}
}
pub trait DumpTree {
fn dump(&self, tree: &mut TreeBuilder);
fn dump_to_string(&self) -> String {
let mut tree = TreeBuilder::new();
self.dump(&mut tree);
tree.finish()
}
fn dump_to_string_with_options(&self, options: DumpOptions) -> String {
let mut tree = TreeBuilder::with_options(options);
self.dump(&mut tree);
tree.finish()
}
}
pub fn fmt_coord(raw: i32) -> String {
let mils = raw as f64 / 10000.0;
if mils == mils.trunc() {
format!("{:.0} mil", mils)
} else {
format!("{:.2} mil", mils)
}
}
pub fn fmt_point(x: i32, y: i32) -> String {
format!("({}, {})", fmt_coord(x), fmt_coord(y))
}
pub fn fmt_coord_point(pt: &crate::types::CoordPoint) -> String {
fmt_point(pt.x.to_raw(), pt.y.to_raw())
}
pub fn fmt_coord_val(c: &crate::types::Coord) -> String {
fmt_coord(c.to_raw())
}
pub fn fmt_angle(degrees: f64) -> String {
format!("{:.1}°", degrees)
}
pub fn fmt_layer(layer: &crate::types::Layer) -> String {
layer.name().to_string()
}
pub fn fmt_bool(b: bool) -> String {
if b {
"yes".to_string()
} else {
"no".to_string()
}
}