Skip to main content

fn_traits/fns/
compose_fn.rs

1use crate::{Fn, FnMut, FnOnce};
2
3/// A function object that is created by the [`compose`] function.
4#[derive(Clone, Copy, Default)]
5pub struct ComposeFn<F, G> {
6    lhs: F,
7    rhs: G,
8}
9
10impl<Args, F, G> FnOnce<Args> for ComposeFn<F, G>
11where
12    F: FnOnce<(G::Output,)>,
13    G: FnOnce<Args>,
14{
15    type Output = F::Output;
16
17    fn call_once(self, args: Args) -> Self::Output {
18        self.lhs.call_once((self.rhs.call_once(args),))
19    }
20}
21
22impl<Args, F, G> FnMut<Args> for ComposeFn<F, G>
23where
24    F: FnMut<(G::Output,)>,
25    G: FnMut<Args>,
26{
27    type Output = F::Output;
28
29    fn call_mut(&mut self, args: Args) -> Self::Output {
30        self.lhs.call_mut((self.rhs.call_mut(args),))
31    }
32}
33
34impl<Args, F, G> Fn<Args> for ComposeFn<F, G>
35where
36    F: Fn<(G::Output,)>,
37    G: Fn<Args>,
38{
39    type Output = F::Output;
40
41    fn call(&self, args: Args) -> Self::Output {
42        self.lhs.call((self.rhs.call(args),))
43    }
44}
45
46/// Combines `lhs` and `rhs` into a new function object. The new function will call `rhs` first, then passes the output
47/// into `lhs`, and returns the output of `lhs` as the final output.
48pub fn compose<F, G>(lhs: F, rhs: G) -> ComposeFn<F, G> {
49    ComposeFn { lhs, rhs }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::super::tests::{
55        into_std_fn, into_std_fn_2, into_std_fn_mut, into_std_fn_mut_2, into_std_fn_once, into_std_fn_once_2,
56    };
57    use super::ComposeFn;
58    use crate::fns::option_some_fn::OptionSomeFn;
59
60    #[test]
61    fn test_compose() {
62        let f = super::compose(|x: u32| x + 1, |x: u32| x * 2);
63
64        assert_eq!(into_std_fn_once(Clone::clone(&f))(2), 5);
65        assert_eq!(into_std_fn_mut(Clone::clone(&f))(2), 5);
66        assert_eq!(into_std_fn(Clone::clone(&f))(2), 5);
67
68        let g = super::compose(|x: u32| x + 1, |x: u32, y: u32| x * y);
69
70        assert_eq!(into_std_fn_once_2(Clone::clone(&g))(2, 3), 7);
71        assert_eq!(into_std_fn_mut_2(Clone::clone(&g))(2, 3), 7);
72        assert_eq!(into_std_fn_2(Clone::clone(&g))(2, 3), 7);
73    }
74
75    #[test]
76    fn test_compose_default() {
77        let f = ComposeFn::<OptionSomeFn, OptionSomeFn>::default();
78
79        assert_eq!(into_std_fn_once(Clone::clone(&f))(2), Some(Some(2)));
80        assert_eq!(into_std_fn_mut(Clone::clone(&f))(2), Some(Some(2)));
81        assert_eq!(into_std_fn(Clone::clone(&f))(2), Some(Some(2)));
82    }
83}