1#![no_std]
2
3pub trait TypeFn {
5 type Ret;
6}
7
8#[macro_export]
10macro_rules! call {
11 ($($fn:tt)+) => {
12 <$($fn)+ as TypeFn>::Ret
13 };
14}
15
16#[macro_export]
17macro_rules! call_as {
18 ($fty:ty => $($fn:tt)+) => {
19 <$($fn)+ as $fty>::Ret
20 };
21}
22
23#[macro_export]
25macro_rules! assert_types_eq {
26 ($a:ty, $b:ty) => {{
27 let _: ::core::marker::PhantomData<$a> = ::core::marker::PhantomData::<$b>;
28 }};
29}
30
31#[macro_export]
52macro_rules! type_fn_impl {
53 {@a_or_else_b => } => {compiler_error!()};
54 {@a_or_else_b => $($b:ident)+} => {$($b)*};
55 {@a_or_else_b $($a:ty)+ => $($b:ident)*} => { $($a)+ };
56 {$(fn $name:ident <$($($arg:ident)? $(=> $($argv:ty)+)?),* $(| $($targ:ident),+)?>
57 $(where $($tv:ty : $( + $( ?$tcqm:ident )? $( $tc:ident )? )+ ,)+)? => $ret:ty;)+}
58 => {
59 $(
60 impl<$($($arg, )?)* $($($targ, )*)?>
61 TypeFn for $name <$($crate::type_fn_impl!(@a_or_else_b $($($argv)*)? => $($arg)?)),*>
62 $(where $($tv : $($(?$tcqm)? $($tc)? + )+ ),+)?
63 {
64 type Ret = $ret;
65 }
66 )+
67 };
68}
69
70#[macro_export]
79macro_rules! type_fn {
80 ($($vis:vis fn $name:ident <$($arg:ident),*>;)*) => {
81 $(
82 #[derive(Default, Debug)]
83 $vis struct $name <$($arg),*> ($(::core::marker::PhantomData<$arg>, )*);
84 )*
85 };
86}
87
88#[cfg(test)]
89mod tests {
90 extern crate std;
91 use core::marker::PhantomData;
92
93 use crate::TypeFn;
94
95 #[test]
96 fn test_compile() {
97 #[derive(Default, Debug)]
98 struct Zero;
99 #[derive(Default, Debug)]
100 struct Succ<T>(PhantomData<T>);
101 type_fn! {
102 fn Add<Lhs, Rhs>;
103 fn Sub<Lhs, Rhs>;
104 fn Mul<Lhs, Rhs>;
105 }
106 type_fn_impl! {
107 fn Add< => Zero, Rhs> => Rhs;
108 fn Add<N => Succ<N>, Rhs>
109 where
110 Add<N, Rhs>: + TypeFn,
111 => Succ<<Add<N, Rhs> as TypeFn>::Ret>;
112
113 fn Sub<Lhs, => Zero> => Lhs;
114 fn Sub<Lhs => Succ<Lhs>, Rhs => Succ<Rhs>>
115 where
116 Sub<Lhs, Rhs> : + TypeFn,
117 => <Sub<Lhs, Rhs> as TypeFn>::Ret;
118
119 fn Mul< => Zero, Rhs> => Zero;
120 fn Mul<Lhs => Succ<Lhs>, Rhs>
121 where
122 Mul<Lhs, Rhs>: + TypeFn,
123 Add<Rhs, <Mul<Lhs, Rhs> as TypeFn>::Ret>: + TypeFn,
124 => <Add<Rhs, <Mul<Lhs, Rhs> as TypeFn>::Ret> as TypeFn>::Ret;
125 }
126
127 type TwoMinusOne = <Sub<Succ<Succ<Zero>>, Succ<Zero>> as TypeFn>::Ret;
128 std::println!("{:?}", <Sub<Succ<Succ<Zero>>, Succ<Zero>>>::default());
129 assert_types_eq!(TwoMinusOne, Succ<Zero>);
130 assert_types_eq!(call!(Sub<TwoMinusOne, Succ<Zero>>), Zero);
131 assert_types_eq!(
132 Succ<Succ<Succ<Succ<Zero>>>>,
133 <Mul<Succ<Succ<Zero>>, Succ<Succ<Zero>>> as TypeFn>::Ret
134 );
135 assert_types_eq!(Zero, <Mul<Succ<Succ<Zero>>, Zero> as TypeFn>::Ret);
136 }
137}