diff --git a/src/func/instances/option.rs b/src/func/instances/option.rs index fc2fc70..642c172 100644 --- a/src/func/instances/option.rs +++ b/src/func/instances/option.rs @@ -12,6 +12,8 @@ //! [`result`]: super::result //! [`solo`]: super::solo +use std::convert::Infallible; + use crate::func::class_prelude::*; #[derive(SharedFunctorAny)] @@ -126,14 +128,18 @@ impl<'a> LocalFunctor<'a> for OptionInstance { } } -impl<'a> Fail<'a, ()> for OptionInstance { - fn fail(_e: ()) -> Self::F { - None +impl<'a> Fail<'a, Option> for OptionInstance { + fn fail(e: Option) -> Self::F { + match e { + Some(some) => match some {}, + None => None, + } } } #[cfg(test)] mod option_tests { + use std::convert::Infallible; use std::sync::Arc; use super::{test_suite, tests, Functor}; @@ -159,6 +165,12 @@ mod option_tests { } } + impl<'a> test_suite::FailTestSuite<'a, Option> for T { + fn sample_fail Option>)>(mut f: F) { + f(Arc::new(|| None)) + } + } + #[test] fn fmap_f_none_is_none() { assert_eq!(T::fmap(None, |_: ()| ()), None); @@ -190,4 +202,9 @@ mod option_tests { fn shared_follows_laws() { test_suite::shared_follows_laws::().unwrap(); } + + #[test] + fn fail_follows_laws() { + test_suite::fail_functor_follows_laws::().unwrap(); + } } diff --git a/src/func/test_suite.rs b/src/func/test_suite.rs index eaf18f1..6b239de 100644 --- a/src/func/test_suite.rs +++ b/src/func/test_suite.rs @@ -1,7 +1,7 @@ use std::sync::Arc; -use shared::SharedFunctor; - +use super::fail::*; +use super::shared::*; use super::tests::*; use super::*; @@ -13,6 +13,10 @@ pub trait FunctorTestSuite<'a>: WeakFunctor<'a> + Eqr<'a> { fn sample>>)>(f: F); } +pub trait FailTestSuite<'a, E: 'a + Send>: FunctorTestSuite<'a> + Fail<'a, E> { + fn sample_fail E>)>(f: F); +} + pub fn functor_follows_laws<'a, T: Functor<'a> + FunctorTestSuite<'a>>() -> R { let mut res = R::default(); T::sample(|pa| { @@ -132,3 +136,11 @@ pub fn shared_follows_laws<'a, T: SharedFunctor<'a> + FunctorTestSuite<'a>>() -> }); res } + +pub fn fail_functor_follows_laws<'a, T: Functor<'a> + FailTestSuite<'a, E>, E: 'a + Send>() -> R { + let mut res = R::default(); + T::sample_fail(|pe| { + res += fmap_keeps_fail::(move || pe(), |x: i32| x + 2); + }); + res +} diff --git a/src/func/tests.rs b/src/func/tests.rs index 9509ce4..1e3bbca 100644 --- a/src/func/tests.rs +++ b/src/func/tests.rs @@ -3,10 +3,10 @@ use std::{ ops::{Add, AddAssign}, }; -use applicative_select::Selected; -use controlflow::IterativeWrapped; -use shared::SharedFunctor; - +use super::applicative_select::*; +use super::controlflow::*; +use super::fail::*; +use super::shared::*; use super::*; pub struct TestResults { @@ -478,3 +478,16 @@ pub fn shared_is_same_after_clone< T::unshare(sa), ) } + +pub fn fmap_keeps_fail< + 'a, + T: Functor<'a> + Fail<'a, E> + Eqr<'a>, + A: 'a + Send, + B: 'a + Send + Debug + PartialEq, + E: 'a + Send, +>( + e0: impl 'a + Send + Fn() -> E, + f: impl 'a + Send + Fn(A) -> B, +) -> R { + T::eqr("fmap fail", T::fmap(T::fail(e0()), f), T::fail(e0())) +}