| // 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. |
| |
| //! Definition of `Predicate`s for comparisons of membership in a set. |
| |
| use std::collections::HashSet; |
| use std::fmt; |
| use std::hash::Hash; |
| use std::iter::FromIterator; |
| |
| use crate::reflection; |
| use crate::utils; |
| use crate::Predicate; |
| |
| /// Predicate that returns `true` if `variable` is a member of the pre-defined |
| /// set, otherwise returns `false`. |
| /// |
| /// Note that this implementation places the fewest restrictions on the |
| /// underlying `Item` type at the expense of having the least performant |
| /// implementation (linear search). If the type to be searched is `Hash + Eq`, |
| /// it is much more efficient to use `HashableInPredicate` and |
| /// `in_hash`. The implementation-specific predicates will be |
| /// deprecated when Rust supports trait specialization. |
| #[derive(Debug, Clone, PartialEq, Eq)] |
| pub struct InPredicate<T> |
| where |
| T: PartialEq + fmt::Debug, |
| { |
| inner: utils::DebugAdapter<Vec<T>>, |
| } |
| |
| impl<T> InPredicate<T> |
| where |
| T: Ord + fmt::Debug, |
| { |
| /// Creates a new predicate that will return `true` when the given `variable` is |
| /// contained with the set of items provided. |
| /// |
| /// Note that this implementation requires `Item` to be `Ord`. The |
| /// `InPredicate` uses a less efficient search algorithm but only |
| /// requires `Item` implement `PartialEq`. The implementation-specific |
| /// predicates will be deprecated when Rust supports trait specialization. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use predicates::prelude::*; |
| /// |
| /// let predicate_fn = predicate::in_iter(vec![1, 3, 5]).sort(); |
| /// assert_eq!(true, predicate_fn.eval(&1)); |
| /// assert_eq!(false, predicate_fn.eval(&2)); |
| /// assert_eq!(true, predicate_fn.eval(&3)); |
| /// |
| /// let predicate_fn = predicate::in_iter(vec!["a", "c", "e"]).sort(); |
| /// assert_eq!(true, predicate_fn.eval("a")); |
| /// assert_eq!(false, predicate_fn.eval("b")); |
| /// assert_eq!(true, predicate_fn.eval("c")); |
| /// |
| /// let predicate_fn = predicate::in_iter(vec![String::from("a"), String::from("c"), String::from("e")]).sort(); |
| /// assert_eq!(true, predicate_fn.eval("a")); |
| /// assert_eq!(false, predicate_fn.eval("b")); |
| /// assert_eq!(true, predicate_fn.eval("c")); |
| /// ``` |
| pub fn sort(self) -> OrdInPredicate<T> { |
| let mut items = self.inner.debug; |
| items.sort(); |
| OrdInPredicate { |
| inner: utils::DebugAdapter::new(items), |
| } |
| } |
| } |
| |
| impl<P, T> Predicate<P> for InPredicate<T> |
| where |
| T: std::borrow::Borrow<P> + PartialEq + fmt::Debug, |
| P: PartialEq + fmt::Debug + ?Sized, |
| { |
| fn eval(&self, variable: &P) -> bool { |
| self.inner.debug.iter().any(|x| x.borrow() == variable) |
| } |
| |
| fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> { |
| utils::default_find_case(self, expected, variable).map(|case| { |
| case.add_product(reflection::Product::new( |
| "var", |
| utils::DebugAdapter::new(variable).to_string(), |
| )) |
| }) |
| } |
| } |
| |
| impl<T> reflection::PredicateReflection for InPredicate<T> |
| where |
| T: PartialEq + fmt::Debug, |
| { |
| fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a> { |
| let params = vec![reflection::Parameter::new("values", &self.inner)]; |
| Box::new(params.into_iter()) |
| } |
| } |
| |
| impl<T> fmt::Display for InPredicate<T> |
| where |
| T: PartialEq + fmt::Debug, |
| { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| let palette = crate::Palette::new(f.alternate()); |
| write!( |
| f, |
| "{} {} {}", |
| palette.var("var"), |
| palette.description("in"), |
| palette.expected("values") |
| ) |
| } |
| } |
| |
| /// Creates a new predicate that will return `true` when the given `variable` is |
| /// contained with the set of items provided. |
| /// |
| /// Note that this implementation places the fewest restrictions on the |
| /// underlying `Item` type at the expense of having the least performant |
| /// implementation (linear search). If the type to be searched is `Hash + Eq`, |
| /// it is much more efficient to use `HashableInPredicate` and |
| /// `in_hash`. The implementation-specific predicates will be |
| /// deprecated when Rust supports trait specialization. |
| /// |
| /// If you need to optimize this |
| /// - Type is `Ord`, call `sort()` on this predicate. |
| /// - Type is `Hash`, replace `in_iter` with `in_hash`. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use predicates::prelude::*; |
| /// |
| /// let predicate_fn = predicate::in_iter(vec![1, 3, 5]); |
| /// assert_eq!(true, predicate_fn.eval(&1)); |
| /// assert_eq!(false, predicate_fn.eval(&2)); |
| /// assert_eq!(true, predicate_fn.eval(&3)); |
| /// |
| /// let predicate_fn = predicate::in_iter(vec!["a", "c", "e"]); |
| /// assert_eq!(true, predicate_fn.eval("a")); |
| /// assert_eq!(false, predicate_fn.eval("b")); |
| /// assert_eq!(true, predicate_fn.eval("c")); |
| /// |
| /// let predicate_fn = predicate::in_iter(vec![String::from("a"), String::from("c"), String::from("e")]); |
| /// assert_eq!(true, predicate_fn.eval("a")); |
| /// assert_eq!(false, predicate_fn.eval("b")); |
| /// assert_eq!(true, predicate_fn.eval("c")); |
| /// ``` |
| pub fn in_iter<I, T>(iter: I) -> InPredicate<T> |
| where |
| T: PartialEq + fmt::Debug, |
| I: IntoIterator<Item = T>, |
| { |
| InPredicate { |
| inner: utils::DebugAdapter::new(Vec::from_iter(iter)), |
| } |
| } |
| |
| /// Predicate that returns `true` if `variable` is a member of the pre-defined |
| /// set, otherwise returns `false`. |
| /// |
| /// Note that this implementation requires `Item` to be `Ord`. The |
| /// `InPredicate` uses a less efficient search algorithm but only |
| /// requires `Item` implement `PartialEq`. The implementation-specific |
| /// predicates will be deprecated when Rust supports trait specialization. |
| /// |
| /// This is created by the `predicate::in_iter(...).sort` function. |
| #[derive(Debug, Clone, PartialEq, Eq)] |
| pub struct OrdInPredicate<T> |
| where |
| T: Ord + fmt::Debug, |
| { |
| inner: utils::DebugAdapter<Vec<T>>, |
| } |
| |
| impl<P, T> Predicate<P> for OrdInPredicate<T> |
| where |
| T: std::borrow::Borrow<P> + Ord + fmt::Debug, |
| P: Ord + fmt::Debug + ?Sized, |
| { |
| fn eval(&self, variable: &P) -> bool { |
| self.inner |
| .debug |
| .binary_search_by(|x| x.borrow().cmp(variable)) |
| .is_ok() |
| } |
| |
| fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> { |
| utils::default_find_case(self, expected, variable).map(|case| { |
| case.add_product(reflection::Product::new( |
| "var", |
| utils::DebugAdapter::new(variable).to_string(), |
| )) |
| }) |
| } |
| } |
| |
| impl<T> reflection::PredicateReflection for OrdInPredicate<T> |
| where |
| T: Ord + fmt::Debug, |
| { |
| fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a> { |
| let params = vec![reflection::Parameter::new("values", &self.inner)]; |
| Box::new(params.into_iter()) |
| } |
| } |
| |
| impl<T> fmt::Display for OrdInPredicate<T> |
| where |
| T: Ord + fmt::Debug, |
| { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| let palette = crate::Palette::new(f.alternate()); |
| write!( |
| f, |
| "{} {} {}", |
| palette.var("var"), |
| palette.description("in"), |
| palette.expected("values") |
| ) |
| } |
| } |
| |
| /// Predicate that returns `true` if `variable` is a member of the pre-defined |
| /// `HashSet`, otherwise returns `false`. |
| /// |
| /// Note that this implementation requires `Item` to be `Hash + Eq`. The |
| /// `InPredicate` uses a less efficient search algorithm but only |
| /// requires `Item` implement `PartialEq`. The implementation-specific |
| /// predicates will be deprecated when Rust supports trait specialization. |
| /// |
| /// This is created by the `predicate::in_hash` function. |
| #[derive(Debug, Clone, PartialEq, Eq)] |
| pub struct HashableInPredicate<T> |
| where |
| T: Hash + Eq + fmt::Debug, |
| { |
| inner: utils::DebugAdapter<HashSet<T>>, |
| } |
| |
| impl<P, T> Predicate<P> for HashableInPredicate<T> |
| where |
| T: std::borrow::Borrow<P> + Hash + Eq + fmt::Debug, |
| P: Hash + Eq + fmt::Debug + ?Sized, |
| { |
| fn eval(&self, variable: &P) -> bool { |
| self.inner.debug.contains(variable) |
| } |
| |
| fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> { |
| utils::default_find_case(self, expected, variable).map(|case| { |
| case.add_product(reflection::Product::new( |
| "var", |
| utils::DebugAdapter::new(variable).to_string(), |
| )) |
| }) |
| } |
| } |
| |
| impl<T> reflection::PredicateReflection for HashableInPredicate<T> |
| where |
| T: Hash + Eq + fmt::Debug, |
| { |
| fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a> { |
| let params = vec![reflection::Parameter::new("values", &self.inner)]; |
| Box::new(params.into_iter()) |
| } |
| } |
| |
| impl<T> fmt::Display for HashableInPredicate<T> |
| where |
| T: Hash + Eq + fmt::Debug, |
| { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| let palette = crate::Palette::new(f.alternate()); |
| write!( |
| f, |
| "{} {} {}", |
| palette.var("var"), |
| palette.description("in"), |
| palette.expected("values") |
| ) |
| } |
| } |
| |
| /// Creates a new predicate that will return `true` when the given `variable` is |
| /// contained with the set of items provided. |
| /// |
| /// Note that this implementation requires `Item` to be `Hash + Eq`. The |
| /// `InPredicate` uses a less efficient search algorithm but only |
| /// requires `Item` implement `PartialEq`. The implementation-specific |
| /// predicates will be deprecated when Rust supports trait specialization. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use predicates::prelude::*; |
| /// |
| /// let predicate_fn = predicate::in_hash(vec![1, 3, 5]); |
| /// assert_eq!(true, predicate_fn.eval(&1)); |
| /// assert_eq!(false, predicate_fn.eval(&2)); |
| /// assert_eq!(true, predicate_fn.eval(&3)); |
| /// |
| /// let predicate_fn = predicate::in_hash(vec!["a", "c", "e"]); |
| /// assert_eq!(true, predicate_fn.eval("a")); |
| /// assert_eq!(false, predicate_fn.eval("b")); |
| /// assert_eq!(true, predicate_fn.eval("c")); |
| /// |
| /// let predicate_fn = predicate::in_hash(vec![String::from("a"), String::from("c"), String::from("e")]); |
| /// assert_eq!(true, predicate_fn.eval("a")); |
| /// assert_eq!(false, predicate_fn.eval("b")); |
| /// assert_eq!(true, predicate_fn.eval("c")); |
| /// ``` |
| pub fn in_hash<I, T>(iter: I) -> HashableInPredicate<T> |
| where |
| T: Hash + Eq + fmt::Debug, |
| I: IntoIterator<Item = T>, |
| { |
| HashableInPredicate { |
| inner: utils::DebugAdapter::new(HashSet::from_iter(iter)), |
| } |
| } |