1 // Copyright (c) 2018 The predicates-rs Project Developers.
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // http://www.apache.org/license/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8
9 //! Render `Case` as a tree.
10
11 #![cfg_attr(docsrs, feature(doc_auto_cfg))]
12
13 use std::fmt;
14
15 use predicates_core::reflection;
16
17 /// Render `Self` as a displayable tree.
18 pub trait CaseTreeExt {
19 /// Render `Self` as a displayable tree.
tree(&self) -> CaseTree20 fn tree(&self) -> CaseTree;
21 }
22
23 impl<'a> CaseTreeExt for reflection::Case<'a> {
tree(&self) -> CaseTree24 fn tree(&self) -> CaseTree {
25 CaseTree(convert(self))
26 }
27 }
28
29 type CaseTreeInner = termtree::Tree<Displayable>;
30
convert(case: &reflection::Case<'_>) -> CaseTreeInner31 fn convert(case: &reflection::Case<'_>) -> CaseTreeInner {
32 let mut leaves: Vec<CaseTreeInner> = vec![];
33
34 leaves.extend(case.predicate().iter().flat_map(|pred| {
35 pred.parameters().map(|item| {
36 let root = Displayable::new(&item);
37 termtree::Tree::new(root).with_multiline(true)
38 })
39 }));
40
41 leaves.extend(case.products().map(|item| {
42 let root = Displayable::new(item);
43 termtree::Tree::new(root).with_multiline(true)
44 }));
45
46 leaves.extend(case.children().map(convert));
47
48 let root = case
49 .predicate()
50 .map(|p| Displayable::new(&p))
51 .unwrap_or_default();
52 CaseTreeInner::new(root).with_leaves(leaves)
53 }
54
55 /// A `Case` rendered as a tree for display.
56 #[allow(missing_debug_implementations)]
57 pub struct CaseTree(CaseTreeInner);
58
59 impl fmt::Display for CaseTree {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 self.0.fmt(f)
62 }
63 }
64
65 #[derive(Default)]
66 struct Displayable {
67 primary: String,
68 alternate: String,
69 }
70
71 impl Displayable {
new(display: &dyn std::fmt::Display) -> Self72 fn new(display: &dyn std::fmt::Display) -> Self {
73 let primary = format!("{}", display);
74 let alternate = format!("{:#}", display);
75 Self { primary, alternate }
76 }
77 }
78
79 impl fmt::Display for Displayable {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 if f.alternate() {
82 self.alternate.fmt(f)
83 } else {
84 self.primary.fmt(f)
85 }
86 }
87 }
88