reducer/reactor/
slice.rs

1use crate::reactor::*;
2
3/// Notifies all [`Reactor`]s in the slice in order.
4///
5/// # Example
6///
7/// ```rust
8/// use reducer::*;
9///
10/// struct State { /* ... */ }
11/// struct Action { /* ... */ }
12///
13/// impl Reducer<Action> for State {
14///     fn reduce(&mut self, action: Action) {
15///         // ...
16///     }
17/// }
18///
19/// struct Actor { /* ... */ }
20/// struct ActorError(/*...*/);
21///
22/// impl Reactor<State> for Actor {
23///     type Error = ActorError;
24///     fn react(&mut self, state: &State) -> Result<(), Self::Error> {
25///         // ...
26///         Ok(())
27///     }
28/// }
29///
30/// # #[cfg(feature = "alloc")] {
31/// let mut actors = vec![];
32///
33/// actors.push(Actor { /* ... */ });
34/// actors.push(Actor { /* ... */ });
35/// // ...
36/// actors.push(Actor { /* ... */ });
37///
38/// let mut store = Store::new(State { /* ... */ }, actors.into_boxed_slice());
39///
40/// // All actors get notified of state changes.
41/// store.dispatch(Action { /* ... */ });
42/// # }
43/// ```
44impl<S, T> Reactor<S> for [T]
45where
46    S: ?Sized,
47    T: Reactor<S>,
48{
49    type Error = T::Error;
50
51    fn react(&mut self, state: &S) -> Result<(), Self::Error> {
52        for reducer in self {
53            reducer.react(state)?;
54        }
55
56        Ok(())
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63    use mockall::predicate::*;
64    use std::vec::Vec;
65    use test_strategy::proptest;
66
67    #[proptest]
68    fn react(state: u8, results: Vec<Result<(), u8>>) {
69        let (idx, result) = results
70            .iter()
71            .enumerate()
72            .find(|(_, r)| r.is_err())
73            .map_or((results.len(), Ok(())), |(i, &r)| (i, r));
74
75        let mut mocks: Vec<_> = results
76            .into_iter()
77            .enumerate()
78            .map(move |(i, r)| {
79                let mut mock = MockReactor::new();
80
81                mock.expect_react()
82                    .with(eq(state))
83                    .times(if i > idx { 0 } else { 1 })
84                    .return_const(r);
85
86                mock
87            })
88            .collect();
89
90        let reactor = mocks.as_mut_slice();
91        assert_eq!(Reactor::react(reactor, &state), result);
92    }
93}