diff options
Diffstat (limited to 'src/reflection.rs')
-rw-r--r-- | src/reflection.rs | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/src/reflection.rs b/src/reflection.rs new file mode 100644 index 0000000..120d1bd --- /dev/null +++ b/src/reflection.rs @@ -0,0 +1,252 @@ +// Copyright (c) 2018 The predicates-rs Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/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. + +//! Introspect into the state of a `Predicate`. + +use std::borrow; +use std::fmt; +use std::slice; + +/// Introspect the state of a `Predicate`. +pub trait PredicateReflection: fmt::Display { + /// Parameters of the current `Predicate`. + fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = Parameter<'a>> + 'a> { + let params = vec![]; + Box::new(params.into_iter()) + } + + /// Nested `Predicate`s of the current `Predicate`. + fn children<'a>(&'a self) -> Box<dyn Iterator<Item = Child<'a>> + 'a> { + let params = vec![]; + Box::new(params.into_iter()) + } +} + +/// A view of a `Predicate` parameter, provided by reflection. +/// +/// ```rust +/// use predicates_core; +/// +/// let param = predicates_core::reflection::Parameter::new("key", &10); +/// println!("{}", param); +/// ``` +pub struct Parameter<'a>(&'a str, &'a dyn fmt::Display); + +impl<'a> Parameter<'a> { + /// Create a new `Parameter`. + pub fn new(key: &'a str, value: &'a dyn fmt::Display) -> Self { + Self(key, value) + } + + /// Access the `Parameter` name. + pub fn name(&self) -> &str { + self.0 + } + + /// Access the `Parameter` value. + pub fn value(&self) -> &dyn fmt::Display { + self.1 + } +} + +impl<'a> fmt::Display for Parameter<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}: {}", self.0, self.1) + } +} + +impl<'a> fmt::Debug for Parameter<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "({:?}, {})", self.0, self.1) + } +} + +/// A view of a `Predicate` child, provided by reflection. +pub struct Child<'a>(&'a str, &'a dyn PredicateReflection); + +impl<'a> Child<'a> { + /// Create a new `Predicate` child. + pub fn new(key: &'a str, value: &'a dyn PredicateReflection) -> Self { + Self(key, value) + } + + /// Access the `Child`'s name. + pub fn name(&self) -> &str { + self.0 + } + + /// Access the `Child` `Predicate`. + pub fn value(&self) -> &dyn PredicateReflection { + self.1 + } +} + +impl<'a> fmt::Display for Child<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}: {}", self.0, self.1) + } +} + +impl<'a> fmt::Debug for Child<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "({:?}, {})", self.0, self.1) + } +} + +/// A descriptive explanation for why a predicate failed. +pub struct Case<'a> { + predicate: Option<&'a dyn PredicateReflection>, + result: bool, + products: Vec<Product>, + children: Vec<Case<'a>>, +} + +impl<'a> Case<'a> { + /// Create a new `Case` describing the result of a `Predicate`. + pub fn new(predicate: Option<&'a dyn PredicateReflection>, result: bool) -> Self { + Self { + predicate, + result, + products: Default::default(), + children: Default::default(), + } + } + + /// Add an additional by product to a `Case`. + pub fn add_product(mut self, product: Product) -> Self { + self.products.push(product); + self + } + + /// Add an additional by product to a `Case`. + pub fn add_child(mut self, child: Case<'a>) -> Self { + self.children.push(child); + self + } + + /// The `Predicate` that produced this case. + pub fn predicate(&self) -> Option<&dyn PredicateReflection> { + self.predicate + } + + /// The result of this case. + pub fn result(&self) -> bool { + self.result + } + + /// Access the by-products from determining this case. + pub fn products(&self) -> CaseProducts<'_> { + CaseProducts(self.products.iter()) + } + + /// Access the sub-cases. + pub fn children(&self) -> CaseChildren<'_> { + CaseChildren(self.children.iter()) + } +} + +impl<'a> fmt::Debug for Case<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let predicate = if let Some(ref predicate) = self.predicate { + format!("Some({})", predicate) + } else { + "None".to_owned() + }; + f.debug_struct("Case") + .field("predicate", &predicate) + .field("result", &self.result) + .field("products", &self.products) + .field("children", &self.children) + .finish() + } +} + +/// Iterator over a `Case`s by-products. +#[derive(Debug, Clone)] +pub struct CaseProducts<'a>(slice::Iter<'a, Product>); + +impl<'a> Iterator for CaseProducts<'a> { + type Item = &'a Product; + + fn next(&mut self) -> Option<&'a Product> { + self.0.next() + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } + + fn count(self) -> usize { + self.0.count() + } +} + +/// Iterator over a `Case`s sub-cases. +#[derive(Debug, Clone)] +pub struct CaseChildren<'a>(slice::Iter<'a, Case<'a>>); + +impl<'a> Iterator for CaseChildren<'a> { + type Item = &'a Case<'a>; + + fn next(&mut self) -> Option<&'a Case<'a>> { + self.0.next() + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } + + fn count(self) -> usize { + self.0.count() + } +} + +/// A by-product of a predicate evaluation. +/// +/// ```rust +/// use predicates_core; +/// +/// let product = predicates_core::reflection::Product::new("key", "value"); +/// println!("{}", product); +/// let product = predicates_core::reflection::Product::new(format!("key-{}", 5), 30); +/// println!("{}", product); +/// ``` +pub struct Product(borrow::Cow<'static, str>, Box<dyn fmt::Display>); + +impl Product { + /// Create a new `Product`. + pub fn new<S, D>(key: S, value: D) -> Self + where + S: Into<borrow::Cow<'static, str>>, + D: fmt::Display + 'static, + { + Self(key.into(), Box::new(value)) + } + + /// Access the `Product` name. + pub fn name(&self) -> &str { + self.0.as_ref() + } + + /// Access the `Product` value. + pub fn value(&self) -> &dyn fmt::Display { + &self.1 + } +} + +impl fmt::Display for Product { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}: {}", self.0, self.1) + } +} + +impl fmt::Debug for Product { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "({:?}, {})", self.0, self.1) + } +} |