1use crate::Action;
4use std::marker::PhantomData;
5
6pub type Reducer<S, A> = fn(&mut S, A) -> bool;
10
11pub struct Store<S, A: Action> {
51 state: S,
52 reducer: Reducer<S, A>,
53 _marker: PhantomData<A>,
54}
55
56impl<S, A: Action> Store<S, A> {
57 pub fn new(state: S, reducer: Reducer<S, A>) -> Self {
59 Self {
60 state,
61 reducer,
62 _marker: PhantomData,
63 }
64 }
65
66 pub fn dispatch(&mut self, action: A) -> bool {
71 (self.reducer)(&mut self.state, action)
72 }
73
74 pub fn state(&self) -> &S {
76 &self.state
77 }
78
79 pub fn state_mut(&mut self) -> &mut S {
85 &mut self.state
86 }
87}
88
89pub struct StoreWithMiddleware<S, A: Action, M: Middleware<A>> {
94 store: Store<S, A>,
95 middleware: M,
96}
97
98impl<S, A: Action, M: Middleware<A>> StoreWithMiddleware<S, A, M> {
99 pub fn new(state: S, reducer: Reducer<S, A>, middleware: M) -> Self {
101 Self {
102 store: Store::new(state, reducer),
103 middleware,
104 }
105 }
106
107 pub fn dispatch(&mut self, action: A) -> bool {
109 self.middleware.before(&action);
110 let changed = self.store.dispatch(action.clone());
111 self.middleware.after(&action, changed);
112 changed
113 }
114
115 pub fn state(&self) -> &S {
117 self.store.state()
118 }
119
120 pub fn state_mut(&mut self) -> &mut S {
122 self.store.state_mut()
123 }
124
125 pub fn middleware(&self) -> &M {
127 &self.middleware
128 }
129
130 pub fn middleware_mut(&mut self) -> &mut M {
132 &mut self.middleware
133 }
134}
135
136pub trait Middleware<A: Action> {
141 fn before(&mut self, action: &A);
143
144 fn after(&mut self, action: &A, state_changed: bool);
146}
147
148#[derive(Debug, Clone, Copy, Default)]
150pub struct NoopMiddleware;
151
152impl<A: Action> Middleware<A> for NoopMiddleware {
153 fn before(&mut self, _action: &A) {}
154 fn after(&mut self, _action: &A, _state_changed: bool) {}
155}
156
157#[derive(Debug, Clone, Default)]
159pub struct LoggingMiddleware {
160 pub log_before: bool,
162 pub log_after: bool,
164}
165
166impl LoggingMiddleware {
167 pub fn new() -> Self {
169 Self {
170 log_before: false,
171 log_after: true,
172 }
173 }
174
175 pub fn verbose() -> Self {
177 Self {
178 log_before: true,
179 log_after: true,
180 }
181 }
182}
183
184impl<A: Action> Middleware<A> for LoggingMiddleware {
185 fn before(&mut self, action: &A) {
186 if self.log_before {
187 tracing::debug!(action = %action.name(), "Dispatching action");
188 }
189 }
190
191 fn after(&mut self, action: &A, state_changed: bool) {
192 if self.log_after {
193 tracing::debug!(
194 action = %action.name(),
195 state_changed = state_changed,
196 "Action processed"
197 );
198 }
199 }
200}
201
202pub struct ComposedMiddleware<A: Action> {
204 middlewares: Vec<Box<dyn Middleware<A>>>,
205}
206
207impl<A: Action> std::fmt::Debug for ComposedMiddleware<A> {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 f.debug_struct("ComposedMiddleware")
210 .field("middlewares_count", &self.middlewares.len())
211 .finish()
212 }
213}
214
215impl<A: Action> Default for ComposedMiddleware<A> {
216 fn default() -> Self {
217 Self::new()
218 }
219}
220
221impl<A: Action> ComposedMiddleware<A> {
222 pub fn new() -> Self {
224 Self {
225 middlewares: Vec::new(),
226 }
227 }
228
229 pub fn add<M: Middleware<A> + 'static>(&mut self, middleware: M) {
231 self.middlewares.push(Box::new(middleware));
232 }
233}
234
235impl<A: Action> Middleware<A> for ComposedMiddleware<A> {
236 fn before(&mut self, action: &A) {
237 for middleware in &mut self.middlewares {
238 middleware.before(action);
239 }
240 }
241
242 fn after(&mut self, action: &A, state_changed: bool) {
243 for middleware in self.middlewares.iter_mut().rev() {
245 middleware.after(action, state_changed);
246 }
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253
254 #[derive(Default)]
255 struct TestState {
256 counter: i32,
257 }
258
259 #[derive(Clone, Debug)]
260 enum TestAction {
261 Increment,
262 Decrement,
263 NoOp,
264 }
265
266 impl Action for TestAction {
267 fn name(&self) -> &'static str {
268 match self {
269 TestAction::Increment => "Increment",
270 TestAction::Decrement => "Decrement",
271 TestAction::NoOp => "NoOp",
272 }
273 }
274 }
275
276 fn test_reducer(state: &mut TestState, action: TestAction) -> bool {
277 match action {
278 TestAction::Increment => {
279 state.counter += 1;
280 true
281 }
282 TestAction::Decrement => {
283 state.counter -= 1;
284 true
285 }
286 TestAction::NoOp => false,
287 }
288 }
289
290 #[test]
291 fn test_store_dispatch() {
292 let mut store = Store::new(TestState::default(), test_reducer);
293
294 assert!(store.dispatch(TestAction::Increment));
295 assert_eq!(store.state().counter, 1);
296
297 assert!(store.dispatch(TestAction::Increment));
298 assert_eq!(store.state().counter, 2);
299
300 assert!(store.dispatch(TestAction::Decrement));
301 assert_eq!(store.state().counter, 1);
302 }
303
304 #[test]
305 fn test_store_noop() {
306 let mut store = Store::new(TestState::default(), test_reducer);
307
308 assert!(!store.dispatch(TestAction::NoOp));
309 assert_eq!(store.state().counter, 0);
310 }
311
312 #[test]
313 fn test_store_state_mut() {
314 let mut store = Store::new(TestState::default(), test_reducer);
315
316 store.state_mut().counter = 100;
317 assert_eq!(store.state().counter, 100);
318 }
319
320 #[derive(Default)]
321 struct CountingMiddleware {
322 before_count: usize,
323 after_count: usize,
324 }
325
326 impl<A: Action> Middleware<A> for CountingMiddleware {
327 fn before(&mut self, _action: &A) {
328 self.before_count += 1;
329 }
330
331 fn after(&mut self, _action: &A, _state_changed: bool) {
332 self.after_count += 1;
333 }
334 }
335
336 #[test]
337 fn test_store_with_middleware() {
338 let mut store = StoreWithMiddleware::new(
339 TestState::default(),
340 test_reducer,
341 CountingMiddleware::default(),
342 );
343
344 store.dispatch(TestAction::Increment);
345 store.dispatch(TestAction::Increment);
346
347 assert_eq!(store.middleware().before_count, 2);
348 assert_eq!(store.middleware().after_count, 2);
349 assert_eq!(store.state().counter, 2);
350 }
351}