Skip to content

fix(API): Switch from Associated Types to Generics #29

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 58 additions & 39 deletions src/boolean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,48 @@

//! Definition of boolean logic combinators over `Predicate`s.

use std::marker::PhantomData;

use Predicate;

/// Predicate that combines two `Predicate`s, returning the AND of the results.
///
/// This is created by the `Predicate::and` function.
#[derive(Debug)]
pub struct AndPredicate<M1, M2>
pub struct AndPredicate<M1, M2, Item>
where
M1: Predicate,
M2: Predicate<Item = M1::Item>,
M1: Predicate<Item>,
M2: Predicate<Item>,
Item: ?Sized,
{
a: M1,
b: M2,
_phantom: PhantomData<Item>,
}

impl<M1, M2> AndPredicate<M1, M2>
impl<M1, M2, Item> AndPredicate<M1, M2, Item>
where
M1: Predicate,
M2: Predicate<Item = M1::Item>,
M1: Predicate<Item>,
M2: Predicate<Item>,
Item: ?Sized,
{
/// Create a new `AndPredicate` over predicates `a` and `b`.
pub fn new(a: M1, b: M2) -> AndPredicate<M1, M2> {
AndPredicate { a: a, b: b }
pub fn new(a: M1, b: M2) -> AndPredicate<M1, M2, Item> {
AndPredicate {
a: a,
b: b,
_phantom: PhantomData,
}
}
}

impl<M1, M2> Predicate for AndPredicate<M1, M2>
impl<M1, M2, Item> Predicate<Item> for AndPredicate<M1, M2, Item>
where
M1: Predicate,
M2: Predicate<Item = M1::Item>,
M1: Predicate<Item>,
M2: Predicate<Item>,
Item: ?Sized,
{
type Item = M1::Item;

fn eval(&self, item: &Self::Item) -> bool {
fn eval(&self, item: &Item) -> bool {
self.a.eval(item) && self.b.eval(item)
}
}
Expand All @@ -50,34 +58,40 @@ where
///
/// This is created by the `Predicate::or` function.
#[derive(Debug)]
pub struct OrPredicate<M1, M2>
pub struct OrPredicate<M1, M2, Item>
where
M1: Predicate,
M2: Predicate<Item = M1::Item>,
M1: Predicate<Item>,
M2: Predicate<Item>,
Item: ?Sized,
{
a: M1,
b: M2,
_phantom: PhantomData<Item>,
}

impl<M1, M2> OrPredicate<M1, M2>
impl<M1, M2, Item> OrPredicate<M1, M2, Item>
where
M1: Predicate,
M2: Predicate<Item = M1::Item>,
M1: Predicate<Item>,
M2: Predicate<Item>,
Item: ?Sized,
{
/// Create a new `OrPredicate` over predicates `a` and `b`.
pub fn new(a: M1, b: M2) -> OrPredicate<M1, M2> {
OrPredicate { a: a, b: b }
pub fn new(a: M1, b: M2) -> OrPredicate<M1, M2, Item> {
OrPredicate {
a: a,
b: b,
_phantom: PhantomData,
}
}
}

impl<M1, M2> Predicate for OrPredicate<M1, M2>
impl<M1, M2, Item> Predicate<Item> for OrPredicate<M1, M2, Item>
where
M1: Predicate,
M2: Predicate<Item = M1::Item>,
M1: Predicate<Item>,
M2: Predicate<Item>,
Item: ?Sized,
{
type Item = M1::Item;

fn eval(&self, item: &Self::Item) -> bool {
fn eval(&self, item: &Item) -> bool {
self.a.eval(item) || self.b.eval(item)
}
}
Expand All @@ -86,30 +100,35 @@ where
///
/// This is created by the `Predicate::not` function.
#[derive(Debug)]
pub struct NotPredicate<M>
pub struct NotPredicate<M, Item>
where
M: Predicate,
M: Predicate<Item>,
Item: ?Sized,
{
inner: M,
_phantom: PhantomData<Item>,
}

impl<M> NotPredicate<M>
impl<M, Item> NotPredicate<M, Item>
where
M: Predicate,
M: Predicate<Item>,
Item: ?Sized,
{
/// Create a new `NotPredicate` over predicate `inner`.
pub fn new(inner: M) -> NotPredicate<M> {
NotPredicate { inner: inner }
pub fn new(inner: M) -> NotPredicate<M, Item> {
NotPredicate {
inner: inner,
_phantom: PhantomData,
}
}
}

impl<M> Predicate for NotPredicate<M>
impl<M, Item> Predicate<Item> for NotPredicate<M, Item>
where
M: Predicate,
M: Predicate<Item>,
Item: ?Sized,
{
type Item = M::Item;

fn eval(&self, item: &Self::Item) -> bool {
fn eval(&self, item: &Item) -> bool {
!self.inner.eval(item)
}
}
46 changes: 28 additions & 18 deletions src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,45 @@ use Predicate;

/// `Predicate` that wraps another `Predicate` as a trait object, allowing
/// sized storage of predicate types.
pub struct BoxPredicate<T: ?Sized>(Box<Predicate<Item = T> + Send + Sync>);
pub struct BoxPredicate<Item: ?Sized>(Box<Predicate<Item> + Send + Sync>);

impl<T> fmt::Debug for BoxPredicate<T> {
impl<Item> BoxPredicate<Item>
where
Item: ?Sized,
{
/// Creates a new `BoxPredicate`, a wrapper around a dynamically-dispatched
/// `Predicate` type with useful trait impls.
pub fn new<P: Predicate<Item>>(inner: P) -> BoxPredicate<Item>
where
P: Send + Sync + 'static,
{
BoxPredicate(Box::new(inner))
}
}

impl<Item> fmt::Debug for BoxPredicate<Item>
where
Item: ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BoxPredicate").finish()
}
}

impl<T> fmt::Display for BoxPredicate<T> {
impl<Item> fmt::Display for BoxPredicate<Item>
where
Item: ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "BoxPredicate")
}
}

impl<T: ?Sized> Predicate for BoxPredicate<T> {
type Item = T;

fn eval(&self, variable: &Self::Item) -> bool {
impl<Item> Predicate<Item> for BoxPredicate<Item>
where
Item: ?Sized,
{
fn eval(&self, variable: &Item) -> bool {
self.0.eval(variable)
}
}

impl<T: ?Sized> BoxPredicate<T> {
/// Creates a new `BoxPredicate`, a wrapper around a dynamically-dispatched
/// `Predicate` type with useful trait impls.
pub fn new<P: Predicate<Item = T>>(inner: P) -> BoxPredicate<T>
where
P: Send + Sync + 'static,
{
BoxPredicate(Box::new(inner))
}
}
14 changes: 6 additions & 8 deletions src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@ use Predicate;
///
/// This is created by the `predicate::always` and `predicate::never` functions.
#[derive(Debug)]
pub struct BooleanPredicate<T> {
pub struct BooleanPredicate<Item> {
retval: bool,
_phantom: PhantomData<T>,
_phantom: PhantomData<Item>,
}

impl<T> Predicate for BooleanPredicate<T> {
type Item = T;

fn eval(&self, _variable: &T) -> bool {
impl<Item> Predicate<Item> for BooleanPredicate<Item> {
fn eval(&self, _variable: &Item) -> bool {
self.retval
}
}
Expand All @@ -43,7 +41,7 @@ impl<T> Predicate for BooleanPredicate<T> {
/// // Won't work - Predicates can only operate on a single type
/// // assert_eq!(true, predicate_fn.eval("hello"))
/// ```
pub fn always<T>() -> BooleanPredicate<T> {
pub fn always<Item>() -> BooleanPredicate<Item> {
BooleanPredicate {
retval: true,
_phantom: PhantomData,
Expand All @@ -64,7 +62,7 @@ pub fn always<T>() -> BooleanPredicate<T> {
/// // Won't work - Predicates can only operate on a single type
/// // assert_eq!(false, predicate_fn.eval("hello"))
/// ```
pub fn never<T>() -> BooleanPredicate<T> {
pub fn never<Item>() -> BooleanPredicate<Item> {
BooleanPredicate {
retval: false,
_phantom: PhantomData,
Expand Down
19 changes: 8 additions & 11 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,10 @@ use boxed::BoxPredicate;
/// mean that the evaluated item is in some sort of pre-defined set. This is
/// different from `Ord` and `Eq` in that an `item` will almost never be the
/// same type as the implementing `Predicate` type.
pub trait Predicate {
/// The type that this `Predicate` will accept for evaluating.
type Item: ?Sized;

pub trait Predicate<Item: ?Sized> {
/// Execute this `Predicate` against `variable`, returning the resulting
/// boolean.
fn eval(&self, variable: &Self::Item) -> bool;
fn eval(&self, variable: &Item) -> bool;

/// Compute the logical AND of two `Predicate` results, returning the result.
///
Expand All @@ -35,9 +32,9 @@ pub trait Predicate {
/// let predicate_fn2 = predicate::always().and(predicate::never());
/// assert_eq!(true, predicate_fn1.eval(&4));
/// assert_eq!(false, predicate_fn2.eval(&4));
fn and<B>(self, other: B) -> AndPredicate<Self, B>
fn and<B>(self, other: B) -> AndPredicate<Self, B, Item>
where
B: Predicate<Item = Self::Item>,
B: Predicate<Item>,
Self: Sized,
{
AndPredicate::new(self, other)
Expand All @@ -56,9 +53,9 @@ pub trait Predicate {
/// assert_eq!(true, predicate_fn1.eval(&4));
/// assert_eq!(true, predicate_fn2.eval(&4));
/// assert_eq!(false, predicate_fn3.eval(&4));
fn or<B>(self, other: B) -> OrPredicate<Self, B>
fn or<B>(self, other: B) -> OrPredicate<Self, B, Item>
where
B: Predicate<Item = Self::Item>,
B: Predicate<Item>,
Self: Sized,
{
OrPredicate::new(self, other)
Expand All @@ -75,7 +72,7 @@ pub trait Predicate {
/// let predicate_fn2 = predicate::never().not();
/// assert_eq!(false, predicate_fn1.eval(&4));
/// assert_eq!(true, predicate_fn2.eval(&4));
fn not(self) -> NotPredicate<Self>
fn not(self) -> NotPredicate<Self, Item>
where
Self: Sized,
{
Expand Down Expand Up @@ -106,7 +103,7 @@ pub trait Predicate {
/// assert_eq!(true, predicates[0].eval(&4));
/// assert_eq!(false, predicates[1].eval(&4));
/// ```
fn boxed(self) -> BoxPredicate<Self::Item>
fn boxed(self) -> BoxPredicate<Item>
where
Self: Sized + Send + Sync + 'static,
{
Expand Down
4 changes: 1 addition & 3 deletions src/float/close.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,7 @@ impl IsClosePredicate {
}
}

impl Predicate for IsClosePredicate {
type Item = f64;

impl Predicate<f64> for IsClosePredicate {
fn eval(&self, variable: &f64) -> bool {
variable.approx_eq(&self.target, self.epsilon, self.ulps)
}
Expand Down
4 changes: 1 addition & 3 deletions src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@ where
_phantom: PhantomData<T>,
}

impl<F, T> Predicate for FnPredicate<F, T>
impl<F, T> Predicate<T> for FnPredicate<F, T>
where
F: Fn(&T) -> bool,
{
type Item = T;

fn eval(&self, variable: &T) -> bool {
(self.function)(variable)
}
Expand Down
5 changes: 2 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,8 @@
//! // returns a `bool`. Implementing a custom `Predicate` still allows all the
//! // usual combinators of the `Predicate` trait to work!
//! struct IsTheAnswer;
//! impl Predicate for IsTheAnswer {
//! type Item = i32;
//! fn eval(&self, variable: &Self::Item) -> bool {
//! impl Predicate<i32> for IsTheAnswer {
//! fn eval(&self, variable: &i32) -> bool {
//! *variable == 42
//! }
//! }
Expand Down
12 changes: 4 additions & 8 deletions src/ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,11 @@ pub struct EqPredicate<T> {
op: EqOps,
}

impl<T> Predicate for EqPredicate<T>
impl<T> Predicate<T> for EqPredicate<T>
where
T: PartialEq,
{
type Item = T;

fn eval(&self, variable: &Self::Item) -> bool {
fn eval(&self, variable: &T) -> bool {
match self.op {
EqOps::Equal => variable.eq(&self.constant),
EqOps::NotEqual => variable.ne(&self.constant),
Expand Down Expand Up @@ -102,13 +100,11 @@ pub struct OrdPredicate<T> {
op: OrdOps,
}

impl<T> Predicate for OrdPredicate<T>
impl<T> Predicate<T> for OrdPredicate<T>
where
T: PartialOrd,
{
type Item = T;

fn eval(&self, variable: &Self::Item) -> bool {
fn eval(&self, variable: &T) -> bool {
match self.op {
OrdOps::LessThan => variable.lt(&self.constant),
OrdOps::LessThanOrEqual => variable.le(&self.constant),
Expand Down
Loading