use std::borrow::Borrow;
pub use failable::ops::and::FailableAnd;
pub use failable::ops::bool::FailableBool;
pub use failable::ops::not::FailableNot;
pub use failable::ops::xor::FailableXOr;
pub use failable::ops::or::FailableOr;
pub use failable::ops::map::{FailableMapInput, FailableMapErr};
pub trait IntoFailableFilter<N> {
type IntoFilt: FailableFilter<N>;
fn into_failable_filter(self) -> Self::IntoFilt;
}
impl<N, I: FailableFilter<N>> IntoFailableFilter<N> for I {
type IntoFilt = I;
fn into_failable_filter(self) -> Self::IntoFilt {
self
}
}
pub trait FailableFilter<N> {
type Error: Sized;
fn filter(&self, &N) -> Result<bool, Self::Error>;
fn not(self) -> FailableNot<Self>
where Self: Sized
{
FailableNot::new(self)
}
fn or<F>(self, other: F) -> FailableOr<Self, F::IntoFilt>
where Self: Sized,
F: IntoFailableFilter<N> + Sized
{
FailableOr::new(self, other.into_failable_filter())
}
fn or_not<F>(self, other: F) -> FailableOr<Self, FailableNot<F::IntoFilt>>
where Self: Sized,
F: IntoFailableFilter<N> + Sized,
{
self.or(FailableNot::new(other.into_failable_filter()))
}
fn or3<F, F2>(self, other: F, other2: F2) -> FailableOr<Self, FailableOr<F::IntoFilt, F2::IntoFilt>>
where Self: Sized,
F: IntoFailableFilter<N> + Sized,
F2: IntoFailableFilter<N> + Sized
{
FailableOr::new(self, FailableOr::new(other.into_failable_filter(), other2.into_failable_filter()))
}
fn nor<F>(self, other: F) -> FailableNot<FailableOr<Self, F>>
where Self: Sized,
{
FailableNot::new(FailableOr::new(self, other))
}
fn xor<F>(self, other: F) -> FailableXOr<Self, F>
where Self: Sized,
{
FailableXOr::new(self, other)
}
fn and<F>(self, other: F) -> FailableAnd<Self, F::IntoFilt>
where Self: Sized,
F: IntoFailableFilter<N> + Sized
{
FailableAnd::new(self, other.into_failable_filter())
}
fn and3<F, F2>(self, other: F, other2: F2) -> FailableAnd<Self, FailableAnd<F::IntoFilt, F2::IntoFilt>>
where Self: Sized,
F: IntoFailableFilter<N> + Sized,
F2: IntoFailableFilter<N> + Sized
{
FailableAnd::new(self, FailableAnd::new(other.into_failable_filter(), other2.into_failable_filter()))
}
fn and_not<F>(self, other: F) -> FailableAnd<Self, FailableNot<F::IntoFilt>>
where Self: Sized,
F: IntoFailableFilter<N> + Sized
{
self.and(FailableNot::new(other.into_failable_filter()))
}
fn nand<F>(self, other: F) -> FailableNot<FailableAnd<Self, F>>
where Self: Sized,
{
FailableNot::new(FailableAnd::new(self, other))
}
fn map_input<O, B, T, M>(self, map: M) -> FailableMapInput<Self, M, O, B>
where Self: Sized,
M: Fn(&T) -> N,
B: Borrow<O> + Sized
{
FailableMapInput::new(self, map)
}
fn map_err<M, OE>(self, map: M) -> FailableMapErr<Self, M, OE>
where Self: Sized,
M: Fn(Self::Error) -> OE
{
FailableMapErr::new(self, map)
}
}
impl<I, E, T> FailableFilter<I> for T
where T: Fn(&I) -> Result<bool, E>
{
type Error = E;
fn filter(&self, other: &I) -> Result<bool, Self::Error> {
self(other)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug)]
struct StupError { }
#[test]
fn compile_test() {
let a = |_: &i32| -> Result<bool, StupError> { Ok(true) };
assert!(a.filter(&1).unwrap());
}
#[test]
fn test_error_return() {
let a = |_: &i32| -> Result<bool, StupError> { Err(StupError {}) };
assert!(a.filter(&1).is_err());
}
#[test]
fn test_error_return_and_chained() {
let a = |_: &i32| -> Result<bool, StupError> { Err(StupError {}) };
let b = |_: &i32| -> Result<bool, StupError> { Ok(true) };
let c = |_: &i32| -> Result<bool, StupError> { Ok(true) };
let d = |_: &i32| -> Result<bool, StupError> { Ok(true) };
let e = d.and(b).and(c).and(a);
assert!(e.filter(&1).is_err());
}
#[test]
fn test_error_return_or_chained() {
let a = |_: &i32| -> Result<bool, StupError> { Err(StupError {}) };
let b = |_: &i32| -> Result<bool, StupError> { Ok(true) };
let c = |_: &i32| -> Result<bool, StupError> { Ok(true) };
let d = |_: &i32| -> Result<bool, StupError> { Ok(true) };
let e = a.or(b).or(c).or(d);
assert!(e.filter(&1).is_err());
}
#[test]
fn test_both_filter_types() {
use filter::Filter;
let a = |_: &i32| -> Result<bool, StupError> { Ok(true) };
let b = |_: &i32| -> bool { true };
let c = |_: &i32| -> Result<bool, StupError> { Ok(true) };
let d = |_: &i32| -> bool { false };
let e = a .and(b.into_failable().map_err(|_| StupError {})) .xor(c) .or(d.into_failable().map_err(|_| StupError {}));
assert!(!e.filter(&1).unwrap());
}
#[test]
fn test_both_filter_types_in_one_scope() {
use filter::Filter;
use failable::filter::FailableFilter;
let failable = |_: &i32| -> Result<bool, StupError> { Ok(true) };
let unfailable = |_: &i32| -> bool { true };
assert!(failable.filter(&1).unwrap());
assert!(unfailable.filter(&1));
}
}