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 let palette = crate::Palette::current();
115 write!(
116 f,
117 "{} {} {}",
118 palette.var.paint("var"),
119 palette.description.paint("in"),
120 palette.expected.paint("values")
121 )
122 }
123 }
124
125 /// Creates a new predicate that will return `true` when the given `variable` is
126 /// contained with the set of items provided.
127 ///
128 /// Note that this implementation places the fewest restrictions on the
129 /// underlying `Item` type at the expense of having the least performant
130 /// implementation (linear search). If the type to be searched is `Hash + Eq`,
131 /// it is much more efficient to use `HashableInPredicate` and
132 /// `in_hash`. The implementation-specific predicates will be
133 /// deprecated when Rust supports trait specialization.
134 ///
135 /// If you need to optimize this
136 /// - Type is `Ord`, call `sort()` on this predicate.
137 /// - Type is `Hash`, replace `in_iter` with `in_hash`.
138 ///
139 /// # Examples
140 ///
141 /// ```
142 /// use predicates::prelude::*;
143 ///
144 /// let predicate_fn = predicate::in_iter(vec![1, 3, 5]);
145 /// assert_eq!(true, predicate_fn.eval(&1));
146 /// assert_eq!(false, predicate_fn.eval(&2));
147 /// assert_eq!(true, predicate_fn.eval(&3));
148 ///
149 /// let predicate_fn = predicate::in_iter(vec!["a", "c", "e"]);
150 /// assert_eq!(true, predicate_fn.eval("a"));
151 /// assert_eq!(false, predicate_fn.eval("b"));
152 /// assert_eq!(true, predicate_fn.eval("c"));
153 /// ```
in_iter<I, T>(iter: I) -> InPredicate<T> where T: PartialEq + fmt::Debug, I: IntoIterator<Item = T>,154 pub fn in_iter<I, T>(iter: I) -> InPredicate<T>
155 where
156 T: PartialEq + fmt::Debug,
157 I: IntoIterator<Item = T>,
158 {
159 InPredicate {
160 inner: utils::DebugAdapter::new(Vec::from_iter(iter)),
161 }
162 }
163
164 /// Predicate that returns `true` if `variable` is a member of the pre-defined
165 /// set, otherwise returns `false`.
166 ///
167 /// Note that this implementation requires `Item` to be `Ord`. The
168 /// `InPredicate` uses a less efficient search algorithm but only
169 /// requires `Item` implement `PartialEq`. The implementation-specific
170 /// predicates will be deprecated when Rust supports trait specialization.
171 ///
172 /// This is created by the `predicate::in_iter(...).sort` function.
173 #[derive(Debug, Clone, PartialEq, Eq)]
174 pub struct OrdInPredicate<T>
175 where
176 T: Ord + fmt::Debug,
177 {
178 inner: utils::DebugAdapter<Vec<T>>,
179 }
180
181 impl<T> Predicate<T> for OrdInPredicate<T>
182 where
183 T: Ord + fmt::Debug,
184 {
eval(&self, variable: &T) -> bool185 fn eval(&self, variable: &T) -> bool {
186 self.inner.debug.binary_search(variable).is_ok()
187 }
188
find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>>189 fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
190 utils::default_find_case(self, expected, variable)
191 }
192 }
193
194 impl<'a, T> Predicate<T> for OrdInPredicate<&'a T>
195 where
196 T: Ord + fmt::Debug + ?Sized,
197 {
eval(&self, variable: &T) -> bool198 fn eval(&self, variable: &T) -> bool {
199 self.inner.debug.binary_search(&variable).is_ok()
200 }
201
find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>>202 fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
203 utils::default_find_case(self, expected, variable)
204 }
205 }
206
207 impl<T> reflection::PredicateReflection for OrdInPredicate<T>
208 where
209 T: Ord + fmt::Debug,
210 {
parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a>211 fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a> {
212 let params = vec![reflection::Parameter::new("values", &self.inner)];
213 Box::new(params.into_iter())
214 }
215 }
216
217 impl<T> fmt::Display for OrdInPredicate<T>
218 where
219 T: Ord + fmt::Debug,
220 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 let palette = crate::Palette::current();
223 write!(
224 f,
225 "{} {} {}",
226 palette.var.paint("var"),
227 palette.description.paint("in"),
228 palette.expected.paint("values")
229 )
230 }
231 }
232
233 /// Predicate that returns `true` if `variable` is a member of the pre-defined
234 /// `HashSet`, otherwise returns `false`.
235 ///
236 /// Note that this implementation requires `Item` to be `Hash + Eq`. The
237 /// `InPredicate` uses a less efficient search algorithm but only
238 /// requires `Item` implement `PartialEq`. The implementation-specific
239 /// predicates will be deprecated when Rust supports trait specialization.
240 ///
241 /// This is created by the `predicate::in_hash` function.
242 #[derive(Debug, Clone, PartialEq, Eq)]
243 pub struct HashableInPredicate<T>
244 where
245 T: Hash + Eq + fmt::Debug,
246 {
247 inner: utils::DebugAdapter<HashSet<T>>,
248 }
249
250 impl<T> Predicate<T> for HashableInPredicate<T>
251 where
252 T: Hash + Eq + fmt::Debug,
253 {
eval(&self, variable: &T) -> bool254 fn eval(&self, variable: &T) -> bool {
255 self.inner.debug.contains(variable)
256 }
257
find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>>258 fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
259 utils::default_find_case(self, expected, variable)
260 }
261 }
262
263 impl<'a, T> Predicate<T> for HashableInPredicate<&'a T>
264 where
265 T: Hash + Eq + fmt::Debug + ?Sized,
266 {
eval(&self, variable: &T) -> bool267 fn eval(&self, variable: &T) -> bool {
268 self.inner.debug.contains(&variable)
269 }
270
find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>>271 fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
272 utils::default_find_case(self, expected, variable)
273 }
274 }
275
276 impl<T> reflection::PredicateReflection for HashableInPredicate<T>
277 where
278 T: Hash + Eq + fmt::Debug,
279 {
parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a>280 fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a> {
281 let params = vec![reflection::Parameter::new("values", &self.inner)];
282 Box::new(params.into_iter())
283 }
284 }
285
286 impl<T> fmt::Display for HashableInPredicate<T>
287 where
288 T: Hash + Eq + fmt::Debug,
289 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result290 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291 let palette = crate::Palette::current();
292 write!(
293 f,
294 "{} {} {}",
295 palette.var.paint("var"),
296 palette.description.paint("in"),
297 palette.expected.paint("values")
298 )
299 }
300 }
301
302 /// Creates a new predicate that will return `true` when the given `variable` is
303 /// contained with the set of items provided.
304 ///
305 /// Note that this implementation requires `Item` to be `Hash + Eq`. The
306 /// `InPredicate` uses a less efficient search algorithm but only
307 /// requires `Item` implement `PartialEq`. The implementation-specific
308 /// predicates will be deprecated when Rust supports trait specialization.
309 ///
310 /// # Examples
311 ///
312 /// ```
313 /// use predicates::prelude::*;
314 ///
315 /// let predicate_fn = predicate::in_hash(vec![1, 3, 5]);
316 /// assert_eq!(true, predicate_fn.eval(&1));
317 /// assert_eq!(false, predicate_fn.eval(&2));
318 /// assert_eq!(true, predicate_fn.eval(&3));
319 ///
320 /// let predicate_fn = predicate::in_hash(vec!["a", "c", "e"]);
321 /// assert_eq!(true, predicate_fn.eval("a"));
322 /// assert_eq!(false, predicate_fn.eval("b"));
323 /// assert_eq!(true, predicate_fn.eval("c"));
324 /// ```
in_hash<I, T>(iter: I) -> HashableInPredicate<T> where T: Hash + Eq + fmt::Debug, I: IntoIterator<Item = T>,325 pub fn in_hash<I, T>(iter: I) -> HashableInPredicate<T>
326 where
327 T: Hash + Eq + fmt::Debug,
328 I: IntoIterator<Item = T>,
329 {
330 HashableInPredicate {
331 inner: utils::DebugAdapter::new(HashSet::from_iter(iter)),
332 }
333 }
334