magic_args/
lib.rs

1//! "Magic" declarative-style function arguments.
2//!
3//! A cursed exercise of the type system.
4//!
5//! ```
6//! # use magic_args::apply;
7//! fn f0() { /* ... */ }
8//! fn f1(x: i32) { /* ... */ }
9//! fn f2(x: i32, z: usize) { /* ... */ }
10//! async fn f3(y: &'static str) { /* ... */ }
11//! async fn f4(y: &'static str, x: i32, z: usize) { /* ... */ }
12//!
13//! let args = (-42_i32, "🦀", 42_usize);
14//!
15//! let _ = apply(f0, &args);
16//! let _ = apply(f1, &args);
17//! let _ = apply(f2, &args);
18//! let _ = apply(f3, &args);
19//! let _ = apply(f4, &args);
20//! ```
21//!
22//! The original idea for this crate comes from [axum's route handlers], which
23//! do this exact thing with their arguments.
24//!
25//! # Quick start
26//!
27//! ```
28//! use magic_args::apply;
29//!
30//! fn f(x: usize, z: &str) -> usize { x + z.len() }
31//!
32//! let args = (31_i32, "foo", 42_usize);
33//!
34//! let y = apply(f, args);
35//! assert_eq!(y, 45);
36//! ```
37//!
38//! It is also possible to have a custom type as `args` (instead of a tuple).
39//!
40//! ```
41//! use magic_args::{apply, MagicArgs};
42//!
43//! fn f(x: usize, z: &str) -> usize { x + z.len() }
44//!
45//! #[derive(MagicArgs)]
46//! struct MyArgs(i32, &'static str, usize);
47//!
48//! let args = MyArgs(31, "foo", 42);
49//!
50//! let y = apply(f, args);
51//! assert_eq!(y, 45);
52//! ```
53//!
54//! # How it works
55//!
56//! The core of this crate is [`Callable`] and [`Args`]. Everything else is only
57//! for convenience and ease of use.
58//!
59//! I will now try to _briefly_ explain how this crate works.
60//!
61//! ## The [`Args`] trait
62//!
63//! The [`Args`] trait describes any kind of type that can act as an "argument
64//! set". This is essentially the type which contains every argument available.
65//!
66//! The [`Args`] trait has blanket implementations for tuples of up to 32
67//! elements. It is also possible to turn any type into [`Args`] with the
68//! [`macro@MagicArgs`] macro. It _is_ possible to hand-implement [`Args`] but
69//! this is not recommended as you must rely on the internal constructs of this
70//! crate that are subject to change at any time.
71//!
72//! ## The [`Callable`] trait
73//!
74//! This is where the magic happens. [`Callable`] describes anything that can
75//! be called with an argument set. It is blanket-implemented for any `FnOnce`
76//! with up to 32 arguments.
77//!
78//! The trait is defined over $A$ and $T$. $A$ is the argument set needed and
79//! $T$ is an ordered tuple which contains the types of the arguments the
80//! function expects to receive. For example, in the following function:
81//!
82//! ```no_run
83//! fn f(x: u32, y: i32, z: usize) {}
84//! ```
85//!
86//! $A$ is any `A: Args<u32> + Args<i32> + Args<usize>` and $T$ is `(u32, i32,
87//! usize)`. The type parameter $T$ is only there to provide disambiguation
88//! for the different `impl`s. Without it, it would be impossible to provide
89//! implementations of `Callable<A>` for `FnOnce()` and `FnOnce(U)` at the same
90//! time. This is because the language, at this time, lacks [specialized trait
91//! `impl`s]. With $T$, the implemented trait is `Callable<A, ()>` for `FnOnce()`
92//! and `Callable<A, (U,)>` for `FnOnce(U)` (which are technically different
93//! traits and thus are allowed to coexist with blanket implementations).
94//!
95//! ## An implementation detail
96//!
97//! **NOTE:** This section serves only as a guide for hackers and just
98//! to explain how the crate works. Nothing here is to be considered as a
99//! semver-stable API. Consider yourself warned.
100//!
101//! If you tried to implement [`Args`] for a tuple of `(T0, T1)`, it would
102//! probably look a bit like this:
103//!
104//! ```compile_fail,E0119
105//! # use magic_args::Args;
106//! impl<T0: Clone, T1> Args<T0> for (T0, T1) {
107//!     fn get(&self) -> T0 { self.0.clone() }
108//! }
109//!
110//! impl<T0, T1: Clone> Args<T1> for (T0, T1) {
111//!     fn get(&self) -> T1 { self.1.clone() }
112//! }
113//! ```
114//!
115//! Which, as you might have guessed from the red border above, does not work.
116//! This is because the above implementations are not well-defined. Consider the
117//! following type, $(i32, i32)$. What happens when we invoke [`Args::get`] on
118//! that type? Do we get back the first or the second field? This is the edge
119//! case the compiler tries to warn us about. As of writing this crate, there is
120//! no support for specifying type bounds like `T0 != T1`. So we can't just say
121//! "where `T0 != T1`" and be done.
122//!
123//! There is another, arguably more convuluted way to describe this. If we
124//! introduce a type `Tagged<T, const N: usize>(T)` we can have many "unique"
125//! $T$s. This is because `Tagged<i32, 0>` is not the same as `Tagged<i32, 1>`.
126//! We can use this little property to modify our [`Args`] implementation a bit;
127//! instead of returning `T0` or `T1`, we return `Tagged<T0, 0>` and
128//! `Tagged<T1, 1>` respectively. This solves our previous issue of
129//! "conflicting implementations" since we are now implementing what is now
130//! 2 different traits; `Args<Tagged<T0, 0>>` and `Args<Tagged<T1, 1>>`. We can
131//! now modify the [`Callable`] `impl`s to take `const N0: usize`,
132//! `const N1: usize` and `A: Args<Tagged<T0, N0>> + Args<Tagged<T1, N1>>`.
133//! This solves our issue and allows all implementations to coexist. For tuples,
134//! the `N` constant in `Tagged` is the index of the field. The
135//! [`macro@MagicArgs`] also uses the index of the field for `N`. `N` is there
136//! to serve as a "tag" for each field. Its value does not really matter, only
137//! that it is different for each field.
138//!
139//! # Limitations
140//!
141//! - This crate operates wholly at the type-level. There is no runtime code
142//!   generated as part of resolving arguments, etc. This makes the crate very
143//!   difficult to use in a dynamic setting.
144//!
145//! - You cannot have 2 different instances of the same type as arguments. For
146//!   example:
147//!
148//! ```compile_fail,E0284
149//! # use magic_args::apply;
150//! fn f(x: i32, y: i32) -> i32 { x + y }
151//!
152//! let args: (i32, i32) = (42, 31);
153//! let _y: i32 = apply(f, args);
154//! ```
155//!
156//!   This can be explained with the following example. Consider the following
157//!   function:
158//!
159//! ```
160//! fn f(x: i32, _y: i32) -> i32 { x }
161//! ```
162//!
163//!   Given only the signature of the function, $f: (i32, i32) \to i32$, can you
164//!   figure out the correct order to pass the values $42$ and $31$ such that
165//!   $f$ returns $42$? Spoiler alert: No. It is impossible. In this case, it is
166//!   not clear how we should pass the arguments to the function. Trying the
167//!   above will result in a cryptic error message(s). This can be alleviated
168//!   however by using a thin wrapper type which semantically conveys the
169//!   meaning of the data.
170//!
171//! ```
172//! # use magic_args::apply;
173//! #[derive(Clone)]
174//! struct X(pub i32);
175//!
176//! #[derive(Clone)]
177//! struct Y(pub i32);
178//!
179//! fn f(X(x): X, Y(y): Y) -> i32 { x + y }
180//!
181//! let args = (X(42), Y(31));
182//! let y = apply(f, args);
183//! assert_eq!(y, 73);
184//! ```
185//!
186//! - Passing non-[`Clone`] arguments is not ideal. Arguments need to be
187//!   [`Clone`] so the following is well-defined:
188//!
189//! ```
190//! # use magic_args::apply;
191//! fn f(x: i32, y: i32) -> i32 { x + y }
192//!
193//! let args = (42,);
194//! let y = apply(f, args);
195//! assert_eq!(y, 84)
196//! ```
197//!
198//!   Notice how this is different than the example before; we are only passing
199//!   one [`i32`], not two so there is no ambiguity here. In this case, the
200//!   value of [`i32`] is [`Clone::clone`]d and passed both as `x` and as `y`.
201//!   Meaning `f` could be rewritten as:
202//!
203//! ```
204//! fn f(x: i32) -> i32 { x * 2 }
205//! ```
206//!
207//!   It is possible to pass non-[`Clone`] arguments, but that needs runtime
208//!   checking to ensure only one instance exists. This can be done with
209//!   [`std::cell::RefCell`] if necessary.
210//!
211//! ---
212//!
213//! Enjoy responsibly!
214//!
215//! [specialized trait `impl`s]: https://github.com/rust-lang/rust/issues/31844
216//! [axum's route handlers]: https://docs.rs/axum/latest/axum/handler/index.html
217//! [`std::cell::RefCell`]: https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html
218
219#![cfg_attr(docsrs, feature(doc_auto_cfg))]
220#![forbid(unsafe_code)]
221#![no_std]
222extern crate self as magic_args;
223
224#[cfg(feature = "derive")]
225/// A derive macro to help you create argument sets.
226///
227/// This macro can be used only on `struct` items.
228///
229/// Generate the appropriate [`Args`] implementations for the annotated type
230/// allowing it to be used with [`Callable`].
231///
232/// # Field attributes
233///
234/// ## `skip`
235///
236/// * **Syntax:** `#[magic_args(skip)]`
237///
238/// Do not expose this field as an available argument. The resulting argument
239/// set will act as if this field does not exist.
240///
241/// ```compile_fail,E0277
242/// # use magic_args::{apply, MagicArgs};
243/// #[derive(MagicArgs)]
244/// struct Args(i32, usize, #[magic_args(skip)] &'static str);
245///
246/// fn f(_x: usize, _y: &'static str) {}
247///
248/// apply(f, Args(42, 42, "Hello, world!"));
249/// ```
250#[doc(inline)]
251pub use magic_args_derive::MagicArgs;
252
253///////////////////////////////////////////////////////////////////////////////
254
255/// A "set of arguments" that contains `T`.
256pub trait Args<T> {
257    /// Get `T` from the set of arguments.
258    ///
259    /// The signature of this method usually means that some copying/cloning
260    /// has to happen. To see why it is designed like this, please refer to the
261    /// [crate-level documentation](crate).
262    fn get(&self) -> T;
263}
264
265impl<T, U> Args<T> for &U
266where
267    U: Args<T>,
268{
269    fn get(&self) -> T {
270        U::get(*self)
271    }
272}
273
274#[doc(hidden)]
275pub mod __private {
276    #[derive(Clone)]
277    pub struct Tagged<T, const N: usize>(pub T);
278}
279
280use self::__private::*;
281
282macro_rules! impl_args_tuple {
283    ($($idx:tt: $t:ident),*) => {
284        impl_args_tuple!(@impl [$($idx: $t),*]: $(($idx, $t))*);
285    };
286    (@impl [$($_idx:tt: $_t:ident),*]:) => {};
287    (@impl [$($_idx:tt: $_t:ident),*]: ($idx:tt, $t:ident) $($tail:tt)*) => {
288        impl<$($_t,)*> Args<Tagged<$t, $idx>> for ($($_t,)*)
289        where
290            $t: Clone
291        {
292            fn get(&self) -> Tagged<$t, $idx> {
293                Tagged(self.$idx.clone())
294            }
295        }
296
297        impl_args_tuple!(@impl [$($_idx: $_t),*]: $($tail)*);
298    };
299}
300
301impl_args_tuple! {}
302impl_args_tuple! { 0: T0 }
303impl_args_tuple! { 0: T0, 1: T1 }
304impl_args_tuple! { 0: T0, 1: T1, 2: T2 }
305impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3 }
306impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4 }
307impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5 }
308impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6 }
309impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7 }
310impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8 }
311impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9 }
312impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10 }
313impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11 }
314impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12 }
315impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13 }
316impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14 }
317impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15 }
318impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16 }
319impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17 }
320impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18 }
321impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19 }
322impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19, 20: T20 }
323impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19, 20: T20, 21: T21 }
324impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19, 20: T20, 21: T21, 22: T22 }
325impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19, 20: T20, 21: T21, 22: T22, 23: T23 }
326impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19, 20: T20, 21: T21, 22: T22, 23: T23, 24: T24 }
327impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19, 20: T20, 21: T21, 22: T22, 23: T23, 24: T24, 25: T25 }
328impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19, 20: T20, 21: T21, 22: T22, 23: T23, 24: T24, 25: T25, 26: T26 }
329impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19, 20: T20, 21: T21, 22: T22, 23: T23, 24: T24, 25: T25, 26: T26, 27: T27 }
330impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19, 20: T20, 21: T21, 22: T22, 23: T23, 24: T24, 25: T25, 26: T26, 27: T27, 28: T28 }
331impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19, 20: T20, 21: T21, 22: T22, 23: T23, 24: T24, 25: T25, 26: T26, 27: T27, 28: T28, 29: T29 }
332impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19, 20: T20, 21: T21, 22: T22, 23: T23, 24: T24, 25: T25, 26: T26, 27: T27, 28: T28, 29: T29, 30: T30 }
333impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10, 11: T11, 12: T12, 13: T13, 14: T14, 15: T15, 16: T16, 17: T17, 18: T18, 19: T19, 20: T20, 21: T21, 22: T22, 23: T23, 24: T24, 25: T25, 26: T26, 27: T27, 28: T28, 29: T29, 30: T30, 31: T31 }
334
335///////////////////////////////////////////////////////////////////////////////
336
337/// A trait to describe any kind of type that can be called.
338///
339/// This trait and the [`Args`] trait are the foundation of the crate. It
340/// provides [`Callable::call`] which is how [`apply`] (and friends) work.
341pub trait Callable<A, T> {
342    type Output;
343
344    fn call(self, args: A) -> Self::Output;
345}
346
347macro_rules! impl_callable_fnonce {
348    ($($t:ident: $n:ident),*) => {
349        impl<F, O, A, $($t,)* $(const $n: usize,)*> Callable<A, ($(Tagged<$t, $n>,)*)> for F
350        where
351            F: FnOnce($($t),*) -> O,
352            $(A: Args<Tagged<$t, $n>>,)*
353        {
354            type Output = O;
355
356            #[allow(non_snake_case)]
357            fn call(self, _args: A) -> Self::Output {
358                $(let $t = <A as Args<Tagged<$t, $n>>>::get(&_args);)*
359                (self)($($t.0,)*)
360            }
361        }
362    };
363}
364
365impl_callable_fnonce! {}
366impl_callable_fnonce! { T0: N0 }
367impl_callable_fnonce! { T0: N0, T1: N1 }
368impl_callable_fnonce! { T0: N0, T1: N1, T2: N2 }
369impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3 }
370impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4 }
371impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5 }
372impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6 }
373impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7 }
374impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8 }
375impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9 }
376impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10 }
377impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11 }
378impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12 }
379impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13 }
380impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14 }
381impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15 }
382impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16 }
383impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17 }
384impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18 }
385impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19 }
386impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19, T20: N20 }
387impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19, T20: N20, T21: N21 }
388impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19, T20: N20, T21: N21, T22: N22 }
389impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19, T20: N20, T21: N21, T22: N22, T23: N23 }
390impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19, T20: N20, T21: N21, T22: N22, T23: N23, T24: N24 }
391impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19, T20: N20, T21: N21, T22: N22, T23: N23, T24: N24, T25: N25 }
392impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19, T20: N20, T21: N21, T22: N22, T23: N23, T24: N24, T25: N25, T26: N26 }
393impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19, T20: N20, T21: N21, T22: N22, T23: N23, T24: N24, T25: N25, T26: N26, T27: N27 }
394impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19, T20: N20, T21: N21, T22: N22, T23: N23, T24: N24, T25: N25, T26: N26, T27: N27, T28: N28 }
395impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19, T20: N20, T21: N21, T22: N22, T23: N23, T24: N24, T25: N25, T26: N26, T27: N27, T28: N28, T29: N29 }
396impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19, T20: N20, T21: N21, T22: N22, T23: N23, T24: N24, T25: N25, T26: N26, T27: N27, T28: N28, T29: N29, T30: N30 }
397impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10, T11: N11, T12: N12, T13: N13, T14: N14, T15: N15, T16: N16, T17: N17, T18: N18, T19: N19, T20: N20, T21: N21, T22: N22, T23: N23, T24: N24, T25: N25, T26: N26, T27: N27, T28: N28, T29: N29, T30: N30, T31: N31 }
398
399///////////////////////////////////////////////////////////////////////////////
400
401/// A convinience trait to provide the `args.apply(f)` syntax.
402pub trait MagicArgs {
403    /// Apply _f_ on `self`.
404    ///
405    /// Equivalent to: `apply(f, self)`.
406    ///
407    /// See: [`apply`].
408    ///
409    /// # Examples
410    ///
411    /// ```
412    /// # use magic_args::{apply, MagicArgs};
413    /// fn f(x: i32) -> i32 { x + 1 }
414    ///
415    /// let y = ("🦀", 41).apply(f);
416    /// assert_eq!(y, 42);
417    /// ```
418    fn apply<C, T>(self, f: C) -> C::Output
419    where
420        C: Callable<Self, T>,
421        Self: Sized;
422}
423
424impl<U> MagicArgs for U {
425    #[inline]
426    fn apply<C, T>(self, f: C) -> C::Output
427    where
428        C: Callable<Self, T>,
429        Self: Sized,
430    {
431        apply(f, self)
432    }
433}
434
435/// Apply _f_ on `args`.
436///
437/// Equivalent to: `f.call(args)`.
438///
439/// See: [`Callable::call`].
440///
441/// # Examples
442///
443/// ```
444/// # use magic_args::{apply, MagicArgs};
445/// fn f(x: i32) -> i32 { x + 1 }
446///
447/// let y = apply(f, ("🦀", 41));
448/// assert_eq!(y, 42);
449/// ```
450#[inline]
451pub fn apply<C, A, T>(f: C, args: A) -> C::Output
452where
453    C: Callable<A, T>,
454{
455    f.call(args)
456}
457
458#[cfg(test)]
459mod tests {
460    use super::*;
461
462    #[test]
463    fn test_sync_functions() {
464        let args = (42u32, 31i32);
465
466        fn f0() -> i32 {
467            42
468        }
469
470        fn f1(x: u32) -> i32 {
471            x as i32
472        }
473
474        fn f2(y: i32, x: u32) -> i32 {
475            y + x as i32
476        }
477
478        fn f3(x: u32, y: u32) -> u32 {
479            x + y
480        }
481
482        assert_eq!(args.apply(f0), 42);
483        assert_eq!(args.apply(f1), 42);
484        assert_eq!(args.apply(f2), 73);
485        assert_eq!(args.apply(f3), 84);
486    }
487
488    #[test]
489    fn test_sync_closures() {
490        let args = (42u32, 31i32);
491
492        let data = &[1_i32, 2, 3, 4, 5];
493
494        assert_eq!(args.apply(|| { data.iter().sum::<i32>() }), 15);
495        assert_eq!(
496            args.apply(|x: u32| { data.iter().sum::<i32>() + x as i32 }),
497            57
498        );
499        assert_eq!(
500            args.apply(|y: i32, x: u32| { data.iter().sum::<i32>() + y + x as i32 }),
501            88
502        );
503        assert_eq!(
504            args.apply(|x: u32, y: u32| { data.iter().sum::<i32>() as u32 + x + y }),
505            99
506        );
507    }
508
509    #[test]
510    fn test_async() {
511        fn assert_future<F: Future>(_f: F) {}
512
513        let args = (42u32, 31i32);
514
515        async fn f0() -> i32 {
516            42
517        }
518
519        async fn f1(x: u32) -> i32 {
520            x as i32
521        }
522
523        async fn f2(y: i32, x: u32) -> i32 {
524            y + x as i32
525        }
526
527        async fn f3(x: u32, y: u32) -> u32 {
528            x + y
529        }
530
531        assert_future(args.apply(f0));
532        assert_future(args.apply(f1));
533        assert_future(args.apply(f2));
534        assert_future(args.apply(f3));
535    }
536
537    #[cfg(feature = "derive")]
538    mod derive {
539        use super::*;
540
541        #[test]
542        fn test_derive_tuple() {
543            #[derive(MagicArgs)]
544            struct MyArgs(i32, u32);
545
546            let args = MyArgs(42, 31);
547            assert_eq!(args.apply(|x: u32, _y: i32| x as i32), 31);
548        }
549
550        #[test]
551        fn test_derive_struct() {
552            #[derive(MagicArgs)]
553            struct MyArgs {
554                x: i32,
555                y: u32,
556            }
557
558            let args = MyArgs { x: 42, y: 31 };
559            assert_eq!(args.apply(|x: u32, _y: i32| x as i32), 31);
560        }
561
562        #[test]
563        fn test_derive_struct_lifetime() {
564            #[derive(MagicArgs)]
565            struct MyArgs<'a>(&'a str);
566
567            let args = MyArgs("Hello, World!");
568            assert_eq!(args.apply(|x: &str| x.len()), 13);
569        }
570    }
571}