Skip to content

Commit 7d2afb9

Browse files
committed
chore: Make find_case object safe
Apparently, a provided function can't downcast `&self` but I can if I spread the implementation around. Overall, trying to meet the goal of making it simple to write a Predicate. Anyone besides us will need to copy `default_find_case` if they want the reference. Not sure what would be a good way to make that good enough for being stable.
1 parent 5d6f8da commit 7d2afb9

File tree

10 files changed

+132
-5
lines changed

10 files changed

+132
-5
lines changed

src/boxed.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
1212
use std::fmt;
1313

14+
use core;
1415
use reflection;
1516
use Predicate;
1617

@@ -70,6 +71,10 @@ where
7071
fn eval(&self, variable: &Item) -> bool {
7172
self.0.eval(variable)
7273
}
74+
75+
fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option<reflection::Case<'a>> {
76+
core::default_find_case(self, expected, variable)
77+
}
7378
}
7479

7580
/// `Predicate` extension for boxing a `Predicate`.

src/constant.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use std::fmt;
1212
use std::marker::PhantomData;
1313

14+
use core;
1415
use reflection;
1516
use Predicate;
1617

@@ -27,6 +28,10 @@ impl<Item> Predicate<Item> for BooleanPredicate<Item> {
2728
fn eval(&self, _variable: &Item) -> bool {
2829
self.retval
2930
}
31+
32+
fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option<reflection::Case<'a>> {
33+
core::default_find_case(self, expected, variable)
34+
}
3035
}
3136

3237
impl<Item> reflection::PredicateReflection for BooleanPredicate<Item> {

src/core.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,29 @@ pub trait Predicate<Item: ?Sized>: reflection::PredicateReflection {
2121
fn eval(&self, variable: &Item) -> bool;
2222

2323
/// Find a case that proves this predicate as `expected` when run against `variable`.
24-
fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option<reflection::Case<'a>>
25-
where
26-
Self: Sized,
27-
{
24+
fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option<reflection::Case<'a>> {
2825
let actual = self.eval(variable);
2926
if expected == actual {
30-
Some(reflection::Case::new(Some(self), actual))
27+
Some(reflection::Case::new(None, actual))
3128
} else {
3229
None
3330
}
3431
}
3532
}
33+
34+
pub(crate) fn default_find_case<'a, P, Item>(
35+
pred: &'a P,
36+
expected: bool,
37+
variable: &Item,
38+
) -> Option<reflection::Case<'a>>
39+
where
40+
P: Predicate<Item>,
41+
Item: ?Sized,
42+
{
43+
let actual = pred.eval(variable);
44+
if expected == actual {
45+
Some(reflection::Case::new(Some(pred), actual))
46+
} else {
47+
None
48+
}
49+
}

src/function.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use std::fmt;
1212
use std::marker::PhantomData;
1313

14+
use core;
1415
use reflection;
1516
use Predicate;
1617

@@ -59,6 +60,10 @@ where
5960
fn eval(&self, variable: &T) -> bool {
6061
(self.function)(variable)
6162
}
63+
64+
fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
65+
core::default_find_case(self, expected, variable)
66+
}
6267
}
6368

6469
impl<F, T> reflection::PredicateReflection for FnPredicate<F, T>

src/iter.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::fmt;
1313
use std::hash::Hash;
1414
use std::iter::FromIterator;
1515

16+
use core;
1617
use reflection;
1718
use Predicate;
1819

@@ -76,6 +77,10 @@ where
7677
fn eval(&self, variable: &T) -> bool {
7778
self.inner.debug.contains(variable)
7879
}
80+
81+
fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
82+
core::default_find_case(self, expected, variable)
83+
}
7984
}
8085

8186
impl<'a, T> Predicate<T> for InPredicate<&'a T>
@@ -85,6 +90,10 @@ where
8590
fn eval(&self, variable: &T) -> bool {
8691
self.inner.debug.contains(&variable)
8792
}
93+
94+
fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
95+
core::default_find_case(self, expected, variable)
96+
}
8897
}
8998

9099
impl<T> reflection::PredicateReflection for InPredicate<T>
@@ -169,6 +178,10 @@ where
169178
fn eval(&self, variable: &T) -> bool {
170179
self.inner.debug.binary_search(variable).is_ok()
171180
}
181+
182+
fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
183+
core::default_find_case(self, expected, variable)
184+
}
172185
}
173186

174187
impl<'a, T> Predicate<T> for OrdInPredicate<&'a T>
@@ -178,6 +191,10 @@ where
178191
fn eval(&self, variable: &T) -> bool {
179192
self.inner.debug.binary_search(&variable).is_ok()
180193
}
194+
195+
fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
196+
core::default_find_case(self, expected, variable)
197+
}
181198
}
182199

183200
impl<T> reflection::PredicateReflection for OrdInPredicate<T>
@@ -223,6 +240,10 @@ where
223240
fn eval(&self, variable: &T) -> bool {
224241
self.inner.debug.contains(variable)
225242
}
243+
244+
fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
245+
core::default_find_case(self, expected, variable)
246+
}
226247
}
227248

228249
impl<'a, T> Predicate<T> for HashableInPredicate<&'a T>
@@ -232,6 +253,10 @@ where
232253
fn eval(&self, variable: &T) -> bool {
233254
self.inner.debug.contains(&variable)
234255
}
256+
257+
fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
258+
core::default_find_case(self, expected, variable)
259+
}
235260
}
236261

237262
impl<T> reflection::PredicateReflection for HashableInPredicate<T>

src/ord.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
1111
use std::fmt;
1212

13+
use core;
1314
use reflection;
1415
use Predicate;
1516

@@ -52,6 +53,10 @@ where
5253
EqOps::NotEqual => variable.ne(&self.constant),
5354
}
5455
}
56+
57+
fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
58+
core::default_find_case(self, expected, variable)
59+
}
5560
}
5661

5762
impl<'a, T> Predicate<T> for EqPredicate<&'a T>
@@ -64,6 +69,10 @@ where
6469
EqOps::NotEqual => variable.ne(self.constant),
6570
}
6671
}
72+
73+
fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
74+
core::default_find_case(self, expected, variable)
75+
}
6776
}
6877

6978
impl<T> reflection::PredicateReflection for EqPredicate<T>
@@ -174,6 +183,10 @@ where
174183
OrdOps::GreaterThan => variable.gt(&self.constant),
175184
}
176185
}
186+
187+
fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
188+
core::default_find_case(self, expected, variable)
189+
}
177190
}
178191

179192
impl<'a, T> Predicate<T> for OrdPredicate<&'a T>
@@ -188,6 +201,10 @@ where
188201
OrdOps::GreaterThan => variable.gt(self.constant),
189202
}
190203
}
204+
205+
fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
206+
core::default_find_case(self, expected, variable)
207+
}
191208
}
192209

193210
impl<T> reflection::PredicateReflection for OrdPredicate<T>

src/path/existence.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use std::fmt;
1010
use std::path;
1111

12+
use core;
1213
use reflection;
1314
use Predicate;
1415

@@ -24,6 +25,14 @@ impl Predicate<path::Path> for ExistencePredicate {
2425
fn eval(&self, path: &path::Path) -> bool {
2526
path.exists() == self.exists
2627
}
28+
29+
fn find_case<'a>(
30+
&'a self,
31+
expected: bool,
32+
variable: &path::Path,
33+
) -> Option<reflection::Case<'a>> {
34+
core::default_find_case(self, expected, variable)
35+
}
2736
}
2837

2938
impl reflection::PredicateReflection for ExistencePredicate {}

src/path/fs.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::fs;
1111
use std::io::{self, Read};
1212
use std::path;
1313

14+
use core;
1415
use reflection;
1516
use Predicate;
1617

@@ -59,12 +60,24 @@ impl Predicate<path::Path> for BinaryFilePredicate {
5960
fn eval(&self, path: &path::Path) -> bool {
6061
self.eval(path).unwrap_or(false)
6162
}
63+
64+
fn find_case<'a>(
65+
&'a self,
66+
expected: bool,
67+
variable: &path::Path,
68+
) -> Option<reflection::Case<'a>> {
69+
core::default_find_case(self, expected, variable)
70+
}
6271
}
6372

6473
impl Predicate<[u8]> for BinaryFilePredicate {
6574
fn eval(&self, actual: &[u8]) -> bool {
6675
self.content.debug == actual
6776
}
77+
78+
fn find_case<'a>(&'a self, expected: bool, variable: &[u8]) -> Option<reflection::Case<'a>> {
79+
core::default_find_case(self, expected, variable)
80+
}
6881
}
6982

7083
impl reflection::PredicateReflection for BinaryFilePredicate {
@@ -120,12 +133,24 @@ impl Predicate<path::Path> for StrFilePredicate {
120133
fn eval(&self, path: &path::Path) -> bool {
121134
self.eval(path).unwrap_or(false)
122135
}
136+
137+
fn find_case<'a>(
138+
&'a self,
139+
expected: bool,
140+
variable: &path::Path,
141+
) -> Option<reflection::Case<'a>> {
142+
core::default_find_case(self, expected, variable)
143+
}
123144
}
124145

125146
impl Predicate<str> for StrFilePredicate {
126147
fn eval(&self, actual: &str) -> bool {
127148
self.content == actual
128149
}
150+
151+
fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option<reflection::Case<'a>> {
152+
core::default_find_case(self, expected, variable)
153+
}
129154
}
130155

131156
impl reflection::PredicateReflection for StrFilePredicate {

src/str/basics.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
use std::fmt;
1010

11+
use core;
1112
use reflection;
1213
use Predicate;
1314

@@ -21,6 +22,10 @@ impl Predicate<str> for IsEmptyPredicate {
2122
fn eval(&self, variable: &str) -> bool {
2223
variable.is_empty()
2324
}
25+
26+
fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option<reflection::Case<'a>> {
27+
core::default_find_case(self, expected, variable)
28+
}
2429
}
2530

2631
impl reflection::PredicateReflection for IsEmptyPredicate {}
@@ -58,6 +63,10 @@ impl Predicate<str> for StartsWithPredicate {
5863
fn eval(&self, variable: &str) -> bool {
5964
variable.starts_with(&self.pattern)
6065
}
66+
67+
fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option<reflection::Case<'a>> {
68+
core::default_find_case(self, expected, variable)
69+
}
6170
}
6271

6372
impl reflection::PredicateReflection for StartsWithPredicate {}
@@ -100,6 +109,10 @@ impl Predicate<str> for EndsWithPredicate {
100109
fn eval(&self, variable: &str) -> bool {
101110
variable.ends_with(&self.pattern)
102111
}
112+
113+
fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option<reflection::Case<'a>> {
114+
core::default_find_case(self, expected, variable)
115+
}
103116
}
104117

105118
impl reflection::PredicateReflection for EndsWithPredicate {}
@@ -162,6 +175,10 @@ impl Predicate<str> for ContainsPredicate {
162175
fn eval(&self, variable: &str) -> bool {
163176
variable.contains(&self.pattern)
164177
}
178+
179+
fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option<reflection::Case<'a>> {
180+
core::default_find_case(self, expected, variable)
181+
}
165182
}
166183

167184
impl reflection::PredicateReflection for ContainsPredicate {}

src/str/regex.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::fmt;
1010

1111
use regex;
1212

13+
use core;
1314
use reflection;
1415
use Predicate;
1516

@@ -45,6 +46,10 @@ impl Predicate<str> for RegexPredicate {
4546
fn eval(&self, variable: &str) -> bool {
4647
self.re.is_match(variable)
4748
}
49+
50+
fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option<reflection::Case<'a>> {
51+
core::default_find_case(self, expected, variable)
52+
}
4853
}
4954

5055
impl reflection::PredicateReflection for RegexPredicate {}

0 commit comments

Comments
 (0)