callable/
lib.rs

1#![no_std]
2
3//!
4//! ```
5//! # use callable::prelude::*;
6//! let callable = callable![fn(&_) -> _](u8::clone);
7//! assert_eq!(callable.call_fn((&1,)), 1);
8//! assert_eq!(callable.emit(&2), 2);
9//!
10//! let callable = callable.provide_first_argument_refed(3);
11//! assert_eq!(callable.call_fn(()), 3);
12//! ```
13
14mod traits;
15pub use traits::*;
16
17pub mod accept_anything;
18pub mod chain;
19
20pub mod argument;
21pub use argument::{ArgumentOfType, ArgumentType, ArgumentTypes, ArgumentsOfTypes};
22
23mod maybe_handle_event;
24pub use maybe_handle_event::*;
25
26#[cfg(feature = "gat")]
27pub mod gat;
28
29mod sealed {
30    pub trait Sealed {}
31}
32
33mod private {
34    #[derive(Debug, Clone, Copy)]
35    pub struct HkFn<F>(pub(crate) F);
36}
37
38#[cfg(feature = "impl_with_macro_rules")]
39mod imp {
40    mod macros;
41    macros::impl_with_macro_rules!(a1: A1, a2: A2, a3: A3, a4: A4);
42}
43
44#[cfg(not(feature = "impl_with_macro_rules"))]
45mod imp;
46
47pub use imp::*;
48
49/// ```
50/// # use callable::{ArgumentType, ArgumentTypes};
51/// # fn __(v:
52/// (ArgumentType![u8], ArgumentType![&str], ArgumentType![&mut Vec<u8>])
53/// # ) ->
54/// // is exactly the same as
55/// ArgumentTypes!(u8, &str, &mut Vec<u8>)
56/// # { v }
57/// ```
58#[macro_export]
59macro_rules! ArgumentType {
60    (&mut $t:ty) => { $crate::argument::ByMut<$t> };
61    (&    $t:ty) => { $crate::argument::ByRef<$t> };
62    (     $t:ty) => { $crate::argument::Value<$t> };
63}
64
65#[macro_export]
66macro_rules! ArgumentTypes {
67    () => {
68        ()
69    };
70    (@$resolved:tt) => {
71        $resolved
72    };
73    ($(@($($resolved:tt)*))? &mut $t:ty $(, $($rest:tt)*)? ) => {
74        $crate::ArgumentTypes! { @($($($resolved)*)? $crate::argument::ByMut<$t>,) $($($rest)*)? }
75    };
76    ($(@($($resolved:tt)*))? &    $t:ty $(, $($rest:tt)*)? ) => {
77        $crate::ArgumentTypes! { @($($($resolved)*)? $crate::argument::ByRef<$t>,) $($($rest)*)? }
78    };
79    ($(@($($resolved:tt)*))?      $t:ty $(, $($rest:tt)*)? ) => {
80        $crate::ArgumentTypes! { @($($($resolved)*)? $crate::argument::Value<$t>,) $($($rest)*)? }
81    };
82}
83
84#[cfg(test)]
85mod tests {
86    use crate::prelude::*;
87
88    #[test]
89    fn test_callable_ref() {
90        fn asserts<T>(t: T) -> T
91        where
92            T: for<'i> CallableOne<&'i usize, Output = usize>,
93        {
94            t
95        }
96
97        let cbk = asserts(crate::r#ref(Clone::clone));
98        assert_eq!(cbk.emit(&0), 0);
99        assert_eq!(cbk.provide_last_argument_refed(8).call_fn(()), 8);
100    }
101
102    #[test]
103    fn mods() {
104        let _: fn() = callable(|| {});
105
106        let _: fn(()) = crate::value(|()| {});
107        let _: callable![fn(&())] = crate::r#ref(|&()| {});
108        let _: callable![fn(&mut ())] = crate::r#mut(|&mut ()| {});
109
110        let _: fn((), ()) = crate::value::value(|(), ()| {});
111        let _: crate::value::HkFn<fn((), &())> = crate::value::r#ref(|(), &()| {});
112    }
113}
114
115mod fn_pointer_fn {
116    #[allow(non_snake_case)]
117    pub fn FnPointer<Out>(f: fn() -> Out) -> fn() -> Out {
118        f
119    }
120}
121pub use fn_pointer_fn::FnPointer;
122pub type FnPointer<Out> = fn() -> Out;
123
124pub use fn_pointer_fn::FnPointer as callable;
125
126pub mod prelude {
127    pub use crate::{ArgumentTypes, Callable, CallableOne, CallableWithFixedArguments, IsCallable};
128
129    pub use crate as callable;
130    pub use crate::callable;
131}
132
133#[doc(hidden)]
134#[macro_export]
135macro_rules! __expand_or {
136    ([         ] $($b:tt)*) => { $($b)* };
137    ([$($a:tt)+] $($b:tt)*) => { $($a)+ };
138}
139
140macro_rules! impl_callable_parse_input {
141    ($dollar:tt $([$($match:tt)*][$($clone:tt)*] => $output_path:ident $output_input:tt )*) => {
142        #[macro_export]
143        macro_rules! __callable_parse_input {
144            // end input
145            ([| $dollar($other:tt)*] $_clone:tt $path:tt $input:tt ) => {
146                $crate::__callable_input_resolved! { [$path $input] $dollar($other)*  }
147            };
148            $(
149                (   [$($match)* , $dollar($_rest:tt)*]
150                    [$($clone)* , $dollar($ rest:tt)*]
151                    {$dollar($paths:ident)*}
152                    {$dollar($inputs:tt  )*}
153                ) => {
154                    $crate::__callable_parse_input! {
155                        [$dollar($_rest)*]
156                        [$dollar($ rest)*]
157                        {$dollar($paths )* $output_path }
158                        {$dollar($inputs)* $output_input}
159                    }
160                };
161                (   [$($match)* | $dollar($_rest:tt)*]
162                    [$($clone)* | $dollar($ rest:tt)*]
163                    {$dollar($paths:ident)*}
164                    {$dollar($inputs:tt  )*}
165                ) => {
166                    $crate::__callable_input_resolved! { [
167                        {$dollar($paths )* $output_path }
168                        {$dollar($inputs)* $output_input}
169                    ] $dollar($rest)* }
170                };
171            )*
172        }
173    };
174}
175
176impl_callable_parse_input! { $
177    // &mut _
178    [&     mut   $_input:pat_param][$r:tt $m:tt $ input:pat_param] => r#mut[$r $m $input]
179    // &mut v: _
180    [&       mut     $($_input:ident)+ :                $_input_ty:ty][$r:tt $m:tt $($ input:ident)+ :                $ input_ty:ty] => r#mut[$r $m $($input)+ : $input_ty]
181    // &mut _: _
182    [&       mut       $_input:tt      :      $_input_ty:ty][$r:tt $m:tt   $ input:tt      :      $ input_ty:ty]=> r#mut [$r $m   $input   : $input_ty]
183    // v: &mut _
184    [                $($_input:ident)+ : &mut $_input_ty:ty][                $($ input:ident)+ : $r:tt $m:tt $ input_ty:ty]=> r#mut [$($input)+   : $r $m $input_ty]
185    // _: &mut _
186    [                  $_input:tt      : &mut $_input_ty:ty , $($_rest:tt)*][                  $ input:tt      : &mut $ input_ty:ty , $($ rest:tt)*]=> r#mut[$input : &mut $input_ty]
187
188    // &_
189    [&    $_input:pat_param][$r:tt $input:pat_param] => r#ref[$r $input]
190    // &v: _
191    [&    $($_input:ident)+ : $_input_ty:ty][$r:tt    $($input:ident)+ : $input_ty:ty] => r#ref[$r $($input)+ : $input_ty]
192    // &_: _
193    [&    $_input:tt : $_input_ty:ty][$r:tt    $input:tt : $input_ty:ty] => r#ref[$r $input : $input_ty]
194    // v: &_
195    [$($_input:ident)+ : & $_input_ty:ty ][$($input:ident)+ : $r:tt $input_ty:ty ] => r#ref[$($input)+ : $r $input_ty]
196    // _: &_
197    [$_input:tt : & $_input_ty:ty ][$input:tt : $r:tt $input_ty:ty ] => r#ref[$input : $r $input_ty]
198
199    // |_| {}
200    [$_input:pat_param][$input:pat_param] => value[$input]
201    // |v: _| {}
202    [$($_input:ident)+ :   $_input_ty:ty][$($input:ident)+ :   $input_ty:ty] => value[$($input)+ : $input_ty]
203    // |_: _| {}
204    [$_input:tt :   $_input_ty:ty][$input:tt :   $input_ty:ty] => value[$input : $input_ty]
205}
206
207/// ```
208/// use callable::callable;
209/// let _: callable![fn() -> u8] = || 1;
210/// let _: callable![fn(&mut _)] = callable![fn(&mut _)](|_: &mut u8| {});
211/// ```
212#[macro_export]
213macro_rules! callable {
214    (|| $($rest:tt)*) => {
215        $crate::__callable_input_resolved! { [{} {}] $($rest)*  }
216    };
217    (|  $($rest:tt)* ) => {
218        $crate::__callable_parse_input! { [$($rest)*][$($rest)*]{}{} }
219    };
220    (fn($($args:tt)*) $(-> $output:ty)?) => {
221        $crate::__fn_pointer! { [$($args)*]{}{}{$($output)?} }
222    };
223}
224
225#[doc(hidden)]
226#[macro_export]
227macro_rules! __fn_pointer {
228    ([                             ]{$($path:ident)*}{$($generics:tt)*}{$output_ty:ty} ) => {
229        $crate $(:: $path)* ::FnPointer::<$($generics)* $output_ty>
230    };
231    ([                             ]{$($path:ident)*}{$($generics:tt)*}{             } ) => {
232        $crate $(:: $path)* ::FnPointer::<$($generics)* ()        >
233    };
234    ([&mut $t:ty $(, $($rest:tt)*)?]{$($path:ident)*}{$($generics:tt)*} $output_ty:tt  ) => {
235        $crate::__fn_pointer! { [$($($rest)*)?]{$($path)* r#mut}{$($generics)* $t,} $output_ty }
236    };
237    ([&    $t:ty $(, $($rest:tt)*)?]{$($path:ident)*}{$($generics:tt)*} $output_ty:tt  ) => {
238        $crate::__fn_pointer! { [$($($rest)*)?]{$($path)* r#ref}{$($generics)* $t,} $output_ty }
239    };
240    ([     $t:ty $(, $($rest:tt)*)?]{$($path:ident)*}{$($generics:tt)*} $output_ty:tt  ) => {
241        $crate::__fn_pointer! { [$($($rest)*)?]{$($path)* value}{$($generics)* $t,} $output_ty }
242    };
243}
244
245#[doc(hidden)]
246#[macro_export]
247macro_rules! __callable_input_resolved {
248    // --- no explicit output type
249    ($input:tt                   $body:expr   $(, $($rest:tt)*)?) => {
250        $crate::__callable_all_resolved! { $input [       ] [   $body   ] $($($rest)*)? }
251    };
252    // This branch is for dev experience
253    ($input:tt               { $($body:tt)* } $(, $($rest:tt)*)?) => {
254        $crate::__callable_all_resolved! { $input [       ] [{$($body)*}] $($($rest)*)? }
255    };
256    // --- explicit output
257    ($input:tt -> $output:ty { $($body:tt)* } $(, $($rest:tt)*)?) => {
258        $crate::__callable_all_resolved! { $input [$output] [{$($body)*}] $($($rest)*)? }
259    };
260}
261
262#[doc(hidden)]
263#[macro_export]
264macro_rules! __callable_all_resolved {
265    // no   state
266    ([{$($method_path:tt)*}{$([$($input:tt)*])*}][$($output:ty)?][$($body:tt)*]) => {
267        $crate $(::$method_path)* ::FnPointer                    (
268            |$($($input)*),*               | $(-> $output)? $($body)*
269        )
270    };
271    // one  state
272    ([{$($method_path:tt)*}{$([$($input:tt)*])*}][$($output:ty)?][$($body:tt)*]   $state:ident $(= $state_expr:expr)?    $(,)?) => {
273        $crate $(::$method_path)* ::r#ref::provide_last_argument (
274            |$($($input)* ,)* $state       | $(-> $output)? $($body)* ,
275            $crate::__expand_or!([$($state_expr)?] $state),
276        )
277    };
278    // many states
279    ([{$($method_path:tt)*}{$([$($input:tt)*])*}][$($output:ty)?][$($body:tt)*] $($state:ident $(= $state_expr:expr)?),+ $(,)?) => {
280        $crate $(::$method_path)* ::r#ref::provide_last_argument (
281            |$($($input)* ,)* ($($state,)+)| $(-> $output)? $($body)* ,
282            ($( $crate::__expand_or!([$($state_expr)?] $state) ,)+),
283        )
284    };
285}