fn_traits/
lib.rs

1#![no_std]
2
3//! Provides [`FnOnce`], [`FnMut`] and [`Fn`] traits like the standard library ones ([`FnOnce`](`ops::FnOnce`),
4//! [`FnMut`](`ops::FnMut`) and [`Fn`](`ops::Fn`)), but can be used in stable Rust.
5
6use core::ops;
7
8#[cfg(test)]
9extern crate std;
10
11pub mod fns;
12
13/// A function that can be called by value, like the standard library [`FnOnce`](`ops::FnOnce`) trait.
14pub trait FnOnce<Args> {
15    /// The return type of the function.
16    type Output;
17
18    /// Calls the function.
19    fn call_once(self, args: Args) -> Self::Output;
20}
21
22/// A function that can be called by mutable reference, like the standard library [`FnMut`](`ops::FnMut`) trait.
23pub trait FnMut<Args> {
24    /// The return type of the function.
25    type Output;
26
27    /// Calls the function.
28    fn call_mut(&mut self, args: Args) -> Self::Output;
29}
30
31/// A function that can be called by shared reference, like the standard library [`Fn`](`ops::Fn`) trait.
32pub trait Fn<Args> {
33    /// The return type of the function.
34    type Output;
35
36    /// Calls the function.
37    fn call(&self, args: Args) -> Self::Output;
38}
39
40macro_rules! impl_fn_traits {
41    ($(($types:ident, $fields:tt),)*) => {
42        impl_fn_traits!(@ [] [] $($types $fields)*);
43    };
44    (@ [$($types:ident)*] [$($fields:tt)*]) => {
45        #[automatically_derived]
46        impl<$($types,)* F, U> FnOnce<($($types,)*)> for F
47        where
48            F: ops::FnOnce($($types,)*) -> U,
49        {
50            type Output = U;
51
52            fn call_once(self, args: ($($types,)*)) -> Self::Output {
53                self($(args.$fields,)*)
54            }
55        }
56
57        #[automatically_derived]
58        impl<$($types,)* F, U> FnMut<($($types,)*)> for F
59        where
60            F: ops::FnMut($($types,)*) -> U + ?Sized,
61        {
62            type Output = U;
63
64            fn call_mut(&mut self, args: ($($types,)*)) -> Self::Output {
65                self($(args.$fields,)*)
66            }
67        }
68
69        #[automatically_derived]
70        impl<$($types,)* F, U> Fn<($($types,)*)> for F
71        where
72            F: ops::Fn($($types,)*) -> U + ?Sized,
73        {
74            type Output = U;
75
76            fn call(&self, args: ($($types,)*)) -> Self::Output {
77                self($(args.$fields,)*)
78            }
79        }
80    };
81    (@ [$($acc_types:ident)*] [$($acc_fields:tt)*] $type_0:ident $field_0:tt $($types:ident $fields:tt)*) => {
82        impl_fn_traits!(@ [$($acc_types)*] [$($acc_fields)*]);
83        impl_fn_traits!(@ [$($acc_types)* $type_0] [$($acc_fields)* $field_0] $($types $fields)*);
84    };
85}
86
87impl_fn_traits![
88    (T0, 0),
89    (T1, 1),
90    (T2, 2),
91    (T3, 3),
92    (T4, 4),
93    (T5, 5),
94    (T6, 6),
95    (T7, 7),
96    (T8, 8),
97    (T9, 9),
98    (T10, 10),
99    (T11, 11),
100    (T12, 12),
101    (T13, 13),
102    (T14, 14),
103    (T15, 15),
104    (T16, 16),
105    (T17, 17),
106    (T18, 18),
107    (T19, 19),
108    (T20, 20),
109    (T21, 21),
110    (T22, 22),
111    (T23, 23),
112    (T24, 24),
113    (T25, 25),
114    (T26, 26),
115    (T27, 27),
116    (T28, 28),
117    (T29, 29),
118    (T30, 30),
119    (T31, 31),
120];
121
122#[cfg(test)]
123mod tests {
124    use super::{Fn, FnMut, FnOnce};
125    use std::string::String;
126    use std::vec::Vec;
127
128    #[test]
129    fn test_fn_once() {
130        fn as_fn_once<T, U>(f: impl FnOnce<T, Output = U>) -> impl FnOnce<T, Output = U> {
131            f
132        }
133
134        assert_eq!(as_fn_once(String::into_bytes).call_once((String::from("abc"),)), b"abc");
135    }
136
137    #[test]
138    fn test_fn_mut() {
139        fn as_fn_mut<T, U>(f: impl FnMut<T, Output = U>) -> impl FnMut<T, Output = U> {
140            f
141        }
142
143        let mut values = Vec::new();
144
145        as_fn_mut(|x| values.push(x)).call_mut((4,));
146
147        assert_eq!(values, [4]);
148    }
149
150    #[test]
151    fn test_fn() {
152        fn as_fn<T, U>(f: impl Fn<T, Output = U>) -> impl Fn<T, Output = U> {
153            f
154        }
155
156        let s = String::from("abc");
157
158        assert_eq!(as_fn(String::as_str).call((&s,)), "abc");
159    }
160}