Skip to content

Commit 7934a3a

Browse files
committed
feat: Allow into_iter predicates to own object and eval vs borrowed types
It is very useful to be able to dynamically construct an object and have that object owned by the predicate, yet evaluate against an unowned type related to the owned one. An obvious example is a String being owned by the predicate but being compared against &strs. Therefore, implement Predicate for In/OrdIn/HashInPredicate that store an object that implements Borrow for the predicate type, replacing existing impls of Predicate<T> for In/OrdIn/HashInPredicate<T> and In/OrdIn/HashInPredicate<&T>. This is backwards compatible as there are blanket implementations of Borrow<T> for T and Borrow<T> for &T. Note that Borrow imposes more requirements than are actually required and AsRef would be sufficient. However, AsRef doesn't have a blanket implementation for T and thus the existing impl of Predicate<T> for InPredicate<T> is still required, but results in a conflict since T may also implement AsRef<T>. Requiring Borrow instead of AsRef is sufficient for common use cases though. This addresses #20 more completely.
1 parent f9536e0 commit 7934a3a

File tree

1 file changed

+35
-68
lines changed

1 file changed

+35
-68
lines changed

src/iter.rs

Lines changed: 35 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ where
6060
/// assert_eq!(true, predicate_fn.eval("a"));
6161
/// assert_eq!(false, predicate_fn.eval("b"));
6262
/// assert_eq!(true, predicate_fn.eval("c"));
63+
///
64+
/// let predicate_fn = predicate::in_iter(vec![String::from("a"), String::from("c"), String::from("e")]).sort();
65+
/// assert_eq!(true, predicate_fn.eval("a"));
66+
/// assert_eq!(false, predicate_fn.eval("b"));
67+
/// assert_eq!(true, predicate_fn.eval("c"));
6368
/// ```
6469
pub fn sort(self) -> OrdInPredicate<T> {
6570
let mut items = self.inner.debug;
@@ -70,33 +75,16 @@ where
7075
}
7176
}
7277

73-
impl<T> Predicate<T> for InPredicate<T>
74-
where
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).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>
78+
impl<P, T> Predicate<P> for InPredicate<T>
9279
where
93-
T: PartialEq + fmt::Debug + ?Sized,
80+
T: std::borrow::Borrow<P> + PartialEq + fmt::Debug,
81+
P: PartialEq + fmt::Debug + ?Sized,
9482
{
95-
fn eval(&self, variable: &T) -> bool {
96-
self.inner.debug.contains(&variable)
83+
fn eval(&self, variable: &P) -> bool {
84+
self.inner.debug.iter().any(|x| x.borrow() == variable)
9785
}
9886

99-
fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
87+
fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> {
10088
utils::default_find_case(self, expected, variable).map(|case| {
10189
case.add_product(reflection::Product::new(
10290
"var",
@@ -160,6 +148,11 @@ where
160148
/// assert_eq!(true, predicate_fn.eval("a"));
161149
/// assert_eq!(false, predicate_fn.eval("b"));
162150
/// assert_eq!(true, predicate_fn.eval("c"));
151+
///
152+
/// let predicate_fn = predicate::in_iter(vec![String::from("a"), String::from("c"), String::from("e")]);
153+
/// assert_eq!(true, predicate_fn.eval("a"));
154+
/// assert_eq!(false, predicate_fn.eval("b"));
155+
/// assert_eq!(true, predicate_fn.eval("c"));
163156
/// ```
164157
pub fn in_iter<I, T>(iter: I) -> InPredicate<T>
165158
where
@@ -188,33 +181,19 @@ where
188181
inner: utils::DebugAdapter<Vec<T>>,
189182
}
190183

191-
impl<T> Predicate<T> for OrdInPredicate<T>
184+
impl<P, T> Predicate<P> for OrdInPredicate<T>
192185
where
193-
T: Ord + fmt::Debug,
186+
T: std::borrow::Borrow<P> + Ord + fmt::Debug,
187+
P: Ord + fmt::Debug + ?Sized,
194188
{
195-
fn eval(&self, variable: &T) -> bool {
196-
self.inner.debug.binary_search(variable).is_ok()
189+
fn eval(&self, variable: &P) -> bool {
190+
self.inner
191+
.debug
192+
.binary_search_by(|x| x.borrow().cmp(variable))
193+
.is_ok()
197194
}
198195

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-
{
213-
fn eval(&self, variable: &T) -> bool {
214-
self.inner.debug.binary_search(&variable).is_ok()
215-
}
216-
217-
fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
196+
fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> {
218197
utils::default_find_case(self, expected, variable).map(|case| {
219198
case.add_product(reflection::Product::new(
220199
"var",
@@ -267,33 +246,16 @@ where
267246
inner: utils::DebugAdapter<HashSet<T>>,
268247
}
269248

270-
impl<T> Predicate<T> for HashableInPredicate<T>
249+
impl<P, T> Predicate<P> for HashableInPredicate<T>
271250
where
272-
T: Hash + Eq + fmt::Debug,
251+
T: std::borrow::Borrow<P> + Hash + Eq + fmt::Debug,
252+
P: Hash + Eq + fmt::Debug + ?Sized,
273253
{
274-
fn eval(&self, variable: &T) -> bool {
254+
fn eval(&self, variable: &P) -> bool {
275255
self.inner.debug.contains(variable)
276256
}
277257

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-
{
292-
fn eval(&self, variable: &T) -> bool {
293-
self.inner.debug.contains(&variable)
294-
}
295-
296-
fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
258+
fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> {
297259
utils::default_find_case(self, expected, variable).map(|case| {
298260
case.add_product(reflection::Product::new(
299261
"var",
@@ -351,6 +313,11 @@ where
351313
/// assert_eq!(true, predicate_fn.eval("a"));
352314
/// assert_eq!(false, predicate_fn.eval("b"));
353315
/// assert_eq!(true, predicate_fn.eval("c"));
316+
///
317+
/// let predicate_fn = predicate::in_hash(vec![String::from("a"), String::from("c"), String::from("e")]);
318+
/// assert_eq!(true, predicate_fn.eval("a"));
319+
/// assert_eq!(false, predicate_fn.eval("b"));
320+
/// assert_eq!(true, predicate_fn.eval("c"));
354321
/// ```
355322
pub fn in_hash<I, T>(iter: I) -> HashableInPredicate<T>
356323
where

0 commit comments

Comments
 (0)