diff options
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f0d2fd5 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,85 @@ +// Copyright (c) 2018 The predicates-rs Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/license/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Render `Case` as a tree. + +use std::fmt; + +use predicates_core::reflection; + +/// Render `Self` as a displayable tree. +pub trait CaseTreeExt { + /// Render `Self` as a displayable tree. + fn tree(&self) -> CaseTree; +} + +impl<'a> CaseTreeExt for reflection::Case<'a> { + fn tree(&self) -> CaseTree { + CaseTree(convert(self)) + } +} + +type CaseTreeInner = termtree::Tree<Displayable>; + +fn convert(case: &reflection::Case<'_>) -> CaseTreeInner { + let mut leaves: Vec<CaseTreeInner> = vec![]; + + leaves.extend(case.predicate().iter().flat_map(|pred| { + pred.parameters().map(|item| { + let root = Displayable::new(&item); + termtree::Tree::new(root).with_multiline(true) + }) + })); + + leaves.extend(case.products().map(|item| { + let root = Displayable::new(item); + termtree::Tree::new(root).with_multiline(true) + })); + + leaves.extend(case.children().map(convert)); + + let root = case + .predicate() + .map(|p| Displayable::new(&p)) + .unwrap_or_default(); + CaseTreeInner::new(root).with_leaves(leaves) +} + +/// A `Case` rendered as a tree for display. +#[allow(missing_debug_implementations)] +pub struct CaseTree(CaseTreeInner); + +impl fmt::Display for CaseTree { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[derive(Default)] +struct Displayable { + primary: String, + alternate: String, +} + +impl Displayable { + fn new(display: &dyn std::fmt::Display) -> Self { + let primary = format!("{}", display); + let alternate = format!("{:#}", display); + Self { primary, alternate } + } +} + +impl fmt::Display for Displayable { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if f.alternate() { + self.alternate.fmt(f) + } else { + self.primary.fmt(f) + } + } +} |