Skip to content
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
71 changes: 71 additions & 0 deletions src/boolean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,74 @@ where
!self.inner.eval(item)
}
}

/// `Predicate` extension that adds boolean logic.
pub trait PredicateBooleanExt<Item: ?Sized>
where
Self: Predicate<Item>,
{
/// Compute the logical AND of two `Predicate` results, returning the result.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn1 = predicate::always().and(predicate::always());
/// 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, Item>
where
B: Predicate<Item>,
Self: Sized,
{
AndPredicate::new(self, other)
}

/// Compute the logical OR of two `Predicate` results, returning the result.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn1 = predicate::always().or(predicate::always());
/// let predicate_fn2 = predicate::always().or(predicate::never());
/// let predicate_fn3 = predicate::never().or(predicate::never());
/// 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, Item>
where
B: Predicate<Item>,
Self: Sized,
{
OrPredicate::new(self, other)
}

/// Compute the logical NOT of a `Predicate`, returning the result.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn1 = predicate::always().not();
/// 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, Item>
where
Self: Sized,
{
NotPredicate::new(self)
}
}

impl<P, Item> PredicateBooleanExt<Item> for P
where
P: Predicate<Item>,
Item: ?Sized,
{
}
43 changes: 43 additions & 0 deletions src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,46 @@ where
self.0.eval(variable)
}
}

/// `Predicate` extension for boxing a `Predicate`.
pub trait PredicateBoxExt<Item: ?Sized>
where
Self: Predicate<Item>,
{
/// Returns a `BoxPredicate` wrapper around this `Predicate` type.
///
/// Returns a `BoxPredicate` wrapper around this `Predicate type. The
/// `BoxPredicate` type has a number of useful properties:
///
/// - It stores the inner predicate as a trait object, so the type of
/// `BoxPredicate` will always be the same even if steps are added or
/// removed from the predicate.
/// - It is a common type, allowing it to be stored in vectors or other
/// collection types.
/// - It implements `Debug` and `Display`.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicates = vec![
/// predicate::always().boxed(),
/// predicate::never().boxed(),
/// ];
/// assert_eq!(true, predicates[0].eval(&4));
/// assert_eq!(false, predicates[1].eval(&4));
/// ```
fn boxed(self) -> BoxPredicate<Item>
where
Self: Sized + Send + Sync + 'static,
{
BoxPredicate::new(self)
}
}

impl<P, Item> PredicateBoxExt<Item> for P
where
P: Predicate<Item>,
{
}
92 changes: 0 additions & 92 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use boolean::{AndPredicate, NotPredicate, OrPredicate};
use boxed::BoxPredicate;

/// Trait for generically evaluating a type against a dynamically created
/// predicate function.
///
Expand All @@ -20,93 +17,4 @@ pub trait Predicate<Item: ?Sized> {
/// Execute this `Predicate` against `variable`, returning the resulting
/// boolean.
fn eval(&self, variable: &Item) -> bool;

/// Compute the logical AND of two `Predicate` results, returning the result.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn1 = predicate::always().and(predicate::always());
/// 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, Item>
where
B: Predicate<Item>,
Self: Sized,
{
AndPredicate::new(self, other)
}

/// Compute the logical OR of two `Predicate` results, returning the result.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn1 = predicate::always().or(predicate::always());
/// let predicate_fn2 = predicate::always().or(predicate::never());
/// let predicate_fn3 = predicate::never().or(predicate::never());
/// 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, Item>
where
B: Predicate<Item>,
Self: Sized,
{
OrPredicate::new(self, other)
}

/// Compute the logical NOT of a `Predicate`, returning the result.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn1 = predicate::always().not();
/// 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, Item>
where
Self: Sized,
{
NotPredicate::new(self)
}

/// Returns a `BoxPredicate` wrapper around this `Predicate` type.
///
/// Returns a `BoxPredicate` wrapper around this `Predicate type. The
/// `BoxPredicate` type has a number of useful properties:
///
/// - It stores the inner predicate as a trait object, so the type of
/// `BoxPredicate` will always be the same even if steps are added or
/// removed from the predicate.
/// - It is a common type, allowing it to be stored in vectors or other
/// collection types.
/// - It implements `Debug` and `Display`.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicates = vec![
/// predicate::always().boxed(),
/// predicate::never().boxed(),
/// ];
/// assert_eq!(true, predicates[0].eval(&4));
/// assert_eq!(false, predicates[1].eval(&4));
/// ```
fn boxed(self) -> BoxPredicate<Item>
where
Self: Sized + Send + Sync + 'static,
{
BoxPredicate::new(self)
}
}
3 changes: 3 additions & 0 deletions src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
//! Module that contains the essentials for working with predicates.

pub use core::Predicate;
pub use boolean::PredicateBooleanExt;
pub use boxed::PredicateBoxExt;
pub use str::PredicateStrExt;

/// Predicate factories
pub mod predicate {
Expand Down
101 changes: 101 additions & 0 deletions src/str/adapters.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use std::ffi;
use std::str;

use Predicate;

/// Predicate adaper that trims the variable being tested.
///
/// This is created by `pred.trim()`.
#[derive(Copy, Clone, Debug)]
pub struct TrimPedicate<P>
where
P: Predicate<str>,
{
p: P,
}

impl<P> Predicate<str> for TrimPedicate<P>
where
P: Predicate<str>,
{
fn eval(&self, variable: &str) -> bool {
self.p.eval(variable.trim())
}
}

/// Predicate adaper that converts a `str` predicate to byte predicate.
///
/// This is created by `pred.from_utf8()`.
#[derive(Copy, Clone, Debug)]
pub struct Utf8Pedicate<P>
where
P: Predicate<str>,
{
p: P,
}

impl<P> Predicate<ffi::OsStr> for Utf8Pedicate<P>
where
P: Predicate<str>,
{
fn eval(&self, variable: &ffi::OsStr) -> bool {
variable.to_str().map(|s| self.p.eval(s)).unwrap_or(false)
}
}

impl<P> Predicate<[u8]> for Utf8Pedicate<P>
where
P: Predicate<str>,
{
fn eval(&self, variable: &[u8]) -> bool {
str::from_utf8(variable)
.map(|s| self.p.eval(s))
.unwrap_or(false)
}
}

/// `Predicate` extension adapting a `str` Predicate.
pub trait PredicateStrExt
where
Self: Predicate<str>,
Self: Sized,
{
/// Returns a `TrimPedicate` that ensures the data passed to `Self` is trimmed.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::str::is_empty().trim();
/// assert_eq!(true, predicate_fn.eval(" "));
/// assert_eq!(false, predicate_fn.eval(" Hello "));
/// ```
fn trim(self) -> TrimPedicate<Self> {
TrimPedicate { p: self }
}

/// Returns a `Utf8Pedicate` that adapts `Self` to a `[u8]` `Predicate`.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
/// use std::ffi::OsStr;
///
/// let predicate_fn = predicate::str::is_empty().not().from_utf8();
/// assert_eq!(true, predicate_fn.eval(OsStr::new("Hello")));
/// assert_eq!(false, predicate_fn.eval(OsStr::new("")));
/// let variable: &[u8] = b"";
/// assert_eq!(false, predicate_fn.eval(variable));
/// ```
fn from_utf8(self) -> Utf8Pedicate<Self> {
Utf8Pedicate { p: self }
}
}

impl<P> PredicateStrExt for P
where
P: Predicate<str>,
{
}
2 changes: 2 additions & 0 deletions src/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

mod basics;
pub use self::basics::*;
mod adapters;
pub use self::adapters::*;

#[cfg(feature = "difference")]
mod difference;
Expand Down