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