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