tuple_fn/
lib.rs

1//! This crate provides [`TupleFnOnce`], [`TupleFnMut`] and [`TupleFn`],
2//! corresponding to [`FnOnce`], [`FnMut`] and [`Fn`].
3//!
4//! [`TupleFnOnce`], [`TupleFnMut`] and [`TupleFn`] enables functions or closures
5//! to be called with a tuple of arguments.
6//! For example:
7//!
8//! ```
9//! use tuple_fn::*;
10//!
11//! fn add(a: i32, b: i32) -> i32 {
12//!     a + b
13//! }
14//!
15//! let sum = add.call_with_args_tuple((1, 2));
16//! assert_eq!(sum, 3);
17//! ```
18//!
19//! These three traits should be named as
20//! `FnOnceCallWithArgsTupleExt`, `FnMutCallWithArgsTupleExt`, `FnCallWithArgsTupleExt`
21//! by convention, because they are implemented for
22//! all corresponding `FnOnce`, `FnMut`, `Fn` types and act like extension traits.
23//! They are named as `TupleFn*` just for simplicity.
24
25pub trait KnownFnPointer: TupleFn<Self::ArgsTuple> {
26    /// The type of arguments tuple of this `fn` pointer.
27    /// For example, the following types in each pair are equivalent.
28    ///
29    /// ```
30    /// # trait TupleSameType {} impl<T> TupleSameType for (T, T) {}
31    /// # enum SameType<T1, T2> where (T1, T2): TupleSameType { Yes, T1(T1), T2(T2) }
32    /// # use tuple_fn::KnownFnPointer;
33    /// # SameType::<
34    ///     <fn() -> String as KnownFnPointer>::ArgsTuple
35    /// #     ,
36    ///     ()
37    /// # >::Yes;
38    ///
39    /// # SameType::<
40    ///     <fn(i32) -> String as KnownFnPointer>::ArgsTuple
41    /// #     ,
42    ///     (i32,)
43    /// # >::Yes;
44    ///
45    /// # SameType::<
46    ///     <fn(i32, bool) -> String as KnownFnPointer>::ArgsTuple
47    /// #     ,
48    ///     (i32, bool)
49    /// # >::Yes;
50    /// ```
51    type ArgsTuple;
52
53    /// The type of the `fn` pointer which accepts corresponding references of arguments.
54    /// For example, the following types in each pair are equivalent.
55    ///
56    /// ```
57    /// # trait TupleSameType {} impl<T> TupleSameType for (T, T) {}
58    /// # enum SameType<T1, T2> where (T1, T2): TupleSameType { Yes, T1(T1), T2(T2) }
59    /// # use tuple_fn::KnownFnPointer;
60    /// # SameType::<
61    ///     <fn() -> String as KnownFnPointer>::FnPointerWithRefArgs
62    /// #     ,
63    ///     fn() -> String
64    /// # >::Yes;
65    ///
66    /// # SameType::<
67    ///     <fn(i32) -> String as KnownFnPointer>::FnPointerWithRefArgs
68    /// #     ,
69    ///     fn(&i32) -> String
70    /// # >::Yes;
71    ///
72    /// # SameType::<
73    ///     <fn(i32, bool) -> String as KnownFnPointer>::FnPointerWithRefArgs
74    /// #     ,
75    ///     fn(&i32, &bool) -> String
76    /// # >::Yes;
77    /// ```
78    type FnPointerWithRefArgs;
79
80    /// The corresponding `dyn FnOnce` type.
81    /// For example, the following types in each pair are equivalent.
82    ///
83    /// ```
84    /// # trait TupleSameType {} impl<T: ?Sized> TupleSameType for (*const T, *const T) {}
85    /// # enum SameType<T1: ?Sized, T2: ?Sized> where (*const T1, *const T2): TupleSameType { Yes, T1(*const T1), T2(*const T2) }
86    /// # use tuple_fn::KnownFnPointer;
87    /// # SameType::<
88    ///     <fn() -> String as KnownFnPointer>::DynFnOnce
89    /// #     ,
90    ///     dyn FnOnce() -> String
91    /// # >::Yes;
92    ///
93    /// # SameType::<
94    ///     <fn(i32) -> String as KnownFnPointer>::DynFnOnce
95    /// #     ,
96    ///     dyn FnOnce(i32) -> String
97    /// # >::Yes;
98    ///
99    /// # SameType::<
100    ///     <fn(i32, bool) -> String as KnownFnPointer>::DynFnOnce
101    /// #     ,
102    ///     dyn FnOnce(i32, bool) -> String
103    /// # >::Yes;
104    /// ```
105    type DynFnOnce: ?Sized;
106
107    /// The corresponding `dyn DynFnMut` type.
108    /// For example, the following types in each pair are equivalent.
109    ///
110    /// ```
111    /// # trait TupleSameType {} impl<T: ?Sized> TupleSameType for (*const T, *const T) {}
112    /// # enum SameType<T1: ?Sized, T2: ?Sized> where (*const T1, *const T2): TupleSameType { Yes, T1(*const T1), T2(*const T2) }
113    /// # use tuple_fn::KnownFnPointer;
114    /// # SameType::<
115    ///     <fn() -> String as KnownFnPointer>::DynFnMut
116    /// #     ,
117    ///     dyn FnMut() -> String
118    /// # >::Yes;
119    ///
120    /// # SameType::<
121    ///     <fn(i32) -> String as KnownFnPointer>::DynFnMut
122    /// #     ,
123    ///     dyn FnMut(i32) -> String
124    /// # >::Yes;
125    ///
126    /// # SameType::<
127    ///     <fn(i32, bool) -> String as KnownFnPointer>::DynFnMut
128    /// #     ,
129    ///     dyn FnMut(i32, bool) -> String
130    /// # >::Yes;
131    /// ```
132    type DynFnMut: ?Sized;
133
134    /// The corresponding `dyn DynFn` type.
135    /// For example, the following types in each pair are equivalent.
136    ///
137    /// ```
138    /// # trait TupleSameType {} impl<T: ?Sized> TupleSameType for (*const T, *const T) {}
139    /// # enum SameType<T1: ?Sized, T2: ?Sized> where (*const T1, *const T2): TupleSameType { Yes, T1(*const T1), T2(*const T2) }
140    /// # use tuple_fn::KnownFnPointer;
141    /// # SameType::<
142    ///     <fn() -> String as KnownFnPointer>::DynFn
143    /// #     ,
144    ///     dyn Fn() -> String
145    /// # >::Yes;
146    ///
147    /// # SameType::<
148    ///     <fn(i32) -> String as KnownFnPointer>::DynFn
149    /// #     ,
150    ///     dyn Fn(i32) -> String
151    /// # >::Yes;
152    ///
153    /// # SameType::<
154    ///     <fn(i32, bool) -> String as KnownFnPointer>::DynFn
155    /// #     ,
156    ///     dyn Fn(i32, bool) -> String
157    /// # >::Yes;
158    /// ```
159    type DynFn: ?Sized;
160}
161
162pub trait KnownTuple<'a> {
163    /// The corresponding tuple type which references each item.
164    ///
165    /// ```
166    /// use tuple_fn::KnownTuple;
167    ///
168    /// let _: <() as KnownTuple>::RefTuple = ();
169    /// let _: <(i32,) as KnownTuple>::RefTuple = (&1,);
170    /// let _: <(i32, bool) as KnownTuple>::RefTuple = (&1, &true);
171    /// let _: <(i32, bool, &u8) as KnownTuple>::RefTuple = (&1, &true, &&0u8);
172    /// ```
173    type RefTuple: 'a + KnownTuple<'a>;
174
175    /// The `fn` pointer type which accepts this tuple as arguments and returns `()`.
176    /// For example, the following types in each pair are equivalent.
177    ///
178    /// ```
179    /// # trait TupleSameType {} impl<T> TupleSameType for (T, T) {}
180    /// # enum SameType<T1, T2> where (T1, T2): TupleSameType { Yes, T1(T1), T2(T2) }
181    /// # use tuple_fn::KnownTuple;
182    /// # SameType::<
183    /// <() as KnownTuple>::FnPointer, fn()
184    /// # >::Yes;
185    /// # SameType::<
186    /// <(i32,) as KnownTuple>::FnPointer, fn(i32)
187    /// # >::Yes;
188    /// # SameType::<
189    /// <(i32, bool) as KnownTuple>::FnPointer, fn(i32, bool)
190    /// # >::Yes;
191    /// ```
192    type FnPointer: KnownFnPointer<ArgsTuple = Self>;
193
194    /// Convert ref of tuple to tuple of refs.
195    ///
196    /// ```
197    /// # use tuple_fn::KnownTuple;
198    /// let _: (&i8, &String) = (1, "hello".to_string()).as_tuple_of_refs();
199    /// ```
200    fn as_tuple_of_refs(&'a self) -> Self::RefTuple;
201}
202
203/// Enables the types which implements [`FnOnce`] to be called with arguments tuple.
204///
205/// ```
206/// use tuple_fn::TupleFnOnce;
207///
208/// let start = "hello".to_string();
209///
210/// let closure = move |s1, s2| {
211///     let mut start = start;
212///     start.push_str(" ");
213///     start.push_str(s1);
214///     start.push_str(" ");
215///     start.push_str(s2);
216///     start
217/// };
218///
219/// let result = closure.call_once_with_args_tuple(("world", "!"));
220///
221/// assert_eq!(result, "hello world !");
222/// ```
223pub trait TupleFnOnce<Args> {
224    type TupleFnOutput;
225
226    fn call_once_with_args_tuple(self, args: Args) -> Self::TupleFnOutput;
227}
228
229/// Enables the types which implements [`FnMut`] to be called with arguments tuple.
230///
231/// ```
232/// use tuple_fn::TupleFnMut;
233///
234/// let mut result = vec![1, 2];
235///
236/// let mut closure = |value, prepend| {
237///     if prepend {
238///         result.insert(0, value);
239///     } else {
240///         result.push(value);
241///     }
242/// };
243///
244/// closure(0, true);
245/// closure(3, false);
246///
247/// assert_eq!(result, [0, 1, 2, 3]);
248/// ```
249pub trait TupleFnMut<Args>: TupleFnOnce<Args> {
250    fn call_mut_with_args_tuple(&mut self, args: Args) -> Self::TupleFnOutput;
251}
252
253/// Enables the types which implements [`Fn`] to be called with arguments tuple.
254///
255/// ```
256/// use tuple_fn::TupleFn;
257///
258/// let start = "hello".to_string();
259///
260/// let closure = move |s1, s2| {
261///     format!("{} {} {}", start, s1, s2)
262/// };
263///
264/// let result = closure.call_with_args_tuple(("world", "!"));
265///
266/// assert_eq!(result, "hello world !");
267///
268/// let result = closure.call_with_args_tuple(("to", "everyone!"));
269///
270/// assert_eq!(result, "hello to everyone!");
271/// ```
272pub trait TupleFn<Args>: TupleFnMut<Args> {
273    fn call_with_args_tuple(&self, args: Args) -> Self::TupleFnOutput;
274}
275
276macro_rules! impl_for_tuples {
277    ($( ( $($t:ident,)* ) )+) => {
278        $(
279            impl<R, $($t,)*> KnownFnPointer for fn($($t,)*) -> R {
280                type ArgsTuple = ($($t,)*);
281
282                type FnPointerWithRefArgs = fn($(&$t,)*) -> R;
283
284                type DynFnOnce = dyn FnOnce($($t,)*) -> R;
285                type DynFnMut = dyn FnMut($($t,)*) -> R;
286                type DynFn = dyn Fn($($t,)*) -> R;
287            }
288
289            impl<'a, $($t: 'a,)*> KnownTuple<'a> for ($($t,)*) {
290                type RefTuple = ($(&'a $t,)*);
291                type FnPointer = fn($($t,)*);
292
293                fn as_tuple_of_refs(&'a self) -> Self::RefTuple {
294                    #[allow(non_snake_case)]
295                    let ($($t,)*) = self;
296                    ($($t,)*)
297                }
298            }
299
300            impl<R, T: FnOnce( $($t,)* ) -> R, $($t,)*> TupleFnOnce<($($t,)*)> for T {
301                type TupleFnOutput = R;
302
303                fn call_once_with_args_tuple(self, #[allow(non_snake_case)] ($($t,)*): ($($t,)*)) -> Self::TupleFnOutput {
304                    self($($t,)*)
305                }
306            }
307
308            impl<R, T: FnMut( $($t,)* ) -> R, $($t,)*> TupleFnMut<($($t,)*)> for T {
309                fn call_mut_with_args_tuple(&mut self, #[allow(non_snake_case)] ($($t,)*): ($($t,)*)) -> R {
310                    self($($t,)*)
311                }
312            }
313
314            impl<R, T: Fn( $($t,)* ) -> R, $($t,)*> TupleFn<($($t,)*)> for T {
315                fn call_with_args_tuple(&self, #[allow(non_snake_case)] ($($t,)*): ($($t,)*)) -> R {
316                    self($($t,)*)
317                }
318            }
319        )+
320    };
321}
322
323impl_for_tuples! {
324    ()
325    (A1,)
326    (A1,A2,)
327    (A1,A2,A3,)
328    (A1,A2,A3,A4,)
329    (A1,A2,A3,A4,A5,)
330    (A1,A2,A3,A4,A5,A6,)
331    (A1,A2,A3,A4,A5,A6,A7,)
332    (A1,A2,A3,A4,A5,A6,A7,A8,)
333    (A1,A2,A3,A4,A5,A6,A7,A8,A9,)
334    (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,)
335    (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,)
336    (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,)
337    (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,)
338    (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,)
339    (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,)
340}
341
342#[cfg(test)]
343mod tests {
344    use super::*;
345
346    #[test]
347    fn it_works() {
348        fn call_fn_once<F: TupleFnOnce<Args>, Args>(func: F, args: Args) -> F::TupleFnOutput {
349            func.call_once_with_args_tuple(args)
350        }
351
352        assert_eq!(call_fn_once(|| 1, ()), 1);
353        assert_eq!(call_fn_once(|v| v, (2,)), 2);
354        assert_eq!(call_fn_once(|a, b| a + b, (3, 4)), 7);
355        assert_eq!(call_fn_once(|a, b, c| (a + b) > c, (5, 6, 8)), true);
356        assert_eq!(
357            call_fn_once(|a, b, c, d| (a + b) > (c + d), (1, 2, 3, 4)),
358            false
359        );
360
361        struct Four;
362
363        impl std::fmt::Display for Four {
364            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
365                write!(f, "4")
366            }
367        }
368
369        assert_eq!(
370            call_fn_once(
371                |a, b, c, d, e| format!("{}-{}-{}-{}-{}", a, b, c, d, e),
372                ("1", 2, 3u8, Four, "5".to_string())
373            ),
374            "1-2-3-4-5"
375        );
376
377        assert_eq!(
378            call_fn_once(
379                |a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15| format!(
380                    "{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}",
381                    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15
382                ),
383                (
384                    "1",
385                    2,
386                    3u8,
387                    Four,
388                    "5".to_string(),
389                    std::borrow::Cow::Borrowed("6"),
390                    7u32,
391                    8,
392                    7,
393                    6,
394                    5,
395                    4,
396                    3,
397                    2,
398                    1,
399                )
400            ),
401            "1-2-3-4-5-6-7-8-7-6-5-4-3-2-1"
402        );
403
404        assert_eq!(
405            (call_fn_once::<_, (&str,)>).call_with_args_tuple((|v| v, ("hello",))),
406            "hello"
407        );
408        assert_eq!(
409            call_fn_once.call_with_args_tuple((|v| v, ("world",))),
410            "world"
411        );
412    }
413
414    #[test]
415    fn ref_args_works() {
416        fn call_fn_with_ref_args<'a, Args: 'a + KnownTuple<'a>, F: TupleFnOnce<Args::RefTuple>>(
417            func: F,
418            args: &'a Args,
419        ) -> F::TupleFnOutput {
420            func.call_once_with_args_tuple(args.as_tuple_of_refs())
421        }
422
423        assert_eq!(call_fn_with_ref_args(|| 1, &()), 1);
424        assert_eq!(call_fn_with_ref_args(|v| v, &(2,)), &2);
425        assert_eq!(call_fn_with_ref_args(|v| v + 1, &(2,)), 3);
426        assert_eq!(
427            call_fn_with_ref_args(
428                |v, add: &bool| if *add { v + 1 } else { v - 1 },
429                &(5, false)
430            ),
431            4
432        );
433    }
434}