1pub fn concat_fn<A>(fs: Vec<Box<dyn Fn(A) -> A>>) -> impl Fn(A) -> A {
3 move |mut a: A| {
4 for f in &fs {
5 a = f(a);
6 }
7 a
8 }
9}
10
11pub fn concat_fn_result<A, E>(
13 fs: Vec<Box<dyn Fn(A) -> Result<A, E>>>,
14) -> impl Fn(A) -> Result<A, E> {
15 move |mut a: A| {
16 for f in &fs {
17 a = f(a)?;
18 }
19 Ok(a)
20 }
21}
22
23pub fn concat_mut<A>(mut fs: Vec<Box<dyn FnMut(&mut A)>>) -> impl FnMut(&mut A) {
25 move |a: &mut A| {
26 for f in &mut fs {
27 f(a);
28 }
29 }
30}
31
32pub fn concat_mut_result<A, E>(
34 mut fs: Vec<Box<dyn FnMut(&mut A) -> Result<(), E>>>,
35) -> impl FnMut(&mut A) -> Result<(), E> {
36 move |a: &mut A| {
37 for f in &mut fs {
38 f(a)?;
39 }
40 Ok(())
41 }
42}
43
44#[macro_export]
47macro_rules! concat_fn {
48 ($($f:expr),+ $(,)?) => {{
49 let funcs: Vec<Box<dyn Fn(_) -> _>> = vec![$(Box::new($f)),+];
50 concat_fn(funcs)
51 }};
52}
53
54#[macro_export]
55macro_rules! concat_tryfn {
56 ($($f:expr),+ $(,)?) => {{
57 let funcs: Vec<Box<dyn Fn(_) -> Result<_, _>>> = vec![$(Box::new($f)),+];
58 concat_fn_result(funcs)
59 }};
60}
61
62#[macro_export]
63macro_rules! concat_mut_macro {
64 ($($f:expr),+ $(,)?) => {{
65 let funcs: Vec<Box<dyn FnMut(&mut _)>> = vec![$(Box::new($f)),+];
66 concat_mut(funcs)
67 }};
68}
69
70#[macro_export]
71macro_rules! concat_trymut {
72 ($($f:expr),+ $(,)?) => {{
73 let funcs: Vec<Box<dyn FnMut(&mut _) -> Result<(), _>>> = vec![$(Box::new($f)),+];
74 concat_mut_result(funcs)
75 }};
76}
77
78#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn test_concat_fn() {
85 let f = concat_fn!(|x: i32| x + 1, |x| x * 2, |x| x - 3);
86 assert_eq!(f(2), 3); }
88
89 #[test]
90 fn test_concat_tryfn() {
91 let f = concat_tryfn!(|x: i32| if x > 0 { Ok(x + 1) } else { Err("neg") }, |x| Ok(
92 x * 2
93 ));
94 assert_eq!(f(1), Ok(4));
95 assert_eq!(f(-1), Err("neg"));
96 }
97
98 #[test]
99 fn test_concat_mut() {
100 let mut f = concat_mut_macro!(|x: &mut i32| *x += 2, |x: &mut i32| *x *= 3);
101 let mut val = 1;
102 f(&mut val);
103 assert_eq!(val, 9);
104 }
105
106 #[test]
107 fn test_concat_trymut() {
108 let mut f = concat_trymut!(
109 |x: &mut i32| if *x > 0 {
110 *x += 1;
111 Ok(())
112 } else {
113 Err("bad")
114 },
115 |x: &mut i32| {
116 *x *= 2;
117 Ok(())
118 }
119 );
120 let mut val = 2;
121 assert_eq!(f(&mut val), Ok(()));
122 assert_eq!(val, 6);
123 let mut neg = -1;
124 assert_eq!(f(&mut neg), Err("bad"));
125 }
126}