Skip to content

Commit 3cf8a3a

Browse files
committed
feat: Add basic reflection
Predicates can now report parameter details that don't show up in `Display` as well as what children they have. The expectation is that this will be used by the solution for #7. This also saw an audit of predicates to ensure their `Display` would most likely remain as one line of text. Anything in a `Display` that seemed likely to overflow was moved to a `Parameter. BREAKING CHANGE: `Predicate`s must also implement `reflection::PredicateReflection`.
1 parent 3dcff14 commit 3cf8a3a

19 files changed

+565
-33
lines changed

src/boolean.rs

Lines changed: 57 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 reflection;
1415
use Predicate;
1516

1617
/// Predicate that combines two `Predicate`s, returning the AND of the results.
@@ -55,6 +56,26 @@ where
5556
}
5657
}
5758

59+
impl<M1, M2, Item> reflection::PredicateReflection for AndPredicate<M1, M2, Item>
60+
where
61+
M1: Predicate<Item>,
62+
M2: Predicate<Item>,
63+
Item: ?Sized,
64+
{
65+
fn parameters<'a>(&'a self) -> Box<Iterator<Item = reflection::Parameter<'a>> + 'a> {
66+
let params = vec![];
67+
Box::new(params.into_iter())
68+
}
69+
70+
fn children<'a>(&'a self) -> Box<Iterator<Item = reflection::Child<'a>> + 'a> {
71+
let params = vec![
72+
reflection::Child::new("left", &self.a),
73+
reflection::Child::new("right", &self.b),
74+
];
75+
Box::new(params.into_iter())
76+
}
77+
}
78+
5879
impl<M1, M2, Item> fmt::Display for AndPredicate<M1, M2, Item>
5980
where
6081
M1: Predicate<Item>,
@@ -108,6 +129,26 @@ where
108129
}
109130
}
110131

132+
impl<M1, M2, Item> reflection::PredicateReflection for OrPredicate<M1, M2, Item>
133+
where
134+
M1: Predicate<Item>,
135+
M2: Predicate<Item>,
136+
Item: ?Sized,
137+
{
138+
fn parameters<'a>(&'a self) -> Box<Iterator<Item = reflection::Parameter<'a>> + 'a> {
139+
let params = vec![];
140+
Box::new(params.into_iter())
141+
}
142+
143+
fn children<'a>(&'a self) -> Box<Iterator<Item = reflection::Child<'a>> + 'a> {
144+
let params = vec![
145+
reflection::Child::new("left", &self.a),
146+
reflection::Child::new("right", &self.b),
147+
];
148+
Box::new(params.into_iter())
149+
}
150+
}
151+
111152
impl<M1, M2, Item> fmt::Display for OrPredicate<M1, M2, Item>
112153
where
113154
M1: Predicate<Item>,
@@ -156,6 +197,22 @@ where
156197
}
157198
}
158199

200+
impl<M, Item> reflection::PredicateReflection for NotPredicate<M, Item>
201+
where
202+
M: Predicate<Item>,
203+
Item: ?Sized,
204+
{
205+
fn parameters<'a>(&'a self) -> Box<Iterator<Item = reflection::Parameter<'a>> + 'a> {
206+
let params = vec![];
207+
Box::new(params.into_iter())
208+
}
209+
210+
fn children<'a>(&'a self) -> Box<Iterator<Item = reflection::Child<'a>> + 'a> {
211+
let params = vec![reflection::Child::new("predicate", &self.inner)];
212+
Box::new(params.into_iter())
213+
}
214+
}
215+
159216
impl<M, Item> fmt::Display for NotPredicate<M, Item>
160217
where
161218
M: Predicate<Item>,

src/boxed.rs

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

14+
use reflection;
1415
use Predicate;
1516

1617
/// `Predicate` that wraps another `Predicate` as a trait object, allowing
@@ -40,6 +41,19 @@ where
4041
}
4142
}
4243

44+
impl<Item> reflection::PredicateReflection for BoxPredicate<Item>
45+
where
46+
Item: ?Sized,
47+
{
48+
fn parameters<'a>(&'a self) -> Box<Iterator<Item = reflection::Parameter<'a>> + 'a> {
49+
self.0.parameters()
50+
}
51+
52+
fn children<'a>(&'a self) -> Box<Iterator<Item = reflection::Child<'a>> + 'a> {
53+
self.0.children()
54+
}
55+
}
56+
4357
impl<Item> fmt::Display for BoxPredicate<Item>
4458
where
4559
Item: ?Sized,

src/constant.rs

Lines changed: 13 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 reflection;
1415
use Predicate;
1516

1617
/// Predicate that always returns a constant (boolean) result.
@@ -28,6 +29,18 @@ impl<Item> Predicate<Item> for BooleanPredicate<Item> {
2829
}
2930
}
3031

32+
impl<Item> reflection::PredicateReflection for BooleanPredicate<Item> {
33+
fn parameters<'a>(&'a self) -> Box<Iterator<Item = reflection::Parameter<'a>> + 'a> {
34+
let params = vec![reflection::Parameter::new("value", &self.retval)];
35+
Box::new(params.into_iter())
36+
}
37+
38+
fn children<'a>(&'a self) -> Box<Iterator<Item = reflection::Child<'a>>> {
39+
let params = vec![];
40+
Box::new(params.into_iter())
41+
}
42+
}
43+
3144
impl<Item> fmt::Display for BooleanPredicate<Item> {
3245
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3346
write!(f, "{}", self.retval)

src/core.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9-
use std::fmt;
9+
use reflection;
1010

1111
/// Trait for generically evaluating a type against a dynamically created
1212
/// predicate function.
@@ -15,7 +15,7 @@ use std::fmt;
1515
/// mean that the evaluated item is in some sort of pre-defined set. This is
1616
/// different from `Ord` and `Eq` in that an `item` will almost never be the
1717
/// same type as the implementing `Predicate` type.
18-
pub trait Predicate<Item: ?Sized>: fmt::Display {
18+
pub trait Predicate<Item: ?Sized>: reflection::PredicateReflection {
1919
/// Execute this `Predicate` against `variable`, returning the resulting
2020
/// boolean.
2121
fn eval(&self, variable: &Item) -> bool;

src/float/close.rs

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

14+
use reflection;
1415
use Predicate;
1516

1617
/// Predicate that ensures two numbers are "close" enough, understanding that rounding errors
@@ -86,13 +87,24 @@ impl Predicate<f64> for IsClosePredicate {
8687
}
8788
}
8889

90+
impl reflection::PredicateReflection for IsClosePredicate {
91+
fn parameters<'a>(&'a self) -> Box<Iterator<Item = reflection::Parameter<'a>> + 'a> {
92+
let params = vec![
93+
reflection::Parameter::new("epsilon", &self.epsilon),
94+
reflection::Parameter::new("ulps", &self.ulps),
95+
];
96+
Box::new(params.into_iter())
97+
}
98+
99+
fn children<'a>(&'a self) -> Box<Iterator<Item = reflection::Child<'a>>> {
100+
let params = vec![];
101+
Box::new(params.into_iter())
102+
}
103+
}
104+
89105
impl fmt::Display for IsClosePredicate {
90106
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91-
write!(
92-
f,
93-
"var ~= {} +/- {} ({})",
94-
self.target, self.epsilon, self.ulps
95-
)
107+
write!(f, "var ~= {}", self.target)
96108
}
97109
}
98110

src/function.rs

Lines changed: 16 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 reflection;
1415
use Predicate;
1516

1617
/// Predicate that wraps a function over a reference that returns a `bool`.
@@ -60,6 +61,21 @@ where
6061
}
6162
}
6263

64+
impl<F, T> reflection::PredicateReflection for FnPredicate<F, T>
65+
where
66+
F: Fn(&T) -> bool,
67+
{
68+
fn parameters<'a>(&'a self) -> Box<Iterator<Item = reflection::Parameter<'a>> + 'a> {
69+
let params = vec![];
70+
Box::new(params.into_iter())
71+
}
72+
73+
fn children<'a>(&'a self) -> Box<Iterator<Item = reflection::Child<'a>>> {
74+
let params = vec![];
75+
Box::new(params.into_iter())
76+
}
77+
}
78+
6379
impl<F, T> fmt::Display for FnPredicate<F, T>
6480
where
6581
F: Fn(&T) -> bool,

0 commit comments

Comments
 (0)