1#![allow(clippy::branches_sharing_code)]
2
3#[cfg(test)]
4mod tests;
5
6use std::collections::VecDeque;
7use std::fmt::{self, Display};
8use std::marker::PhantomData;
9use std::rc::Rc;
10use std::fmt::Write;
11
12pub trait Direction {
13
14}
15
16#[derive(Clone, Copy)]
17pub struct Up;
18
19#[derive(Clone, Copy)]
20pub struct Down;
21
22impl Direction for Up {
23
24}
25impl Direction for Down {
26
27}
28
29
30#[derive(Debug, Clone)]
33pub struct Tree<D: Display, V: Direction> {
34 pub root: D,
35 pub leaves: Vec<Tree<D, V>>,
36 multiline: bool,
37 glyphs: GlyphPalette,
38 _dir: PhantomData<V>,
39}
40
41impl<D: Display, V: Direction> Tree<D, V> {
42 pub fn new(root: D) -> Self {
43 Tree {
44 root,
45 leaves: Vec::new(),
46 multiline: false,
47 glyphs: GlyphPalette::new(),
48 _dir: PhantomData,
49 }
50 }
51
52 pub fn with_leaves(mut self, leaves: impl IntoIterator<Item = impl Into<Tree<D, V>>>) -> Self {
53 self.leaves = leaves.into_iter().map(Into::into).collect();
54 self
55 }
56
57 pub fn with_multiline(mut self, yes: bool) -> Self {
59 self.multiline = yes;
60 self
61 }
62
63 pub fn with_glyphs(mut self, glyphs: GlyphPalette) -> Self {
65 self.glyphs = glyphs;
66 self
67 }
68}
69
70impl<D: Display, V: Direction> Tree<D, V> {
71 pub fn set_multiline(&mut self, yes: bool) -> &mut Self {
73 self.multiline = yes;
74 self
75 }
76
77 pub fn set_glyphs(&mut self, glyphs: GlyphPalette) -> &mut Self {
79 self.glyphs = glyphs;
80 self
81 }
82}
83
84impl<D: Display, V: Direction> Tree<D, V> {
85 pub fn push(&mut self, leaf: impl Into<Tree<D, V>>) -> &mut Self {
86 self.leaves.push(leaf.into());
87 self
88 }
89}
90
91impl<D: Display, V: Direction> From<D> for Tree<D, V> {
92 fn from(inner: D) -> Self {
93 Self::new(inner)
94 }
95}
96
97impl<D: Display, V: Direction> Extend<D> for Tree<D, V> {
98 fn extend<T: IntoIterator<Item = D>>(&mut self, iter: T) {
99 self.leaves.extend(iter.into_iter().map(Into::into))
100 }
101}
102
103impl<D: Display, V: Direction> Extend<Tree<D, V>> for Tree<D, V> {
104 fn extend<T: IntoIterator<Item = Tree<D, V>>>(&mut self, iter: T) {
105 self.leaves.extend(iter)
106 }
107}
108
109fn print_leaf_down<D: Display>(
110 leaf: &Tree<D, Down>,
111 last: bool,
112 f: &mut fmt::Formatter,
113 spaces: &Rc<Vec<bool>>,
114 self_glyphs: &GlyphPalette,
115) -> fmt::Result{
116 let mut prefix = (
117 if last {
118 leaf.glyphs.last_item
119 } else {
120 leaf.glyphs.middle_item
121 },
122 leaf.glyphs.item_indent,
123 );
124
125 if leaf.multiline {
126 let rest_prefix = (
127 if last {
128 leaf.glyphs.last_skip
129 } else {
130 leaf.glyphs.middle_skip
131 },
132 leaf.glyphs.skip_indent,
133 );
134 debug_assert_eq!(prefix.0.chars().count(), rest_prefix.0.chars().count());
135 debug_assert_eq!(prefix.1.chars().count(), rest_prefix.1.chars().count());
136
137 let root = if f.alternate() {
138 format!("{:#}", leaf.root)
139 } else {
140 format!("{:}", leaf.root)
141 };
142 for line in root.lines() {
143 for s in spaces.as_slice() {
145 if *s {
146 self_glyphs.last_skip.fmt(f)?;
147 self_glyphs.skip_indent.fmt(f)?;
148 } else {
149 self_glyphs.middle_skip.fmt(f)?;
150 self_glyphs.skip_indent.fmt(f)?;
151 }
152 }
153 prefix.0.fmt(f)?;
154 prefix.1.fmt(f)?;
155 line.fmt(f)?;
156 writeln!(f)?;
157 prefix = rest_prefix;
158 }
159 } else {
160 for s in spaces.as_slice() {
162 if *s {
163 self_glyphs.last_skip.fmt(f)?;
164 self_glyphs.skip_indent.fmt(f)?;
165 } else {
166 self_glyphs.middle_skip.fmt(f)?;
167 self_glyphs.skip_indent.fmt(f)?;
168 }
169 }
170 prefix.0.fmt(f)?;
171 prefix.1.fmt(f)?;
172 leaf.root.fmt(f)?; writeln!(f)?;
174 }
175 Ok(())
176}
177
178impl<D: Display> Display for Tree<D, Down> {
179 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180 self.root.fmt(f)?; writeln!(f)?;
182 let mut queue = DisplauQueue::new();
183 let no_space = Rc::new(Vec::new());
184
185 enqueue_leaves(&mut queue, self, no_space);
186
187 while let Some((last, leaf, spaces)) = queue.pop_front() {
188 print_leaf_down(leaf, last, f, &spaces, &self.glyphs)?;
189 if !leaf.leaves.is_empty() {
191
192 let s: &Vec<bool> = &spaces;
193 let mut child_spaces = s.clone();
194 child_spaces.push(last);
195 let child_spaces = Rc::new(child_spaces);
196
197 enqueue_leaves(&mut queue, leaf, child_spaces);
198 }
199 }
200 Ok(())
201 }
202}
203
204fn print_leaf_up<D: Display>(
205 leaf: &Tree<D, Up>,
206 last: bool,
207 ask_fmt: &mut fmt::Formatter,
208 spaces: &Rc<Vec<bool>>,
209 self_glyphs: &GlyphPalette,
210) -> Result<String, std::fmt::Error>{
211 let mut result = String::new();
212 let mut prefix = (
213 if last {
214 leaf.glyphs.last_item_up
215 } else {
216 leaf.glyphs.middle_item
217 },
218 leaf.glyphs.item_indent,
219 );
220
221 if leaf.multiline {
222 let rest_prefix = (
223 leaf.glyphs.middle_skip,
224 leaf.glyphs.skip_indent,
225 );
226 debug_assert_eq!(prefix.0.chars().count(), rest_prefix.0.chars().count());
227 debug_assert_eq!(prefix.1.chars().count(), rest_prefix.1.chars().count());
228
229 let root = if ask_fmt.alternate() {
230 format!("{:#}", leaf.root)
231 } else {
232 format!("{:}", leaf.root)
233 };
234 for line in root.lines() {
235 for s in spaces.as_slice() {
237 if *s {
238 write!(&mut result, "{}", format!("{}", self_glyphs.last_skip))?;
239 write!(&mut result, "{}", format!("{}", self_glyphs.skip_indent))?;
240 } else {
241 write!(&mut result, "{}", format!("{}", self_glyphs.middle_skip))?;
242 write!(&mut result, "{}", format!("{}", self_glyphs.skip_indent))?;
243 }
244 }
245 write!(&mut result, "{}", format!("{}", prefix.0))?;
246 write!(&mut result, "{}", format!("{}", prefix.1))?;
247 write!(&mut result, "{}", format!("{}", line))?;
248 writeln!(&mut result)?;
249 prefix = rest_prefix;
250 }
251 } else {
252 for s in spaces.as_slice() {
254 if *s {
255 write!(&mut result, "{}", format!("{}", self_glyphs.last_skip))?;
256 write!(&mut result, "{}", format!("{}", self_glyphs.skip_indent))?;
257 } else {
258 write!(&mut result, "{}", format!("{}", self_glyphs.middle_skip))?;
259 write!(&mut result, "{}", format!("{}", self_glyphs.skip_indent))?;
260 }
261 }
262
263 write!(&mut result, "{}", format!("{}", prefix.0))?;
264 write!(&mut result, "{}", format!("{}", prefix.1))?;
265 write!(&mut result, "{}", format!("{}", leaf.root))?;
266 writeln!(&mut result)?;
267
268 }
269 Ok(result)
270}
271
272impl<D: Display> Display for Tree<D, Up> {
273 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
274 let mut queue = DisplauQueue::new();
275 let no_space = Rc::new(Vec::new());
276
277 let mut deque = VecDeque::new();
278 let first = format!("{}\n", self.root);
279 deque.push_back(first);
280
281 enqueue_leaves(&mut queue, self.clone(), no_space);
282
283 while let Some((last, leaf, spaces)) = queue.pop_front() {
284 let leaf_printed = print_leaf_up(leaf, last, f, &spaces, &self.glyphs)?;
285 deque.push_back(leaf_printed);
286 if !leaf.leaves.is_empty() {
288
289 let s: &Vec<bool> = &spaces;
290 let mut child_spaces = s.clone();
291 child_spaces.push(last);
292 let child_spaces = Rc::new(child_spaces);
293
294 enqueue_leaves(&mut queue, leaf, child_spaces);
295 }
296 }
297
298 while let Some(write) = deque.pop_back() {
299 write!(f, "{}", write)?;
300
301 }
302 Ok(())
303 }
304}
305
306type DisplauQueue<'t, D, V> = VecDeque<(bool, &'t Tree<D, V>, Rc<Vec<bool>>)>;
307
308fn enqueue_leaves<'t, D: Display, V: Direction>(
309 queue: &mut DisplauQueue<'t, D, V>,
310 parent: &'t Tree<D, V>,
311 spaces: Rc<Vec<bool>>,
312) {
313 for (i, leaf) in parent.leaves.iter().rev().enumerate() {
314 let last = i == 0;
315 queue.push_front((last, leaf, spaces.clone()));
316 }
317}
318
319
320
321#[derive(Copy, Clone, Debug, PartialEq, Eq)]
322pub struct GlyphPalette {
323 pub middle_item: &'static str,
324 pub last_item: &'static str,
325 pub last_item_up: &'static str,
326 pub item_indent: &'static str,
327
328 pub middle_skip: &'static str,
329 pub last_skip: &'static str,
330 pub skip_indent: &'static str,
331}
332
333impl GlyphPalette {
334 pub const fn new() -> Self {
335 Self {
336 middle_item: "├",
337 last_item: "└",
338 last_item_up: "┌",
339 item_indent: "── ",
340
341 middle_skip: "│",
342 last_skip: " ",
343 skip_indent: " ",
344 }
345 }
346}
347
348impl Default for GlyphPalette {
349 fn default() -> Self {
350 Self::new()
351 }
352}