summaryrefslogtreecommitdiff
path: root/src/reflection.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/reflection.rs')
-rw-r--r--src/reflection.rs252
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)
+ }
+}