Skip to content

Commit 034edfd

Browse files
authored
Merge pull request #36 from epage/trait
Focus on extension traits
2 parents 8471493 + b929216 commit 034edfd

File tree

6 files changed

+220
-92
lines changed

6 files changed

+220
-92
lines changed

src/boolean.rs

+71
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,74 @@ where
132132
!self.inner.eval(item)
133133
}
134134
}
135+
136+
/// `Predicate` extension that adds boolean logic.
137+
pub trait PredicateBooleanExt<Item: ?Sized>
138+
where
139+
Self: Predicate<Item>,
140+
{
141+
/// Compute the logical AND of two `Predicate` results, returning the result.
142+
///
143+
/// # Examples
144+
///
145+
/// ```
146+
/// use predicates::prelude::*;
147+
///
148+
/// let predicate_fn1 = predicate::always().and(predicate::always());
149+
/// let predicate_fn2 = predicate::always().and(predicate::never());
150+
/// assert_eq!(true, predicate_fn1.eval(&4));
151+
/// assert_eq!(false, predicate_fn2.eval(&4));
152+
fn and<B>(self, other: B) -> AndPredicate<Self, B, Item>
153+
where
154+
B: Predicate<Item>,
155+
Self: Sized,
156+
{
157+
AndPredicate::new(self, other)
158+
}
159+
160+
/// Compute the logical OR of two `Predicate` results, returning the result.
161+
///
162+
/// # Examples
163+
///
164+
/// ```
165+
/// use predicates::prelude::*;
166+
///
167+
/// let predicate_fn1 = predicate::always().or(predicate::always());
168+
/// let predicate_fn2 = predicate::always().or(predicate::never());
169+
/// let predicate_fn3 = predicate::never().or(predicate::never());
170+
/// assert_eq!(true, predicate_fn1.eval(&4));
171+
/// assert_eq!(true, predicate_fn2.eval(&4));
172+
/// assert_eq!(false, predicate_fn3.eval(&4));
173+
fn or<B>(self, other: B) -> OrPredicate<Self, B, Item>
174+
where
175+
B: Predicate<Item>,
176+
Self: Sized,
177+
{
178+
OrPredicate::new(self, other)
179+
}
180+
181+
/// Compute the logical NOT of a `Predicate`, returning the result.
182+
///
183+
/// # Examples
184+
///
185+
/// ```
186+
/// use predicates::prelude::*;
187+
///
188+
/// let predicate_fn1 = predicate::always().not();
189+
/// let predicate_fn2 = predicate::never().not();
190+
/// assert_eq!(false, predicate_fn1.eval(&4));
191+
/// assert_eq!(true, predicate_fn2.eval(&4));
192+
fn not(self) -> NotPredicate<Self, Item>
193+
where
194+
Self: Sized,
195+
{
196+
NotPredicate::new(self)
197+
}
198+
}
199+
200+
impl<P, Item> PredicateBooleanExt<Item> for P
201+
where
202+
P: Predicate<Item>,
203+
Item: ?Sized,
204+
{
205+
}

src/boxed.rs

+43
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,46 @@ where
5757
self.0.eval(variable)
5858
}
5959
}
60+
61+
/// `Predicate` extension for boxing a `Predicate`.
62+
pub trait PredicateBoxExt<Item: ?Sized>
63+
where
64+
Self: Predicate<Item>,
65+
{
66+
/// Returns a `BoxPredicate` wrapper around this `Predicate` type.
67+
///
68+
/// Returns a `BoxPredicate` wrapper around this `Predicate type. The
69+
/// `BoxPredicate` type has a number of useful properties:
70+
///
71+
/// - It stores the inner predicate as a trait object, so the type of
72+
/// `BoxPredicate` will always be the same even if steps are added or
73+
/// removed from the predicate.
74+
/// - It is a common type, allowing it to be stored in vectors or other
75+
/// collection types.
76+
/// - It implements `Debug` and `Display`.
77+
///
78+
/// # Examples
79+
///
80+
/// ```
81+
/// use predicates::prelude::*;
82+
///
83+
/// let predicates = vec![
84+
/// predicate::always().boxed(),
85+
/// predicate::never().boxed(),
86+
/// ];
87+
/// assert_eq!(true, predicates[0].eval(&4));
88+
/// assert_eq!(false, predicates[1].eval(&4));
89+
/// ```
90+
fn boxed(self) -> BoxPredicate<Item>
91+
where
92+
Self: Sized + Send + Sync + 'static,
93+
{
94+
BoxPredicate::new(self)
95+
}
96+
}
97+
98+
impl<P, Item> PredicateBoxExt<Item> for P
99+
where
100+
P: Predicate<Item>,
101+
{
102+
}

src/core.rs

-92
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9-
use boolean::{AndPredicate, NotPredicate, OrPredicate};
10-
use boxed::BoxPredicate;
11-
129
/// Trait for generically evaluating a type against a dynamically created
1310
/// predicate function.
1411
///
@@ -20,93 +17,4 @@ pub trait Predicate<Item: ?Sized> {
2017
/// Execute this `Predicate` against `variable`, returning the resulting
2118
/// boolean.
2219
fn eval(&self, variable: &Item) -> bool;
23-
24-
/// Compute the logical AND of two `Predicate` results, returning the result.
25-
///
26-
/// # Examples
27-
///
28-
/// ```
29-
/// use predicates::prelude::*;
30-
///
31-
/// let predicate_fn1 = predicate::always().and(predicate::always());
32-
/// let predicate_fn2 = predicate::always().and(predicate::never());
33-
/// assert_eq!(true, predicate_fn1.eval(&4));
34-
/// assert_eq!(false, predicate_fn2.eval(&4));
35-
fn and<B>(self, other: B) -> AndPredicate<Self, B, Item>
36-
where
37-
B: Predicate<Item>,
38-
Self: Sized,
39-
{
40-
AndPredicate::new(self, other)
41-
}
42-
43-
/// Compute the logical OR of two `Predicate` results, returning the result.
44-
///
45-
/// # Examples
46-
///
47-
/// ```
48-
/// use predicates::prelude::*;
49-
///
50-
/// let predicate_fn1 = predicate::always().or(predicate::always());
51-
/// let predicate_fn2 = predicate::always().or(predicate::never());
52-
/// let predicate_fn3 = predicate::never().or(predicate::never());
53-
/// assert_eq!(true, predicate_fn1.eval(&4));
54-
/// assert_eq!(true, predicate_fn2.eval(&4));
55-
/// assert_eq!(false, predicate_fn3.eval(&4));
56-
fn or<B>(self, other: B) -> OrPredicate<Self, B, Item>
57-
where
58-
B: Predicate<Item>,
59-
Self: Sized,
60-
{
61-
OrPredicate::new(self, other)
62-
}
63-
64-
/// Compute the logical NOT of a `Predicate`, returning the result.
65-
///
66-
/// # Examples
67-
///
68-
/// ```
69-
/// use predicates::prelude::*;
70-
///
71-
/// let predicate_fn1 = predicate::always().not();
72-
/// let predicate_fn2 = predicate::never().not();
73-
/// assert_eq!(false, predicate_fn1.eval(&4));
74-
/// assert_eq!(true, predicate_fn2.eval(&4));
75-
fn not(self) -> NotPredicate<Self, Item>
76-
where
77-
Self: Sized,
78-
{
79-
NotPredicate::new(self)
80-
}
81-
82-
/// Returns a `BoxPredicate` wrapper around this `Predicate` type.
83-
///
84-
/// Returns a `BoxPredicate` wrapper around this `Predicate type. The
85-
/// `BoxPredicate` type has a number of useful properties:
86-
///
87-
/// - It stores the inner predicate as a trait object, so the type of
88-
/// `BoxPredicate` will always be the same even if steps are added or
89-
/// removed from the predicate.
90-
/// - It is a common type, allowing it to be stored in vectors or other
91-
/// collection types.
92-
/// - It implements `Debug` and `Display`.
93-
///
94-
/// # Examples
95-
///
96-
/// ```
97-
/// use predicates::prelude::*;
98-
///
99-
/// let predicates = vec![
100-
/// predicate::always().boxed(),
101-
/// predicate::never().boxed(),
102-
/// ];
103-
/// assert_eq!(true, predicates[0].eval(&4));
104-
/// assert_eq!(false, predicates[1].eval(&4));
105-
/// ```
106-
fn boxed(self) -> BoxPredicate<Item>
107-
where
108-
Self: Sized + Send + Sync + 'static,
109-
{
110-
BoxPredicate::new(self)
111-
}
11220
}

src/prelude.rs

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
//! Module that contains the essentials for working with predicates.
1010
1111
pub use core::Predicate;
12+
pub use boolean::PredicateBooleanExt;
13+
pub use boxed::PredicateBoxExt;
14+
pub use str::PredicateStrExt;
1215

1316
/// Predicate factories
1417
pub mod predicate {

src/str/adapters.rs

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use std::ffi;
2+
use std::str;
3+
4+
use Predicate;
5+
6+
/// Predicate adaper that trims the variable being tested.
7+
///
8+
/// This is created by `pred.trim()`.
9+
#[derive(Copy, Clone, Debug)]
10+
pub struct TrimPedicate<P>
11+
where
12+
P: Predicate<str>,
13+
{
14+
p: P,
15+
}
16+
17+
impl<P> Predicate<str> for TrimPedicate<P>
18+
where
19+
P: Predicate<str>,
20+
{
21+
fn eval(&self, variable: &str) -> bool {
22+
self.p.eval(variable.trim())
23+
}
24+
}
25+
26+
/// Predicate adaper that converts a `str` predicate to byte predicate.
27+
///
28+
/// This is created by `pred.from_utf8()`.
29+
#[derive(Copy, Clone, Debug)]
30+
pub struct Utf8Pedicate<P>
31+
where
32+
P: Predicate<str>,
33+
{
34+
p: P,
35+
}
36+
37+
impl<P> Predicate<ffi::OsStr> for Utf8Pedicate<P>
38+
where
39+
P: Predicate<str>,
40+
{
41+
fn eval(&self, variable: &ffi::OsStr) -> bool {
42+
variable.to_str().map(|s| self.p.eval(s)).unwrap_or(false)
43+
}
44+
}
45+
46+
impl<P> Predicate<[u8]> for Utf8Pedicate<P>
47+
where
48+
P: Predicate<str>,
49+
{
50+
fn eval(&self, variable: &[u8]) -> bool {
51+
str::from_utf8(variable)
52+
.map(|s| self.p.eval(s))
53+
.unwrap_or(false)
54+
}
55+
}
56+
57+
/// `Predicate` extension adapting a `str` Predicate.
58+
pub trait PredicateStrExt
59+
where
60+
Self: Predicate<str>,
61+
Self: Sized,
62+
{
63+
/// Returns a `TrimPedicate` that ensures the data passed to `Self` is trimmed.
64+
///
65+
/// # Examples
66+
///
67+
/// ```
68+
/// use predicates::prelude::*;
69+
///
70+
/// let predicate_fn = predicate::str::is_empty().trim();
71+
/// assert_eq!(true, predicate_fn.eval(" "));
72+
/// assert_eq!(false, predicate_fn.eval(" Hello "));
73+
/// ```
74+
fn trim(self) -> TrimPedicate<Self> {
75+
TrimPedicate { p: self }
76+
}
77+
78+
/// Returns a `Utf8Pedicate` that adapts `Self` to a `[u8]` `Predicate`.
79+
///
80+
/// # Examples
81+
///
82+
/// ```
83+
/// use predicates::prelude::*;
84+
/// use std::ffi::OsStr;
85+
///
86+
/// let predicate_fn = predicate::str::is_empty().not().from_utf8();
87+
/// assert_eq!(true, predicate_fn.eval(OsStr::new("Hello")));
88+
/// assert_eq!(false, predicate_fn.eval(OsStr::new("")));
89+
/// let variable: &[u8] = b"";
90+
/// assert_eq!(false, predicate_fn.eval(variable));
91+
/// ```
92+
fn from_utf8(self) -> Utf8Pedicate<Self> {
93+
Utf8Pedicate { p: self }
94+
}
95+
}
96+
97+
impl<P> PredicateStrExt for P
98+
where
99+
P: Predicate<str>,
100+
{
101+
}

src/str/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
1313
mod basics;
1414
pub use self::basics::*;
15+
mod adapters;
16+
pub use self::adapters::*;
1517

1618
#[cfg(feature = "difference")]
1719
mod difference;

0 commit comments

Comments
 (0)