aboutsummaryrefslogtreecommitdiff
path: root/tests/multiple_generics_lifetime.rs
blob: ddc0628caf7db66bb4c0dc50444e9c9c80178edd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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!()
    }
}