Skip to main content

magic_args/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![no_std]
4extern crate self as magic_args;
5
6mod r#mut;
7pub use self::r#mut::Mut;
8
9mod extend;
10pub use self::extend::Extend;
11
12///////////////////////////////////////////////////////////////////////////////
13
14#[cfg(feature = "derive")]
15/// A derive macro to help you create argument sets.
16///
17/// This macro can be used only on `struct` items.
18///
19/// Generate the appropriate [`Args`] implementations for the annotated type
20/// allowing it to be used with [`Callable`].
21///
22/// # Field attributes
23///
24/// ## `skip`
25///
26/// * **Syntax:** `#[magic_args(skip)]`
27///
28/// Do not expose this field as an available argument. The resulting argument
29/// set will act as if this field does not exist.
30///
31/// ```compile_fail,E0277
32/// # use magic_args::{apply, MagicArgs};
33/// #[derive(MagicArgs)]
34/// struct Args(i32, usize, #[magic_args(skip)] &'static str);
35///
36/// fn f(_x: usize, _y: &'static str) {}
37///
38/// apply(f, Args(42, 42, "Hello, world!"));
39/// ```
40#[doc(inline)]
41pub use magic_args_derive::MagicArgs;
42
43///////////////////////////////////////////////////////////////////////////////
44
45/// A "set of arguments" that contains `T`.
46pub trait Args<T> {
47    /// Get `T` from the set of arguments.
48    ///
49    /// The signature of this method usually means that some copying/cloning
50    /// has to happen. To see why it is designed like this, please refer to the
51    /// [crate-level documentation](crate).
52    fn get(&self) -> T;
53}
54
55impl<T, U> Args<T> for &U
56where
57    U: Args<T>,
58{
59    fn get(&self) -> T {
60        U::get(*self)
61    }
62}
63
64#[doc(hidden)]
65pub mod __private {
66    #[expect(missing_debug_implementations)]
67    #[derive(Clone)]
68    pub struct Tagged<T, const N: usize>(pub T);
69}
70
71use self::__private::*;
72
73macro_rules! impl_args_tuple {
74    ($($idx:tt: $t:ident),*) => {
75        impl_args_tuple!(@impl [$($idx: $t),*]: $(($idx, $t))*);
76    };
77    (@impl [$($_idx:tt: $_t:ident),*]:) => {};
78    (@impl [$($_idx:tt: $_t:ident),*]: ($idx:tt, $t:ident) $($tail:tt)*) => {
79        impl<$($_t,)*> Args<Tagged<$t, $idx>> for ($($_t,)*)
80        where
81            $t: Clone
82        {
83            fn get(&self) -> Tagged<$t, $idx> {
84                Tagged(self.$idx.clone())
85            }
86        }
87
88        impl_args_tuple!(@impl [$($_idx: $_t),*]: $($tail)*);
89    };
90}
91
92impl_args_tuple! {}
93impl_args_tuple! { 0: T0 }
94impl_args_tuple! { 0: T0, 1: T1 }
95impl_args_tuple! { 0: T0, 1: T1, 2: T2 }
96impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3 }
97impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4 }
98impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5 }
99impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6 }
100impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7 }
101impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8 }
102impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9 }
103impl_args_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9, 10: T10 }
104impl_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 }
105impl_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 }
106impl_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 }
107impl_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 }
108impl_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 }
109impl_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 }
110impl_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 }
111impl_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 }
112impl_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 }
113impl_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 }
114impl_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 }
115impl_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 }
116impl_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 }
117impl_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 }
118impl_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 }
119impl_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 }
120impl_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 }
121impl_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 }
122impl_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 }
123impl_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 }
124impl_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 }
125
126///////////////////////////////////////////////////////////////////////////////
127
128/// A trait to describe any kind of type that can be called.
129///
130/// This trait and the [`Args`] trait are the foundation of the crate. It
131/// provides [`Callable::call`] which is how [`apply`] (and friends) work.
132pub trait Callable<A, T> {
133    #[expect(missing_docs)]
134    type Output;
135
136    #[expect(missing_docs)]
137    fn call(self, args: A) -> Self::Output;
138}
139
140macro_rules! impl_callable_fnonce {
141    ($($t:ident: $n:ident),*) => {
142        impl<F, O, A, $($t,)* $(const $n: usize,)*> Callable<A, ($(Tagged<$t, $n>,)*)> for F
143        where
144            F: FnOnce($($t),*) -> O,
145            $(A: Args<Tagged<$t, $n>>,)*
146        {
147            type Output = O;
148
149            #[allow(non_snake_case)]
150            fn call(self, _args: A) -> Self::Output {
151                $(let $t = <A as Args<Tagged<$t, $n>>>::get(&_args);)*
152                (self)($($t.0,)*)
153            }
154        }
155    };
156}
157
158impl_callable_fnonce! {}
159impl_callable_fnonce! { T0: N0 }
160impl_callable_fnonce! { T0: N0, T1: N1 }
161impl_callable_fnonce! { T0: N0, T1: N1, T2: N2 }
162impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3 }
163impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4 }
164impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5 }
165impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6 }
166impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7 }
167impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8 }
168impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9 }
169impl_callable_fnonce! { T0: N0, T1: N1, T2: N2, T3: N3, T4: N4, T5: N5, T6: N6, T7: N7, T8: N8, T9: N9, T10: N10 }
170impl_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 }
171impl_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 }
172impl_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 }
173impl_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 }
174impl_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 }
175impl_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 }
176impl_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 }
177impl_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 }
178impl_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 }
179impl_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 }
180impl_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 }
181impl_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 }
182impl_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 }
183impl_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 }
184impl_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 }
185impl_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 }
186impl_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 }
187impl_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 }
188impl_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 }
189impl_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 }
190impl_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 }
191
192///////////////////////////////////////////////////////////////////////////////
193
194/// A convinience trait to provide the `args.apply(f)` syntax.
195pub trait MagicArgs {
196    /// Apply _f_ on `self`.
197    ///
198    /// Equivalent to: `apply(f, self)`.
199    ///
200    /// See: [`apply`].
201    ///
202    /// # Examples
203    ///
204    /// ```
205    /// # use magic_args::{apply, MagicArgs};
206    /// fn f(x: i32) -> i32 { x + 1 }
207    ///
208    /// let y = ("🦀", 41).apply(f);
209    /// assert_eq!(y, 42);
210    /// ```
211    fn apply<C, T>(self, f: C) -> C::Output
212    where
213        C: Callable<Self, T>,
214        Self: Sized;
215}
216
217impl<U> MagicArgs for U {
218    #[inline]
219    fn apply<C, T>(self, f: C) -> C::Output
220    where
221        C: Callable<Self, T>,
222        Self: Sized,
223    {
224        apply(f, self)
225    }
226}
227
228/// Apply _f_ on `args`.
229///
230/// Equivalent to: `f.call(args)`.
231///
232/// See: [`Callable::call`].
233///
234/// # Examples
235///
236/// ```
237/// # use magic_args::{apply, MagicArgs};
238/// fn f(x: i32) -> i32 { x + 1 }
239///
240/// let y = apply(f, ("🦀", 41));
241/// assert_eq!(y, 42);
242/// ```
243#[inline]
244pub fn apply<C, A, T>(f: C, args: A) -> C::Output
245where
246    C: Callable<A, T>,
247{
248    f.call(args)
249}
250
251///////////////////////////////////////////////////////////////////////////////
252
253#[cfg(test)]
254mod tests {
255    use super::*;
256
257    #[test]
258    #[expect(clippy::cast_possible_wrap)]
259    fn test_sync_functions() {
260        let args = (42u32, 31i32);
261
262        fn f0() -> i32 {
263            42
264        }
265
266        fn f1(x: u32) -> i32 {
267            x as i32
268        }
269
270        fn f2(y: i32, x: u32) -> i32 {
271            y + x as i32
272        }
273
274        fn f3(x: u32, y: u32) -> u32 {
275            x + y
276        }
277
278        assert_eq!(args.apply(f0), 42);
279        assert_eq!(args.apply(f1), 42);
280        assert_eq!(args.apply(f2), 73);
281        assert_eq!(args.apply(f3), 84);
282    }
283
284    #[test]
285    #[expect(clippy::cast_possible_wrap)]
286    fn test_sync_closures() {
287        let args = (42u32, 31i32);
288
289        let data = &[1_i32, 2, 3, 4, 5];
290
291        assert_eq!(args.apply(|| { data.iter().sum::<i32>() }), 15);
292        assert_eq!(
293            args.apply(|x: u32| { data.iter().sum::<i32>() + x as i32 }),
294            57
295        );
296        assert_eq!(
297            args.apply(|y: i32, x: u32| { data.iter().sum::<i32>() + y + x as i32 }),
298            88
299        );
300        assert_eq!(
301            args.apply(|x: u32, y: u32| { data.iter().sum::<i32>() as u32 + x + y }),
302            99
303        );
304    }
305
306    #[test]
307    #[expect(clippy::cast_possible_wrap)]
308    fn test_async() {
309        fn assert_future<F: Future>(_f: F) {}
310
311        let args = (42u32, 31i32);
312
313        async fn f0() -> i32 {
314            42
315        }
316
317        async fn f1(x: u32) -> i32 {
318            x as i32
319        }
320
321        async fn f2(y: i32, x: u32) -> i32 {
322            y + x as i32
323        }
324
325        async fn f3(x: u32, y: u32) -> u32 {
326            x + y
327        }
328
329        assert_future(args.apply(f0));
330        assert_future(args.apply(f1));
331        assert_future(args.apply(f2));
332        assert_future(args.apply(f3));
333    }
334
335    #[cfg(feature = "derive")]
336    mod derive {
337        use super::*;
338
339        #[test]
340        #[expect(clippy::cast_possible_wrap)]
341        fn test_derive_tuple() {
342            #[derive(MagicArgs)]
343            struct MyArgs(i32, u32);
344
345            let args = MyArgs(42, 31);
346            assert_eq!(args.apply(|x: u32, _y: i32| x as i32), 31);
347        }
348
349        #[test]
350        #[expect(clippy::cast_possible_wrap)]
351        fn test_derive_struct() {
352            #[derive(MagicArgs)]
353            struct MyArgs {
354                x: i32,
355                y: u32,
356            }
357
358            let args = MyArgs { x: 42, y: 31 };
359            assert_eq!(args.apply(|x: u32, _y: i32| x as i32), 31);
360        }
361
362        #[test]
363        fn test_derive_struct_lifetime() {
364            #[derive(MagicArgs)]
365            struct MyArgs<'a>(&'a str);
366
367            let args = MyArgs("Hello, World!");
368            assert_eq!(args.apply(|x: &str| x.len()), 13);
369        }
370    }
371}