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
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
use *;

pub trait Path<T> {
    type Lift;

    fn path_force(&self, arg: T) -> <Self as Path<T>>::Lift;

    /// Can call method if the existential paths of constrained input matches.
    fn path(&self, arg: T) -> <Self as Path<T>>::Lift
        where <Self as Path<T>>::Lift: ExPath<
                    Lift = <<T as Constrain<<Self as ExPath>::Lift>>::Lift as ExPath>::Lift>,
              T: Constrain<<Self as ExPath>::Lift>,
              <T as Constrain<<Self as ExPath>::Lift>>::Lift: ExPath,
              Self: ExPath
    {
        self.path_force(arg)
    }
}

macro_rules! path_impl {
    (sym $a:ident , $b:ident , $c:ident) => {
        impl<T: Clone> Path<$b> for $a<T>
            where $b<T>: ExPath
        {
            type Lift = $c<<<$b as Constrain<T>>::Lift as ExPath>::Lift>;

            fn path_force(&self, arg: $b) -> Self::Lift {
                $c {i: arg.i_force(self.i.clone()).ex_path()}
            }
        }
    };
    (sym $a:ident , $b:ident , $c:ident < $t:ident >) => {
        impl<T: Clone> Path<$b> for $a<T>
            where $b<T>: ExPath
        {
            type Lift = $c<$t, <<$b as Constrain<T>>::Lift as ExPath>::Lift>;

            fn path_force(&self, arg: $b) -> Self::Lift {
                $c {t: PhantomData, i: arg.i_force(self.i.clone()).ex_path()}
            }
        }
    };
    (sym $a:ident < $t:ident >, $b:ident , $c:ident) => {
        impl<T: Clone> Path<$b> for $a<$t, T>
            where $b<T>: ExPath
        {
            type Lift = $c<<<$b as Constrain<T>>::Lift as ExPath>::Lift>;

            fn path_force(&self, arg: $b) -> Self::Lift {
                $c {i: arg.i_force(self.i.clone()).ex_path()}
            }
        }
    };
    (sym $a:ident < $t:ident >, $b:ident < $bt:ident >, $c:ident) => {
        impl<T: Clone> Path<$b<$bt>> for $a<$t, T>
            where $b<$bt, T>: ExPath
        {
            type Lift = $c<<<$b<$bt> as Constrain<T>>::Lift as ExPath>::Lift>;

            fn path_force(&self, arg: $b<$bt>) -> Self::Lift {
                $c {i: arg.i_force(self.i.clone()).ex_path()}
            }
        }
    };
    (sym $a:ident < $t:ident >, $b:ident < $bt:ident >, $c:ident < $t2:ident >) => {
        impl<T: Clone> Path<$b<$bt>> for $a<$t, T>
            where $b<$bt, T>: ExPath
        {
            type Lift = $c<$t2, <<$b<$bt> as Constrain<T>>::Lift as ExPath>::Lift>;

            fn path_force(&self, arg: $b<$bt>) -> Self::Lift {
                $c {t: PhantomData, i: arg.i_force(self.i.clone()).ex_path()}
            }
        }
    };
    ($a:ident , $b:ident , $c:ident) => {
        impl Path<$b> for $a {
            type Lift = $c;

            fn path_force(&self, _: $b) -> Self::Lift {
                $c::default()
            }
        }
    }
}

path_impl!{sym Or, Not, And}
path_impl!{sym And, Not, Or}
path_impl!{sym Eq<bool>, Not, Xor}
path_impl!{sym Xor, Not, Eq<bool>}
path_impl!{sym Nor, Not, Nand}
path_impl!{sym Nand, Not, Nor}
path_impl!{sym Exc, Not, Nrexc}
path_impl!{sym Nrexc, Not, Exc}
path_impl!{sym Rexc, Not, Nexc}
path_impl!{sym Nexc, Not, Rexc}

macro_rules! nat_impl {
    ($t:ident) => {
        path_impl!{sym Add<$t>, Even<$t>, Eq<bool>}
        path_impl!{sym Add<$t>, Odd<$t>, Xor}
    };
}

nat_impl!{u8}
nat_impl!{u16}
nat_impl!{u32}
nat_impl!{u64}