any_fn/
into_any_fn.rs

1use crate::{AnyFn, Ref, RefMut, Value};
2use alloc::{boxed::Box, vec};
3use core::any::{Any, TypeId};
4
5/// A trait to convert a statically-typed function into a dynamically-typed
6/// function.
7pub trait IntoAnyFn<'a, T, S> {
8    /// Converts itself into a dynamically-typed function.
9    fn into_any_fn(self) -> AnyFn<'a>;
10}
11
12macro_rules! impl_function {
13    ([$($name:ident),*], [$([$($trait:tt),*]),*], [$($parameter:ty),*], [$($argument:item),*], [$($type:ty),*]) => {
14        #[allow(unused_parens)]
15        impl<'a, T1: FnMut($($parameter),*) -> T2 + 'a, T2: Any, $($name: Any $(+$trait)*),*> IntoAnyFn<'a, ($($type,)*), T2> for T1 {
16            #[allow(non_snake_case)]
17            fn into_any_fn(mut self) -> AnyFn<'a> {
18                #[allow(unused, unused_mut)]
19                AnyFn::new(
20                    vec![$(TypeId::of::<$name>()),*],
21                    TypeId::of::<T2>(),
22                    Box::new(move |arguments: &[&Value]| {
23                        let mut iter = 0..;
24                        $($argument);*
25                        Ok(Value::new(self($($name!(arguments, iter)),*)))
26                    }),
27                )
28            }
29        }
30    };
31}
32
33macro_rules! impl_function_combination {
34    ([$($x:ident),*]) => {
35        impl_function_combination!([$($x),*], [], [], [], [], []);
36    };
37    (
38        [$x:ident$(,)? $($y:ident),*],
39        [$($name:ident),* $(,)?],
40        [$([$($trait:tt),* $(,)?]),* $(,)?],
41        [$($parameter:ty),* $(,)?],
42        [$($argument:item),* $(,)?],
43        [$($type:ty),* $(,)?]
44    ) => {
45        impl_function_combination!(
46            [$($y),*],
47            [$x, $($name),*],
48            [[Clone], $([$($trait),*]),*],
49            [$x, $($parameter),*],
50            [
51                macro_rules! $x {
52                    ($arguments:ident, $iter:ident) => {
53                        $arguments[$iter.next().unwrap_or_default()]
54                            .downcast_ref::<$x>()?
55                            .clone()
56                    };
57                },
58                $($argument),*
59            ],
60            [$x, $($type),*]
61        );
62        impl_function_combination!(
63            [$($y),*],
64            [$x, $($name),*],
65            [[], $([$($trait),*]),*],
66            [&$x, $($parameter),*],
67            [
68                macro_rules! $x {
69                    ($arguments:ident, $iter:ident) => {
70                        &*($arguments[$iter.next().unwrap_or_default()]
71                            .downcast_ref::<$x>()?)
72                    };
73                },
74                $($argument),*
75            ],
76            [Ref<$x>, $($type),*]
77        );
78        impl_function_combination!(
79            [$($y),*],
80            [$x, $($name),*],
81            [[], $([$($trait),*]),*],
82            [&mut $x, $($parameter),*],
83            [
84                macro_rules! $x {
85                    ($arguments:ident, $iter:ident) => {
86                        &mut *($arguments[$iter.next().unwrap_or_default()]
87                            .downcast_mut::<$x>()?)
88                    };
89                },
90                $($argument),*
91            ],
92            [RefMut<$x>, $($type),*]
93        );
94    };
95    (
96        [],
97        [$($name:ident),* $(,)?],
98        [$([$($trait:tt),* $(,)?]),* $(,)?],
99        [$($parameter:ty),* $(,)?],
100        [$($argument:item),* $(,)?],
101        [$($type:ty),* $(,)?]
102    ) => {
103        impl_function!(
104            [$($name),*],
105            [$([$($trait),*]),*],
106            [$($parameter),*],
107            [$($argument),*],
108            [$($type),*]
109        );
110    }
111}
112
113macro_rules! impl_functions {
114    ($first_type:ident, $($type:ident),*) => {
115        impl_function_combination!([$first_type, $($type),*]);
116        impl_functions!($($type),*);
117    };
118    ($type:ident) => {
119        impl_function_combination!([$type]);
120        impl_function_combination!([]);
121    }
122}
123
124impl_functions!(A, B, C, D, E, F);