diff options
| -rw-r--r-- | src/lib.rs | 46 | ||||
| -rw-r--r-- | tests/multiple_generics.rs | 21 | ||||
| -rw-r--r-- | tests/multiple_generics_lifetime.rs | 81 |
3 files changed, 125 insertions, 23 deletions
@@ -90,13 +90,13 @@ macro_rules! free { } } }; - (<$a:lifetime>, $v:vis $name:ident<$($other_lifetimes:lifetime,)+ $generic:ident>, $f:ty) =>{ + (<$a:lifetime>, $v:vis $name:ident<$($other_lifetimes:lifetime,)+ $generic:ident $(,$other_generics:ident)*>, $f:ty) =>{ #[derive(Clone)] - $v enum $name<$($other_lifetimes,)* $generic> { + $v enum $name<$($other_lifetimes,)* $generic $(,$other_generics)*> { Pure($generic), Free(Box<$f>) } - impl<$($other_lifetimes : $a,)* $generic> $name<$($other_lifetimes,)* $generic> where $generic : $a { + impl<$($other_lifetimes : $a,)* $generic $(,$other_generics)*> $name<$($other_lifetimes,)* $generic $(,$other_generics)*> where $generic : $a { $v fn lift_f(functor : <$f as $crate::higher::Functor<$a, Self>>::Target<$generic>) -> Self{ use $crate::higher::Functor; Self::Free(Box::new(functor.fmap(|a| Self::Pure(a)))) @@ -111,16 +111,16 @@ macro_rules! free { } } - impl<$($other_lifetimes : $a,)* A> $crate::higher::Functor<$a,A> for $name<$($other_lifetimes,)*A> where A : $a { - type Target<T> = $name<$($other_lifetimes,)* T>; - fn fmap<B,F>(self, f: F) -> Self::Target<B> - where F: Fn(A) -> B + $a + impl<$($other_lifetimes : $a,)* $generic $(,$other_generics)*> $crate::higher::Functor<$a,$generic> for $name<$($other_lifetimes,)* $generic $(,$other_generics)*> where $generic : $a { + type Target<FreeMacroReservedType> = $name<$($other_lifetimes,)* FreeMacroReservedType $(,$other_generics)*>; + fn fmap<FreeMacroReservedType,F>(self, f: F) -> Self::Target<FreeMacroReservedType> + where F: Fn($generic) -> FreeMacroReservedType + $a { - fn __fmap_impl<$($other_lifetimes : $a,)* A, B, F>(s : $name<$($other_lifetimes,)* A>, f : std::rc::Rc<F>) -> $name<$($other_lifetimes,)* B> where A : $a, F: Fn(A) -> B + $a{ + fn __fmap_impl<$($other_lifetimes : $a,)* $generic $(,$other_generics)*, FreeMacroReservedType, F>(s : $name<$($other_lifetimes,)* $generic $(,$other_generics)*>, f : std::rc::Rc<F>) -> $name<$($other_lifetimes,)* FreeMacroReservedType $(,$other_generics)*> where $generic : $a, F: Fn($generic) -> FreeMacroReservedType + $a{ use $crate::higher::Functor; match s { $name::Pure(a) => {$name::Pure(f(a))}, - $name::Free(fa) => {$name::Free(Box::new(fa.fmap(move |x : $name<$($other_lifetimes,)*A>| __fmap_impl(x, f.clone()))))}, + $name::Free(fa) => {$name::Free(Box::new(fa.fmap(move |x : $name<$($other_lifetimes,)* $generic $(,$other_generics)*>| __fmap_impl(x, f.clone()))))}, } } @@ -129,36 +129,36 @@ macro_rules! free { } } - impl<$($other_lifetimes,)* A> $crate::higher::Pure<A> for $name<$($other_lifetimes,)* A> { - fn pure(value : A) -> Self { + impl<$($other_lifetimes,)* $generic $(,$other_generics)*> $crate::higher::Pure<$generic> for $name<$($other_lifetimes,)* $generic $(,$other_generics)*> { + fn pure(value : $generic) -> Self { Self::Pure(value) } } - impl<$($other_lifetimes : $a,)* A> $crate::higher::Apply<$a, A> for $name<$($other_lifetimes,)* A> where A: $a + Clone, Self : Clone{ - type Target<T> = $name<$($other_lifetimes,)* T> where T:$a; - fn apply<B>( + impl<$($other_lifetimes : $a,)* $generic $(,$other_generics)*> $crate::higher::Apply<$a, $generic> for $name<$($other_lifetimes,)* $generic $(,$other_generics)*> where $generic: $a + Clone, Self : Clone{ + type Target<FreeMacroReservedType> = $name<$($other_lifetimes,)* FreeMacroReservedType $(,$other_generics)*> where FreeMacroReservedType:$a; + fn apply<FreeMacroReservedType>( self, - f: <Self as $crate::higher::Apply<$a, A>>::Target<$crate::higher::apply::ApplyFn<$a, A, B>>, - ) -> <Self as $crate::higher::Apply<$a, A>>::Target<B> + f: <Self as $crate::higher::Apply<$a, $generic>>::Target<$crate::higher::apply::ApplyFn<$a, $generic, FreeMacroReservedType>>, + ) -> <Self as $crate::higher::Apply<$a, $generic>>::Target<FreeMacroReservedType> where - B: $a, + FreeMacroReservedType: $a, { $crate::higher::apply::ap(f,self) } } - impl<$($other_lifetimes : $a,)* A> $crate::higher::Bind<$a,A> for $name<$($other_lifetimes,)*A> where A : $a{ - type Target<T> = $name<$($other_lifetimes,)* T>; - fn bind<B, F>(self, f: F) -> Self::Target<B> + impl<$($other_lifetimes : $a,)* $generic $(,$other_generics)*> $crate::higher::Bind<$a,$generic> for $name<$($other_lifetimes,)* $generic $(,$other_generics)*> where $generic : $a{ + type Target<FreeMacroReservedType> = $name<$($other_lifetimes,)* FreeMacroReservedType $(,$other_generics)*>; + fn bind<FreeMacroReservedType, F>(self, f: F) -> Self::Target<FreeMacroReservedType> where - F: Fn(A) -> Self::Target<B> + $a, + F: Fn($generic) -> Self::Target<FreeMacroReservedType> + $a, { - fn __bind_impl<$($other_lifetimes : $a,)* A, B, F>(s : $name<$($other_lifetimes,)*A>, f : std::rc::Rc<F>) -> $name<$($other_lifetimes,)* B> where A : $a, F: Fn(A) -> $name<$($other_lifetimes,)* B> + $a{ + fn __bind_impl<$($other_lifetimes : $a,)* $generic $(,$other_generics)*, FreeMacroReservedType, F>(s : $name<$($other_lifetimes,)* $generic $(,$other_generics)*>, f : std::rc::Rc<F>) -> $name<$($other_lifetimes,)* FreeMacroReservedType $(,$other_generics)*> where $generic : $a, F: Fn($generic) -> $name<$($other_lifetimes,)* FreeMacroReservedType $(,$other_generics)*> + $a{ use $crate::higher::Functor; match s { $name::Pure(a) => {f(a)}, - $name::Free(fa) => {$name::Free(Box::new(fa.fmap(move |x : $name<$($other_lifetimes,)*A>| __bind_impl(x, f.clone()))))}, + $name::Free(fa) => {$name::Free(Box::new(fa.fmap(move |x : $name<$($other_lifetimes,)* $generic $(,$other_generics)*>| __bind_impl(x, f.clone()))))}, } } let r = std::rc::Rc::new(f); diff --git a/tests/multiple_generics.rs b/tests/multiple_generics.rs index ce13414..2f560dd 100644 --- a/tests/multiple_generics.rs +++ b/tests/multiple_generics.rs @@ -62,4 +62,25 @@ fn test_multiple_generics2(){ }, _ => unreachable!() } +} + +#[test] +fn test_multiple_generics3(){ + let m : FreeResult<_, String> = FreeResult::lift_f(Ok(37u32)); + let f : FreeResult<_, String> = FreeResult::Pure(|x : u32| -> f32 {(x as f32)*0.5f32}).fmap(Into::into); + let m = m.apply(f); + match m{ + FreeResult::Free(m) => { + match &*m{ + Ok(k) => { + match k { + FreeResult::Pure(k) => assert_eq!(18.5f32, *k), + FreeResult::Free(_) => unreachable!(), + } + } + Err(_) => unreachable!(), + } + }, + _ => unreachable!() + } }
\ No newline at end of file diff --git a/tests/multiple_generics_lifetime.rs b/tests/multiple_generics_lifetime.rs new file mode 100644 index 0000000..ddc0628 --- /dev/null +++ b/tests/multiple_generics_lifetime.rs @@ -0,0 +1,81 @@ +//! Tests if multiple generic parameters work, if the return value's lifetime depends on the mapping function lifetime. + +use std::rc::Rc; +use higher_free_macro::free; +use higher::{Functor, Bind, Apply}; + +#[derive(Clone)] +struct TestFunctor<'a, 'b, A, B>{ + data : &'b B, + next : Rc<dyn Fn(i32)->A + 'a>, +} + +impl<'a,'b,A : 'a,B> Functor<'a,A> for TestFunctor<'a, 'b, A, B>{ + type Target<T> = TestFunctor<'a, 'b, T, B>; + + fn fmap<C, F>(self, f: F) -> Self::Target<C> + where + F: Fn(A) -> C + 'a { + TestFunctor{ data : self.data, next : Rc::new(move |x| f((self.next)(x)))} + } +} + +free!(<'xx>, FreeTest<'xx,'yy,AA,BB>, TestFunctor<'xx, 'yy, FreeTest<'xx, 'yy, AA, BB>, BB>); + +#[test] +fn test_lifetime_multiple_generics(){ + let m = FreeTest::lift_f(TestFunctor{ data : &"Listening to NSP while writing this.", next : Rc::new(|x| (x as f32)*0.5f32)}); + let f = FreeTest::Pure(|x : f32| -> bool {x > 0.7f32} ).fmap(Into::into); + let m = m.apply(f); + match m { + FreeTest::Free(m) => { + assert_eq!(m.data, &"Listening to NSP while writing this."); + let x = m.next.clone(); + let y = m.next.clone(); + let m1 = x(1); + match m1{ + FreeTest::Pure(v) => assert!(!v), + FreeTest::Free(_) => unreachable!(), + } + let m2 = y(3); + match m2{ + FreeTest::Pure(v) => assert!(v), + FreeTest::Free(_) => unreachable!(), + } + }, + _ => unreachable!() + } +} + +#[test] +fn test_lifetime_multiple_generics_bind(){ + let m = FreeTest::lift_f(TestFunctor{ data : &"Listening to Soilwork while writing this.", next : Rc::new(|x| (x as f32)*0.5f32)}); + let m = m.bind(|x : f32| -> FreeTest<_,_> { + if x < 0.0 { + FreeTest::Pure(x.abs().floor() as u32) + } else { + FreeTest::lift_f(TestFunctor{data : &"Now it's Little Big.", next : Rc::new(move |y| (y as u32) + (x.ceil() as u32))}) + }}); + match m{ + FreeTest::Free(m) => { + assert_eq!(m.data, &"Listening to Soilwork while writing this."); + match (m.next)(-3){ + FreeTest::Pure(v) => assert_eq!(v, 1), + FreeTest::Free(_) => unreachable!(), + } + match (m.next)(3){ + FreeTest::Pure(_) => unreachable!(), + FreeTest::Free(v) => { + assert_eq!(v.data, &"Now it's Little Big."); + match (v.next)(5) { + FreeTest::Pure(v) => { + assert_eq!(v, 7) + }, + FreeTest::Free(_) => unreachable!(), + } + }, + } + }, + _ => unreachable!() + } +}
\ No newline at end of file |
