1use std::fmt::Write;
7
8use crate::types::ParameterCollection;
9
10#[derive(Debug, Clone, Default)]
12pub struct DumpOptions {
13 pub show_keys: bool,
15}
16
17#[derive(Default)]
19pub struct TreeBuilder {
20 output: String,
21 indent_stack: Vec<bool>, options: DumpOptions,
23}
24
25impl TreeBuilder {
26 pub fn new() -> Self {
28 Self::default()
29 }
30
31 pub fn with_options(options: DumpOptions) -> Self {
33 Self {
34 options,
35 ..Self::default()
36 }
37 }
38
39 pub fn options(&self) -> &DumpOptions {
41 &self.options
42 }
43
44 pub fn show_keys(&self) -> bool {
46 self.options.show_keys
47 }
48
49 fn prefix(&self) -> String {
51 let mut s = String::new();
52 for (i, &has_more) in self.indent_stack.iter().enumerate() {
53 if i == self.indent_stack.len() - 1 {
54 if has_more {
55 s.push_str("├── ");
56 } else {
57 s.push_str("└── ");
58 }
59 } else if has_more {
60 s.push_str("│ ");
61 } else {
62 s.push_str(" ");
63 }
64 }
65 s
66 }
67
68 fn continuation_prefix(&self) -> String {
70 let mut s = String::new();
71 for &has_more in &self.indent_stack {
72 if has_more {
73 s.push_str("│ ");
74 } else {
75 s.push_str(" ");
76 }
77 }
78 s
79 }
80
81 pub fn begin_node(&mut self, title: &str) {
83 let prefix = self.prefix();
84 writeln!(&mut self.output, "{}{}", prefix, title).expect("writing to String cannot fail");
85 }
86
87 pub fn add_leaf(&mut self, title: &str, props: &[(&str, String)]) {
89 let prefix = self.prefix();
90 if props.is_empty() {
91 writeln!(&mut self.output, "{}{}", prefix, title)
92 .expect("writing to String cannot fail");
93 } else {
94 writeln!(&mut self.output, "{}{}", prefix, title)
95 .expect("writing to String cannot fail");
96 let cont = self.continuation_prefix();
97 for (name, value) in props {
98 writeln!(&mut self.output, "{} {} = {}", cont, name, value)
99 .expect("writing to String cannot fail");
100 }
101 }
102 }
103
104 pub fn add_leaf_with_params(
109 &mut self,
110 title: &str,
111 props: &[(&str, String)],
112 params: Option<&ParameterCollection>,
113 ) {
114 let prefix = self.prefix();
115 writeln!(&mut self.output, "{}{}", prefix, title).expect("writing to String cannot fail");
116 let cont = self.continuation_prefix();
117
118 for (name, value) in props {
120 writeln!(&mut self.output, "{} {} = {}", cont, name, value)
121 .expect("writing to String cannot fail");
122 }
123
124 if self.options.show_keys {
126 if let Some(params) = params {
127 writeln!(&mut self.output, "{} [all keys]", cont)
128 .expect("writing to String cannot fail");
129 for (key, value) in params.iter() {
130 writeln!(
131 &mut self.output,
132 "{} {} = {}",
133 cont,
134 key,
135 value.as_str()
136 )
137 .expect("writing to String cannot fail");
138 }
139 }
140 }
141 }
142
143 pub fn push(&mut self, has_more_siblings: bool) {
145 self.indent_stack.push(has_more_siblings);
146 }
147
148 pub fn pop(&mut self) {
150 self.indent_stack.pop();
151 }
152
153 pub fn root(&mut self, title: &str) {
155 writeln!(&mut self.output, "{}", title).expect("writing to String cannot fail");
156 }
157
158 pub fn finish(self) -> String {
160 self.output
161 }
162}
163
164pub trait DumpTree {
166 fn dump(&self, tree: &mut TreeBuilder);
168
169 fn dump_to_string(&self) -> String {
171 let mut tree = TreeBuilder::new();
172 self.dump(&mut tree);
173 tree.finish()
174 }
175
176 fn dump_to_string_with_options(&self, options: DumpOptions) -> String {
178 let mut tree = TreeBuilder::with_options(options);
179 self.dump(&mut tree);
180 tree.finish()
181 }
182}
183
184pub fn fmt_coord(raw: i32) -> String {
186 let mils = raw as f64 / 10000.0;
187 if mils == mils.trunc() {
188 format!("{:.0} mil", mils)
189 } else {
190 format!("{:.2} mil", mils)
191 }
192}
193
194pub fn fmt_point(x: i32, y: i32) -> String {
196 format!("({}, {})", fmt_coord(x), fmt_coord(y))
197}
198
199pub fn fmt_coord_point(pt: &crate::types::CoordPoint) -> String {
201 fmt_point(pt.x.to_raw(), pt.y.to_raw())
202}
203
204pub fn fmt_coord_val(c: &crate::types::Coord) -> String {
206 fmt_coord(c.to_raw())
207}
208
209pub fn fmt_angle(degrees: f64) -> String {
211 format!("{:.1}°", degrees)
212}
213
214pub fn fmt_layer(layer: &crate::types::Layer) -> String {
216 layer.name().to_string()
217}
218
219pub fn fmt_bool(b: bool) -> String {
221 if b {
222 "yes".to_string()
223 } else {
224 "no".to_string()
225 }
226}