diff --git a/Cargo.toml b/Cargo.toml index 7865d7f..72a2f96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,9 @@ difference = { version = "2.0", optional = true } normalize-line-endings = { version = "0.2.2", optional = true } regex = { version="1.0", optional = true } float-cmp = { version="0.4", optional = true } +treeline = { version = "0.1", optional = true } [features] -default = ["difference", "regex", "float-cmp", "normalize-line-endings"] +default = ["difference", "regex", "float-cmp", "normalize-line-endings", "tree"] unstable = [] +tree = ["treeline",] diff --git a/examples/case_tree.rs b/examples/case_tree.rs new file mode 100644 index 0000000..bcc6a6f --- /dev/null +++ b/examples/case_tree.rs @@ -0,0 +1,15 @@ +extern crate predicates; + +use predicates::prelude::*; +use predicates::tree::CaseTreeExt; + +fn main() { + let pred = predicate::ne(5).not().and(predicate::ge(5)); + + let var = 5; + let case = pred.find_case(true, &var); + if let Some(case) = case { + println!("var is {}", var); + println!("{}", case.tree()); + } +} diff --git a/src/lib.rs b/src/lib.rs index a98561b..a29e03b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,6 +100,8 @@ extern crate float_cmp; extern crate normalize_line_endings; #[cfg(feature = "regex")] extern crate regex; +#[cfg(feature = "treeline")] +extern crate treeline; pub mod prelude; @@ -123,3 +125,5 @@ pub mod boolean; pub mod float; pub mod path; pub mod str; +#[cfg(feature = "tree")] +pub mod tree; diff --git a/src/tree.rs b/src/tree.rs new file mode 100644 index 0000000..5445a77 --- /dev/null +++ b/src/tree.rs @@ -0,0 +1,60 @@ +// Copyright (c) 2018 The predicates-rs Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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 treeline; + +use 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 = treeline::Tree>; + +fn convert<'a>(case: &reflection::Case<'a>) -> CaseTreeInner { + let mut leaves: Vec = vec![]; + + leaves.extend(case.predicate().iter().flat_map(|pred| { + pred.parameters().map(|item| { + let root: Box = Box::new(item.to_string()); + treeline::Tree::new(root, vec![]) + }) + })); + + leaves.extend(case.products().map(|item| { + let root: Box = Box::new(item.to_string()); + treeline::Tree::new(root, vec![]) + })); + + leaves.extend(case.children().map(|item| convert(item))); + + let root = Box::new(case.predicate().map(|p| p.to_string()).unwrap_or_default()); + CaseTreeInner::new(root, 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) + } +}