std_traits/
fun.rs

1use crate::{primitive::Primitive, tuple::Tuple};
2
3pub trait FunctionPointer: Primitive + Copy + Sized {
4    type Args: Tuple;
5    type Return;
6
7    fn call(self, args: Self::Args) -> Self::Return;
8}
9
10impl<R> Primitive for fn() -> R {}
11impl<R> FunctionPointer for fn() -> R {
12    type Args = ();
13    type Return = R;
14
15    fn call(self, _args: Self::Args) -> Self::Return {
16        self()
17    }
18}
19
20#[cfg_attr(docsrs, doc(fake_variadic))]
21#[cfg_attr(
22    docsrs,
23    doc = "This trait is implemented for function pointers with up to 12 arguments."
24)]
25impl<A1, R> Primitive for fn(A1) -> R {}
26
27#[cfg_attr(docsrs, doc(fake_variadic))]
28#[cfg_attr(
29    docsrs,
30    doc = "This trait is implemented for function pointers with up to 12 arguments."
31)]
32impl<A1, R> FunctionPointer for fn(A1) -> R {
33    type Args = (A1,);
34    type Return = R;
35
36    fn call(self, args: Self::Args) -> Self::Return {
37        self(args.0)
38    }
39}
40
41macro_rules! impl_fn {
42    ($($args:tt $n:tt),*) => {
43        #[cfg_attr(docsrs, doc(hidden))]
44        impl<$($args,)* R> Primitive for fn($($args,)*) -> R {}
45        #[cfg_attr(docsrs, doc(hidden))]
46        impl<$($args,)* R> FunctionPointer for fn($($args,)*) -> R {
47            type Args = ($($args,)*);
48            type Return = R;
49
50            fn call(self, args: Self::Args) -> Self::Return {
51                self($(args.$n),*)
52            }
53        }
54    }
55}
56
57/*
58for n in range(2, 13):
59    print(f"impl_fn!({', '.join(f'A{i + 1} {i}' for i in range(n))});")
60*/
61impl_fn!(A1 0, A2 1);
62impl_fn!(A1 0, A2 1, A3 2);
63impl_fn!(A1 0, A2 1, A3 2, A4 3);
64impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4);
65impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5);
66impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6);
67impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7);
68impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7, A9 8);
69impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7, A9 8, A10 9);
70impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7, A9 8, A10 9, A11 10);
71impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7, A9 8, A10 9, A11 10, A12 11);
72
73#[cfg(test)]
74mod test {
75    use super::FunctionPointer;
76
77    fn f0() {}
78    fn f1<T>(a: T) -> T {
79        a
80    }
81    fn f2<T1, T2>(a: T1, b: T2) -> (T1, T2) {
82        (a, b)
83    }
84    fn f3<T1, T2, T3>(a: T1, b: T2, c: T3) -> (T1, T2, T3) {
85        (a, b, c)
86    }
87
88    #[test]
89    fn test_call_0_args() {
90        (f0 as fn() -> _).call(());
91    }
92
93    #[test]
94    fn test_call_1_arg() {
95        assert_eq!((f1 as fn(usize) -> _).call((1337,)), (1337usize));
96    }
97
98    #[test]
99    fn test_call_2_args() {
100        assert_eq!(
101            (f2 as fn(char, [u8; 2]) -> _).call(('x', [2, 3])),
102            ('x', [2u8, 3u8])
103        );
104    }
105
106    #[test]
107    fn test_call_3_args() {
108        assert_eq!(
109            (f3 as fn(usize, &'static str, bool) -> _).call((1, "b", false)),
110            (1usize, "b", false)
111        );
112    }
113}