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
11use std::fmt;
12
13use predicates_core::reflection;
14
15/// Render `Self` as a displayable tree.
16pub trait CaseTreeExt {
17 /// Render `Self` as a displayable tree.
18 fn tree(&self) -> CaseTree;
19}
20
21impl<'a> CaseTreeExt for reflection::Case<'a> {
22 fn tree(&self) -> CaseTree {
23 CaseTree(convert(self))
24 }
25}
26
27type CaseTreeInner = termtree::Tree<Displayable>;
28
29fn 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)]
55pub struct CaseTree(CaseTreeInner);
56
57impl fmt::Display for CaseTree {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 self.0.fmt(f)
60 }
61}
62
63#[derive(Default)]
64struct Displayable {
65 primary: String,
66 alternate: String,
67}
68
69impl Displayable {
70 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
77impl fmt::Display for Displayable {
78 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