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}