aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs46
-rw-r--r--tests/multiple_generics.rs21
-rw-r--r--tests/multiple_generics_lifetime.rs81
3 files changed, 125 insertions, 23 deletions
diff --git a/src/lib.rs b/src/lib.rs
index f12fe95..e529f5b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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