• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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