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