1use crate::{
2 num::Integer,
3 primitive::Primitive,
4 ptr::{Pointer, cast_ptr},
5 tuple::Tuple,
6 util::cast_int,
7};
8
9pub trait FunctionPointer: Primitive + Copy + Sized {
10 type Args: Tuple;
11 type Return;
12
13 fn call(self, args: Self::Args) -> Self::Return;
14
15 fn cast_ptr<T: Sized, P: Pointer<T>>(self) -> P;
16
17 fn cast_int<T: Integer>(self) -> T;
18}
19
20impl<R> Primitive for fn() -> R {}
21impl<R> FunctionPointer for fn() -> R {
22 type Args = ();
23 type Return = R;
24
25 fn call(self, _args: Self::Args) -> Self::Return {
26 self()
27 }
28
29 fn cast_ptr<T: Sized, P: Pointer<T>>(self) -> P {
30 cast_ptr!(T, P, self)
31 }
32
33 fn cast_int<T: Integer>(self) -> T {
34 cast_int!(self => T)
35 }
36}
37
38#[cfg_attr(docsrs, doc(fake_variadic))]
39#[cfg_attr(
40 docsrs,
41 doc = "This trait is implemented for function pointers with up to 12 arguments."
42)]
43impl<A1, R> Primitive for fn(A1) -> R {}
44
45#[cfg_attr(docsrs, doc(fake_variadic))]
46#[cfg_attr(
47 docsrs,
48 doc = "This trait is implemented for function pointers with up to 12 arguments."
49)]
50impl<A1, R> FunctionPointer for fn(A1) -> R {
51 type Args = (A1,);
52 type Return = R;
53
54 fn call(self, args: Self::Args) -> Self::Return {
55 self(args.0)
56 }
57
58 fn cast_ptr<T: Sized, P: Pointer<T>>(self) -> P {
59 cast_ptr!(T, P, self)
60 }
61
62 fn cast_int<T: Integer>(self) -> T {
63 cast_int!(self => T)
64 }
65}
66
67macro_rules! impl_fn {
68 ($($args:tt $n:tt),*) => {
69 #[cfg_attr(docsrs, doc(hidden))]
70 impl<$($args,)* R> Primitive for fn($($args,)*) -> R {}
71 #[cfg_attr(docsrs, doc(hidden))]
72 impl<$($args,)* R> FunctionPointer for fn($($args,)*) -> R {
73 type Args = ($($args,)*);
74 type Return = R;
75
76 fn call(self, args: Self::Args) -> Self::Return {
77 self($(args.$n),*)
78 }
79
80 fn cast_ptr<T: Sized, P: Pointer<T>>(self) -> P {
81 cast_ptr!(T, P, self)
82 }
83
84 fn cast_int<T: Integer>(self) -> T {
85 cast_int!(self => T)
86 }
87 }
88 }
89}
90
91impl_fn!(A1 0, A2 1);
96impl_fn!(A1 0, A2 1, A3 2);
97impl_fn!(A1 0, A2 1, A3 2, A4 3);
98impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4);
99impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5);
100impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6);
101impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7);
102impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7, A9 8);
103impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7, A9 8, A10 9);
104impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7, A9 8, A10 9, A11 10);
105impl_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);
106
107#[cfg(test)]
108mod test {
109 use super::FunctionPointer;
110
111 fn f0() {}
112 fn f1<T>(a: T) -> T {
113 a
114 }
115 fn f2<T1, T2>(a: T1, b: T2) -> (T1, T2) {
116 (a, b)
117 }
118 fn f3<T1, T2, T3>(a: T1, b: T2, c: T3) -> (T1, T2, T3) {
119 (a, b, c)
120 }
121
122 #[test]
123 fn test_call_0_args() {
124 (f0 as fn() -> _).call(());
125 }
126
127 #[test]
128 fn test_call_1_arg() {
129 assert_eq!((f1 as fn(usize) -> _).call((1337,)), (1337usize));
130 }
131
132 #[test]
133 fn test_call_2_args() {
134 assert_eq!(
135 (f2 as fn(char, [u8; 2]) -> _).call(('x', [2, 3])),
136 ('x', [2u8, 3u8])
137 );
138 }
139
140 #[test]
141 fn test_call_3_args() {
142 assert_eq!(
143 (f3 as fn(usize, &'static str, bool) -> _).call((1, "b", false)),
144 (1usize, "b", false)
145 );
146 }
147}