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
57impl_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}