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 use std::fmt;
12 
13 use predicates_core::reflection;
14 
15 /// Render `Self` as a displayable tree.
16 pub trait CaseTreeExt {
17     /// Render `Self` as a displayable tree.
tree(&self) -> CaseTree18     fn tree(&self) -> CaseTree;
19 }
20 
21 impl<'a> CaseTreeExt for reflection::Case<'a> {
tree(&self) -> CaseTree22     fn tree(&self) -> CaseTree {
23         CaseTree(convert(self))
24     }
25 }
26 
27 type CaseTreeInner = termtree::Tree<Displayable>;
28 
convert(case: &reflection::Case<'_>) -> CaseTreeInner29 fn convert(case: &reflection::Case<'_>) -> CaseTreeInner {
30     let mut leaves: Vec<CaseTreeInner> = vec![];
31 
32     leaves.extend(case.predicate().iter().flat_map(|pred| {
33         pred.parameters().map(|item| {
34             let root = Displayable::new(&item);
35             termtree::Tree::new(root).with_multiline(true)
36         })
37     }));
38 
39     leaves.extend(case.products().map(|item| {
40         let root = Displayable::new(item);
41         termtree::Tree::new(root).with_multiline(true)
42     }));
43 
44     leaves.extend(case.children().map(convert));
45 
46     let root = case
47         .predicate()
48         .map(|p| Displayable::new(&p))
49         .unwrap_or_default();
50     CaseTreeInner::new(root).with_leaves(leaves)
51 }
52 
53 /// A `Case` rendered as a tree for display.
54 #[allow(missing_debug_implementations)]
55 pub struct CaseTree(CaseTreeInner);
56 
57 impl fmt::Display for CaseTree {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result58     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59         self.0.fmt(f)
60     }
61 }
62 
63 #[derive(Default)]
64 struct Displayable {
65     primary: String,
66     alternate: String,
67 }
68 
69 impl Displayable {
new(display: &dyn std::fmt::Display) -> Self70     fn new(display: &dyn std::fmt::Display) -> Self {
71         let primary = format!("{}", display);
72         let alternate = format!("{:#}", display);
73         Self { primary, alternate }
74     }
75 }
76 
77 impl fmt::Display for Displayable {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result78     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79         if f.alternate() {
80             self.alternate.fmt(f)
81         } else {
82             self.primary.fmt(f)
83         }
84     }
85 }
86