fnmutant/
lib.rs

1use core::marker::PhantomData;
2
3pub struct FnMutant<In, Extra, Out, F: for<'a> Fn(In, Extra) -> Out> {
4    pub f: F,
5    phantom_in: PhantomData<In>,
6    phantom_extra: PhantomData<Extra>,
7    phantom_out: PhantomData<Out>,
8}
9
10impl<In, Extra, Out, F: for<'a> Fn(In, Extra) -> Out> FnMutant<In, Extra, Out, F> {
11    pub fn new(f: F) -> Self {
12        Self {
13            f,
14            phantom_in: PhantomData,
15            phantom_extra: PhantomData,
16            phantom_out: PhantomData,
17        }
18    }
19}
20
21pub fn mutant<In, Extra, Out, F: for<'a> Fn(In, Extra) -> Out>(
22    f: F,
23) -> FnMutant<In, Extra, Out, F> {
24    FnMutant::new(f)
25}
26
27#[cfg(test)]
28mod tests {
29    use std::iter::FromIterator;
30    use crate::FnMutant;
31
32    fn incr(x: &mut i32, amount: i32) {
33        // Tried doing some thread_local stuff here, but couldn't get that to work (thankfully).
34        *x += amount
35    }
36
37    fn decr(x: &mut i32, amount: i32) {
38        *x -= amount
39    }
40
41
42    fn helper(fps: &[FnMutant<&mut i32, i32, (), &dyn for<'b> Fn(&mut i32, i32)>],
43              xs: &mut [i32], expect: Vec<i32>) {
44            let len = xs.len();
45            for i in 0..len * 5 {
46                for fp in fps {
47                    (fp.f)(xs.get_mut(i % len).unwrap(), 1);
48                }
49            }
50            assert_eq!(xs, expect.as_slice());
51    }
52
53    #[test]
54    fn it_works() {
55        use super::*;
56        let fps: [FnMutant<&mut i32, i32, (), &dyn for<'b> Fn(&mut i32, i32)>; 3] =
57            [mutant(&incr), mutant(&decr), mutant(&incr)];
58        {
59            let mut xs = [0, 1, 2, 3, 4, 5];
60            let expect = Vec::from_iter(xs.iter().map(|x| x + 5));
61            helper(&fps, &mut xs, expect.clone());
62            assert_eq!(xs, expect.as_slice());
63            drop(xs);
64        }
65        {
66            let mut xs = [0, 1, 2, 3, 4, 5];
67            let expect = Vec::from_iter(xs.iter().map(|x| x + 5));
68            helper(&fps, &mut xs, expect.clone());
69            assert_eq!(xs, expect.as_slice());
70            drop(xs);
71        }
72    }
73}