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}