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
11 use std::collections::HashSet;
12 use std::fmt;
13 use std::hash::Hash;
14 use std::iter::FromIterator;
15
16 use crate::reflection;
17 use crate::utils;
18 use 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)]
30 pub struct InPredicate<T>
31 where
32 T: PartialEq + fmt::Debug,
33 {
34 inner: utils::DebugAdapter<Vec<T>>,
35 }
36
37 impl<T> InPredicate<T>
38 where
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 /// ```
sort(self) -> OrdInPredicate<T>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
73 impl<T> Predicate<T> for InPredicate<T>
74 where
75 T: PartialEq + fmt::Debug,
76 {
eval(&self, variable: &T) -> bool77 fn eval(&self, variable: &T) -> bool {
78 self.inner.debug.contains(variable)
79 }
80
find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>>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
86 impl<'a, T> Predicate<T> for InPredicate<&'a T>
87 where
88 T: PartialEq + fmt::Debug + ?Sized,
89 {
eval(&self, variable: &T) -> bool90 fn eval(&self, variable: &T) -> bool {
91 self.inner.debug.contains(&variable)
92 }
93
find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>>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
99 impl<T> reflection::PredicateReflection for InPredicate<T>
100 where
101 T: PartialEq + fmt::Debug,
102 {
parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a>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
109 impl<T> fmt::Display for InPredicate<T>
110 where
111 T: PartialEq + fmt::Debug,
112 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result113 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 /// ```
in_iter<I, T>(iter: I) -> InPredicate<T> where T: PartialEq + fmt::Debug, I: IntoIterator<Item = T>,147 pub fn in_iter<I, T>(iter: I) -> InPredicate<T>
148 where
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)]
167 pub struct OrdInPredicate<T>
168 where
169 T: Ord + fmt::Debug,
170 {
171 inner: utils::DebugAdapter<Vec<T>>,
172 }
173
174 impl<T> Predicate<T> for OrdInPredicate<T>
175 where
176 T: Ord + fmt::Debug,
177 {
eval(&self, variable: &T) -> bool178 fn eval(&self, variable: &T) -> bool {
179 self.inner.debug.binary_search(variable).is_ok()
180 }
181
find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>>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
187 impl<'a, T> Predicate<T> for OrdInPredicate<&'a T>
188 where
189 T: Ord + fmt::Debug + ?Sized,
190 {
eval(&self, variable: &T) -> bool191 fn eval(&self, variable: &T) -> bool {
192 self.inner.debug.binary_search(&variable).is_ok()
193 }
194
find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>>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
200 impl<T> reflection::PredicateReflection for OrdInPredicate<T>
201 where
202 T: Ord + fmt::Debug,
203 {
parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a>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
210 impl<T> fmt::Display for OrdInPredicate<T>
211 where
212 T: Ord + fmt::Debug,
213 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result214 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)]
229 pub struct HashableInPredicate<T>
230 where
231 T: Hash + Eq + fmt::Debug,
232 {
233 inner: utils::DebugAdapter<HashSet<T>>,
234 }
235
236 impl<T> Predicate<T> for HashableInPredicate<T>
237 where
238 T: Hash + Eq + fmt::Debug,
239 {
eval(&self, variable: &T) -> bool240 fn eval(&self, variable: &T) -> bool {
241 self.inner.debug.contains(variable)
242 }
243
find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>>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
249 impl<'a, T> Predicate<T> for HashableInPredicate<&'a T>
250 where
251 T: Hash + Eq + fmt::Debug + ?Sized,
252 {
eval(&self, variable: &T) -> bool253 fn eval(&self, variable: &T) -> bool {
254 self.inner.debug.contains(&variable)
255 }
256
find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>>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
262 impl<T> reflection::PredicateReflection for HashableInPredicate<T>
263 where
264 T: Hash + Eq + fmt::Debug,
265 {
parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a>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
272 impl<T> fmt::Display for HashableInPredicate<T>
273 where
274 T: Hash + Eq + fmt::Debug,
275 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result276 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 /// ```
in_hash<I, T>(iter: I) -> HashableInPredicate<T> where T: Hash + Eq + fmt::Debug, I: IntoIterator<Item = T>,304 pub fn in_hash<I, T>(iter: I) -> HashableInPredicate<T>
305 where
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 }
313