// 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. //! 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 where T: PartialEq + fmt::Debug, { inner: utils::DebugAdapter>, } impl InPredicate 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 { let mut items = self.inner.debug; items.sort(); OrdInPredicate { inner: utils::DebugAdapter::new(items), } } } impl Predicate

for InPredicate where T: std::borrow::Borrow

+ 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> { utils::default_find_case(self, expected, variable).map(|case| { case.add_product(reflection::Product::new( "var", utils::DebugAdapter::new(variable).to_string(), )) }) } } impl reflection::PredicateReflection for InPredicate where T: PartialEq + fmt::Debug, { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("values", &self.inner)]; Box::new(params.into_iter()) } } impl fmt::Display for InPredicate 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(iter: I) -> InPredicate where T: PartialEq + fmt::Debug, I: IntoIterator, { 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 where T: Ord + fmt::Debug, { inner: utils::DebugAdapter>, } impl Predicate

for OrdInPredicate where T: std::borrow::Borrow

+ 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> { utils::default_find_case(self, expected, variable).map(|case| { case.add_product(reflection::Product::new( "var", utils::DebugAdapter::new(variable).to_string(), )) }) } } impl reflection::PredicateReflection for OrdInPredicate where T: Ord + fmt::Debug, { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("values", &self.inner)]; Box::new(params.into_iter()) } } impl fmt::Display for OrdInPredicate 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 where T: Hash + Eq + fmt::Debug, { inner: utils::DebugAdapter>, } impl Predicate

for HashableInPredicate where T: std::borrow::Borrow

+ 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> { utils::default_find_case(self, expected, variable).map(|case| { case.add_product(reflection::Product::new( "var", utils::DebugAdapter::new(variable).to_string(), )) }) } } impl reflection::PredicateReflection for HashableInPredicate where T: Hash + Eq + fmt::Debug, { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("values", &self.inner)]; Box::new(params.into_iter()) } } impl fmt::Display for HashableInPredicate 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(iter: I) -> HashableInPredicate where T: Hash + Eq + fmt::Debug, I: IntoIterator, { HashableInPredicate { inner: utils::DebugAdapter::new(HashSet::from_iter(iter)), } }