Skip to main content

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_cfg))]
220#![forbid(unsafe_code)]
221#![no_std]
222extern crate self as magic_args;
223
224mod extend;
225pub use self::extend::Extend;
226
227///////////////////////////////////////////////////////////////////////////////
228
229#[cfg(feature = "derive")]
230/// A derive macro to help you create argument sets.
231///
232/// This macro can be used only on `struct` items.
233///
234/// Generate the appropriate [`Args`] implementations for the annotated type
235/// allowing it to be used with [`Callable`].
236///
237/// # Field attributes
238///
239/// ## `skip`
240///
241/// * **Syntax:** `#[magic_args(skip)]`
242///
243/// Do not expose this field as an available argument. The resulting argument
244/// set will act as if this field does not exist.
245///
246/// ```compile_fail,E0277
247/// # use magic_args::{apply, MagicArgs};
248/// #[derive(MagicArgs)]
249/// struct Args(i32, usize, #[magic_args(skip)] &'static str);
250///
251/// fn f(_x: usize, _y: &'static str) {}
252///
253/// apply(f, Args(42, 42, "Hello, world!"));
254/// ```
255#[doc(inline)]
256pub use magic_args_derive::MagicArgs;
257
258///////////////////////////////////////////////////////////////////////////////
259
260/// A "set of arguments" that contains `T`.
261pub trait Args<T> {
262    /// Get `T` from the set of arguments.
263    ///
264    /// The signature of this method usually means that some copying/cloning
265    /// has to happen. To see why it is designed like this, please refer to the
266    /// [crate-level documentation](crate).
267    fn get(&self) -> T;
268}
269
270impl<T, U> Args<T> for &U
271where
272    U: Args<T>,
273{
274    fn get(&self) -> T {
275        U::get(*self)
276    }
277}
278
279#[doc(hidden)]
280pub mod __private {
281    #[derive(Clone)]
282    pub struct Tagged<T, const N: usize>(pub T);
283}
284
285use self::__private::*;
286
287macro_rules! impl_args_tuple {
288    ($($idx:tt: $t:ident),*) => {
289        impl_args_tuple!(@impl [$($idx: $t),*]: $(($idx, $t))*);
290    };
291    (@impl [$($_idx:tt: $_t:ident),*]:) => {};
292    (@impl [$($_idx:tt: $_t:ident),*]: ($idx:tt, $t:ident) $($tail:tt)*) => {
293        impl<$($_t,)*> Args<Tagged<$t, $idx>> for ($($_t,)*)
294        where
295            $t: Clone
296        {
297            fn get(&self) -> Tagged<$t, $idx> {
298                Tagged(self.$idx.clone())
299            }
300        }
301
302        impl_args_tuple!(@impl [$($_idx: $_t),*]: $($tail)*);
303    };
304}
305
306impl_args_tuple! {}
307impl_args_tuple! { 0: T0 }
308impl_args_tuple! { 0: T0, 1: T1 }
309impl_args_tuple! { 0: T0, 1: T1, 2: T2 }
310impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3 }
311impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4 }
312impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5 }
313impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6 }
314impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7 }
315impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8 }
316impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
334impl_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 }
335impl_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 }
336impl_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 }
337impl_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 }
338impl_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 }
339
340///////////////////////////////////////////////////////////////////////////////
341
342/// A trait to describe any kind of type that can be called.
343///
344/// This trait and the [`Args`] trait are the foundation of the crate. It
345/// provides [`Callable::call`] which is how [`apply`] (and friends) work.
346pub trait Callable<A, T> {
347    type Output;
348
349    fn call(self, args: A) -> Self::Output;
350}
351
352macro_rules! impl_callable_fnonce {
353    ($($t:ident: $n:ident),*) => {
354        impl<F, O, A, $($t,)* $(const $n: usize,)*> Callable<A, ($(Tagged<$t, $n>,)*)> for F
355        where
356            F: FnOnce($($t),*) -> O,
357            $(A: Args<Tagged<$t, $n>>,)*
358        {
359            type Output = O;
360
361            #[allow(non_snake_case)]
362            fn call(self, _args: A) -> Self::Output {
363                $(let $t = <A as Args<Tagged<$t, $n>>>::get(&_args);)*
364                (self)($($t.0,)*)
365            }
366        }
367    };
368}
369
370impl_callable_fnonce! {}
371impl_callable_fnonce! { T0: N0 }
372impl_callable_fnonce! { T0: N0, T1: N1 }
373impl_callable_fnonce! { T0: N0, T1: N1, T2: N2 }
374impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3 }
375impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4 }
376impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5 }
377impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6 }
378impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7 }
379impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8 }
380impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
398impl_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 }
399impl_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 }
400impl_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 }
401impl_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 }
402impl_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 }
403
404///////////////////////////////////////////////////////////////////////////////
405
406/// A convinience trait to provide the `args.apply(f)` syntax.
407pub trait MagicArgs {
408    /// Apply _f_ on `self`.
409    ///
410    /// Equivalent to: `apply(f, self)`.
411    ///
412    /// See: [`apply`].
413    ///
414    /// # Examples
415    ///
416    /// ```
417    /// # use magic_args::{apply, MagicArgs};
418    /// fn f(x: i32) -> i32 { x + 1 }
419    ///
420    /// let y = ("🦀", 41).apply(f);
421    /// assert_eq!(y, 42);
422    /// ```
423    fn apply<C, T>(self, f: C) -> C::Output
424    where
425        C: Callable<Self, T>,
426        Self: Sized;
427}
428
429impl<U> MagicArgs for U {
430    #[inline]
431    fn apply<C, T>(self, f: C) -> C::Output
432    where
433        C: Callable<Self, T>,
434        Self: Sized,
435    {
436        apply(f, self)
437    }
438}
439
440/// Apply _f_ on `args`.
441///
442/// Equivalent to: `f.call(args)`.
443///
444/// See: [`Callable::call`].
445///
446/// # Examples
447///
448/// ```
449/// # use magic_args::{apply, MagicArgs};
450/// fn f(x: i32) -> i32 { x + 1 }
451///
452/// let y = apply(f, ("🦀", 41));
453/// assert_eq!(y, 42);
454/// ```
455#[inline]
456pub fn apply<C, A, T>(f: C, args: A) -> C::Output
457where
458    C: Callable<A, T>,
459{
460    f.call(args)
461}
462
463#[cfg(test)]
464mod tests {
465    use super::*;
466
467    #[test]
468    fn test_sync_functions() {
469        let args = (42u32, 31i32);
470
471        fn f0() -> i32 {
472            42
473        }
474
475        fn f1(x: u32) -> i32 {
476            x as i32
477        }
478
479        fn f2(y: i32, x: u32) -> i32 {
480            y + x as i32
481        }
482
483        fn f3(x: u32, y: u32) -> u32 {
484            x + y
485        }
486
487        assert_eq!(args.apply(f0), 42);
488        assert_eq!(args.apply(f1), 42);
489        assert_eq!(args.apply(f2), 73);
490        assert_eq!(args.apply(f3), 84);
491    }
492
493    #[test]
494    fn test_sync_closures() {
495        let args = (42u32, 31i32);
496
497        let data = &[1_i32, 2, 3, 4, 5];
498
499        assert_eq!(args.apply(|| { data.iter().sum::<i32>() }), 15);
500        assert_eq!(
501            args.apply(|x: u32| { data.iter().sum::<i32>() + x as i32 }),
502            57
503        );
504        assert_eq!(
505            args.apply(|y: i32, x: u32| { data.iter().sum::<i32>() + y + x as i32 }),
506            88
507        );
508        assert_eq!(
509            args.apply(|x: u32, y: u32| { data.iter().sum::<i32>() as u32 + x + y }),
510            99
511        );
512    }
513
514    #[test]
515    fn test_async() {
516        fn assert_future<F: Future>(_f: F) {}
517
518        let args = (42u32, 31i32);
519
520        async fn f0() -> i32 {
521            42
522        }
523
524        async fn f1(x: u32) -> i32 {
525            x as i32
526        }
527
528        async fn f2(y: i32, x: u32) -> i32 {
529            y + x as i32
530        }
531
532        async fn f3(x: u32, y: u32) -> u32 {
533            x + y
534        }
535
536        assert_future(args.apply(f0));
537        assert_future(args.apply(f1));
538        assert_future(args.apply(f2));
539        assert_future(args.apply(f3));
540    }
541
542    #[cfg(feature = "derive")]
543    mod derive {
544        use super::*;
545
546        #[test]
547        fn test_derive_tuple() {
548            #[derive(MagicArgs)]
549            struct MyArgs(i32, u32);
550
551            let args = MyArgs(42, 31);
552            assert_eq!(args.apply(|x: u32, _y: i32| x as i32), 31);
553        }
554
555        #[test]
556        fn test_derive_struct() {
557            #[derive(MagicArgs)]
558            struct MyArgs {
559                x: i32,
560                y: u32,
561            }
562
563            let args = MyArgs { x: 42, y: 31 };
564            assert_eq!(args.apply(|x: u32, _y: i32| x as i32), 31);
565        }
566
567        #[test]
568        fn test_derive_struct_lifetime() {
569            #[derive(MagicArgs)]
570            struct MyArgs<'a>(&'a str);
571
572            let args = MyArgs("Hello, World!");
573            assert_eq!(args.apply(|x: &str| x.len()), 13);
574        }
575    }
576}