predicates/iter.rs
1// Copyright (c) 2018 The predicates-rs Project Developers.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/license/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Definition of `Predicate`s for comparisons of membership in a set.
10
11use std::collections::HashSet;
12use std::fmt;
13use std::hash::Hash;
14use std::iter::FromIterator;
15
16use crate::reflection;
17use crate::utils;
18use crate::Predicate;
19
20/// Predicate that returns `true` if `variable` is a member of the pre-defined
21/// set, otherwise returns `false`.
22///
23/// Note that this implementation places the fewest restrictions on the
24/// underlying `Item` type at the expense of having the least performant
25/// implementation (linear search). If the type to be searched is `Hash + Eq`,
26/// it is much more efficient to use `HashableInPredicate` and
27/// `in_hash`. The implementation-specific predicates will be
28/// deprecated when Rust supports trait specialization.
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct InPredicate<T>
31where
32 T: PartialEq + fmt::Debug,
33{
34 inner: utils::DebugAdapter<Vec<T>>,
35}
36
37impl<T> InPredicate<T>
38where
39 T: Ord + fmt::Debug,
40{
41 /// Creates a new predicate that will return `true` when the given `variable` is
42 /// contained with the set of items provided.
43 ///
44 /// Note that this implementation requires `Item` to be `Ord`. The
45 /// `InPredicate` uses a less efficient search algorithm but only
46 /// requires `Item` implement `PartialEq`. The implementation-specific
47 /// predicates will be deprecated when Rust supports trait specialization.
48 ///
49 /// # Examples
50 ///
51 /// ```
52 /// use predicates::prelude::*;
53 ///
54 /// let predicate_fn = predicate::in_iter(vec![1, 3, 5]).sort();
55 /// assert_eq!(true, predicate_fn.eval(&1));
56 /// assert_eq!(false, predicate_fn.eval(&2));
57 /// assert_eq!(true, predicate_fn.eval(&3));
58 ///
59 /// let predicate_fn = predicate::in_iter(vec!["a", "c", "e"]).sort();
60 /// assert_eq!(true, predicate_fn.eval("a"));
61 /// assert_eq!(false, predicate_fn.eval("b"));
62 /// assert_eq!(true, predicate_fn.eval("c"));
63 /// ```
64 pub fn sort(self) -> OrdInPredicate<T> {
65 let mut items = self.inner.debug;
66 items.sort();
67 OrdInPredicate {
68 inner: utils::DebugAdapter::new(items),
69 }
70 }
71}
72
73impl<T> Predicate<T> for InPredicate<T>
74where
75 T: PartialEq + fmt::Debug,
76{
77 fn eval(&self, variable: &T) -> bool {
78 self.inner.debug.contains(variable)
79 }
80
81 fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
82 utils::default_find_case(self, expected, variable)
83 }
84}
85
86impl<'a, T> Predicate<T> for InPredicate<&'a T>
87where
88 T: PartialEq + fmt::Debug + ?Sized,
89{
90 fn eval(&self, variable: &T) -> bool {
91 self.inner.debug.contains(&variable)
92 }
93
94 fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
95 utils::default_find_case(self, expected, variable)
96 }
97}
98
99impl<T> reflection::PredicateReflection for InPredicate<T>
100where
101 T: PartialEq + fmt::Debug,
102{
103 fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a> {
104 let params = vec![reflection::Parameter::new("values", &self.inner)];
105 Box::new(params.into_iter())
106 }
107}
108
109impl<T> fmt::Display for InPredicate<T>
110where
111 T: PartialEq + fmt::Debug,
112{
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 write!(f, "var in values")
115 }
116}
117
118/// Creates a new predicate that will return `true` when the given `variable` is
119/// contained with the set of items provided.
120///
121/// Note that this implementation places the fewest restrictions on the
122/// underlying `Item` type at the expense of having the least performant
123/// implementation (linear search). If the type to be searched is `Hash + Eq`,
124/// it is much more efficient to use `HashableInPredicate` and
125/// `in_hash`. The implementation-specific predicates will be
126/// deprecated when Rust supports trait specialization.
127///
128/// If you need to optimize this
129/// - Type is `Ord`, call `sort()` on this predicate.
130/// - Type is `Hash`, replace `in_iter` with `in_hash`.
131///
132/// # Examples
133///
134/// ```
135/// use predicates::prelude::*;
136///
137/// let predicate_fn = predicate::in_iter(vec![1, 3, 5]);
138/// assert_eq!(true, predicate_fn.eval(&1));
139/// assert_eq!(false, predicate_fn.eval(&2));
140/// assert_eq!(true, predicate_fn.eval(&3));
141///
142/// let predicate_fn = predicate::in_iter(vec!["a", "c", "e"]);
143/// assert_eq!(true, predicate_fn.eval("a"));
144/// assert_eq!(false, predicate_fn.eval("b"));
145/// assert_eq!(true, predicate_fn.eval("c"));
146/// ```
147pub fn in_iter<I, T>(iter: I) -> InPredicate<T>
148where
149 T: PartialEq + fmt::Debug,
150 I: IntoIterator<Item = T>,
151{
152 InPredicate {
153 inner: utils::DebugAdapter::new(Vec::from_iter(iter)),
154 }
155}
156
157/// Predicate that returns `true` if `variable` is a member of the pre-defined
158/// set, otherwise returns `false`.
159///
160/// Note that this implementation requires `Item` to be `Ord`. The
161/// `InPredicate` uses a less efficient search algorithm but only
162/// requires `Item` implement `PartialEq`. The implementation-specific
163/// predicates will be deprecated when Rust supports trait specialization.
164///
165/// This is created by the `predicate::in_iter(...).sort` function.
166#[derive(Debug, Clone, PartialEq, Eq)]
167pub struct OrdInPredicate<T>
168where
169 T: Ord + fmt::Debug,
170{
171 inner: utils::DebugAdapter<Vec<T>>,
172}
173
174impl<T> Predicate<T> for OrdInPredicate<T>
175where
176 T: Ord + fmt::Debug,
177{
178 fn eval(&self, variable: &T) -> bool {
179 self.inner.debug.binary_search(variable).is_ok()
180 }
181
182 fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
183 utils::default_find_case(self, expected, variable)
184 }
185}
186
187impl<'a, T> Predicate<T> for OrdInPredicate<&'a T>
188where
189 T: Ord + fmt::Debug + ?Sized,
190{
191 fn eval(&self, variable: &T) -> bool {
192 self.inner.debug.binary_search(&variable).is_ok()
193 }
194
195 fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
196 utils::default_find_case(self, expected, variable)
197 }
198}
199
200impl<T> reflection::PredicateReflection for OrdInPredicate<T>
201where
202 T: Ord + fmt::Debug,
203{
204 fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a> {
205 let params = vec![reflection::Parameter::new("values", &self.inner)];
206 Box::new(params.into_iter())
207 }
208}
209
210impl<T> fmt::Display for OrdInPredicate<T>
211where
212 T: Ord + fmt::Debug,
213{
214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215 write!(f, "var in values")
216 }
217}
218
219/// Predicate that returns `true` if `variable` is a member of the pre-defined
220/// `HashSet`, otherwise returns `false`.
221///
222/// Note that this implementation requires `Item` to be `Hash + Eq`. The
223/// `InPredicate` uses a less efficient search algorithm but only
224/// requires `Item` implement `PartialEq`. The implementation-specific
225/// predicates will be deprecated when Rust supports trait specialization.
226///
227/// This is created by the `predicate::in_hash` function.
228#[derive(Debug, Clone, PartialEq, Eq)]
229pub struct HashableInPredicate<T>
230where
231 T: Hash + Eq + fmt::Debug,
232{
233 inner: utils::DebugAdapter<HashSet<T>>,
234}
235
236impl<T> Predicate<T> for HashableInPredicate<T>
237where
238 T: Hash + Eq + fmt::Debug,
239{
240 fn eval(&self, variable: &T) -> bool {
241 self.inner.debug.contains(variable)
242 }
243
244 fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
245 utils::default_find_case(self, expected, variable)
246 }
247}
248
249impl<'a, T> Predicate<T> for HashableInPredicate<&'a T>
250where
251 T: Hash + Eq + fmt::Debug + ?Sized,
252{
253 fn eval(&self, variable: &T) -> bool {
254 self.inner.debug.contains(&variable)
255 }
256
257 fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
258 utils::default_find_case(self, expected, variable)
259 }
260}
261
262impl<T> reflection::PredicateReflection for HashableInPredicate<T>
263where
264 T: Hash + Eq + fmt::Debug,
265{
266 fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a> {
267 let params = vec![reflection::Parameter::new("values", &self.inner)];
268 Box::new(params.into_iter())
269 }
270}
271
272impl<T> fmt::Display for HashableInPredicate<T>
273where
274 T: Hash + Eq + fmt::Debug,
275{
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 write!(f, "var in values")
278 }
279}
280
281/// Creates a new predicate that will return `true` when the given `variable` is
282/// contained with the set of items provided.
283///
284/// Note that this implementation requires `Item` to be `Hash + Eq`. The
285/// `InPredicate` uses a less efficient search algorithm but only
286/// requires `Item` implement `PartialEq`. The implementation-specific
287/// predicates will be deprecated when Rust supports trait specialization.
288///
289/// # Examples
290///
291/// ```
292/// use predicates::prelude::*;
293///
294/// let predicate_fn = predicate::in_hash(vec![1, 3, 5]);
295/// assert_eq!(true, predicate_fn.eval(&1));
296/// assert_eq!(false, predicate_fn.eval(&2));
297/// assert_eq!(true, predicate_fn.eval(&3));
298///
299/// let predicate_fn = predicate::in_hash(vec!["a", "c", "e"]);
300/// assert_eq!(true, predicate_fn.eval("a"));
301/// assert_eq!(false, predicate_fn.eval("b"));
302/// assert_eq!(true, predicate_fn.eval("c"));
303/// ```
304pub fn in_hash<I, T>(iter: I) -> HashableInPredicate<T>
305where
306 T: Hash + Eq + fmt::Debug,
307 I: IntoIterator<Item = T>,
308{
309 HashableInPredicate {
310 inner: utils::DebugAdapter::new(HashSet::from_iter(iter)),
311 }
312}