1use std::sync::{Arc, Mutex};
2
3#[derive(Clone)]
4pub struct Store<S, A>
5where
6 S: Clone,
7 A: Clone,
8{
9 state: Arc<Mutex<S>>,
10 reducer: fn(&S, &A) -> S,
11 subscribers: Arc<Mutex<Vec<Box<dyn Fn(&S) + Send + Sync>>>>,
12 middlewares: Vec<Arc<dyn Fn(&Store<S, A>, &A, &dyn Fn(&A)) + Send + Sync>>,
13}
14
15impl<S, A> Store<S, A>
16where
17 S: Clone + Send + Sync + 'static,
18 A: Clone + Send + Sync + 'static,
19{
20 pub fn new(reducer: fn(&S, &A) -> S, initial_state: S) -> Self {
21 Store {
22 state: Arc::new(Mutex::new(initial_state)),
23 reducer,
24 subscribers: Arc::new(Mutex::new(Vec::new())),
25 middlewares: Vec::new(),
26 }
27 }
28
29 pub fn add_middleware(&mut self, middleware: Arc<dyn Fn(&Store<S, A>, &A, &dyn Fn(&A)) + Send + Sync>) {
30 self.middlewares.push(middleware);
31 }
32
33 pub fn dispatch(&self, action: &A) {
34 let base_dispatch = |action: &A| {
35 let mut state = self.state.lock().unwrap();
36 *state = (self.reducer)(&state, action);
37 self.notify_subscribers(&state);
38 };
39
40 let dispatch = self.middlewares.iter().rev().fold(
41 Box::new(base_dispatch) as Box<dyn Fn(&A)>,
42 |next, middleware| {
43 Box::new(move |action: &A| {
44 middleware(self, action, &|a| next(a));
45 }) as Box<dyn Fn(&A)>
46 },
47 );
48
49 dispatch(action);
50 }
51
52 pub fn subscribe<F>(&self, listener: F)
53 where
54 F: Fn(&S) + 'static + Send + Sync,
55 {
56 let mut subscribers = self.subscribers.lock().unwrap();
57 subscribers.push(Box::new(listener));
58 }
59
60 fn notify_subscribers(&self, state: &S) {
61 let subscribers = self.subscribers.lock().unwrap();
62 for listener in subscribers.iter() {
63 listener(state);
64 }
65 }
66
67 pub fn get_state(&self) -> S {
68 self.state.lock().unwrap().clone()
69 }
70
71 pub fn with_middleware(mut self, middlewares: Vec<Arc<dyn Fn(&Store<S, A>, &A, &dyn Fn(&A)) + Send + Sync>>) -> Self {
72 self.middlewares = middlewares;
73 self
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[derive(Clone, PartialEq, Debug)]
82 struct TestState {
83 pub counter: i32,
84 }
85
86 #[derive(Clone, Debug)]
87 enum TestAction {
88 Increment,
89 Decrement,
90 }
91
92 fn test_reducer(state: &TestState, action: &TestAction) -> TestState {
93 match action {
94 TestAction::Increment => TestState {
95 counter: state.counter + 1,
96 },
97 TestAction::Decrement => TestState {
98 counter: state.counter - 1,
99 },
100 }
101 }
102
103 fn logger_middleware<S, A>(
104 store: &Store<S, A>,
105 action: &A,
106 next: &dyn Fn(&A),
107 ) where
108 S: Clone + Send + Sync + 'static + std::fmt::Debug,
109 A: Clone + Send + Sync + 'static + std::fmt::Debug,
110 {
111 println!("Dispatching action: {:?}", action);
112 next(action);
113 println!("New state: {:?}", store.get_state());
114 }
115
116 #[test]
117 fn test_store() {
118 let initial_state = TestState { counter: 0 };
119 let store = Store::new(test_reducer as fn(&TestState, &TestAction) -> TestState, initial_state)
120 .with_middleware(vec![Arc::new(logger_middleware)]);
121
122 store.dispatch(&TestAction::Increment);
123 assert_eq!(store.get_state().counter, 1);
124
125 store.dispatch(&TestAction::Decrement);
126 assert_eq!(store.get_state().counter, 0);
127 }
128
129 #[test]
130 fn test_subscribe() {
131 let initial_state = TestState { counter: 0 };
132 let store = Store::new(test_reducer as fn(&TestState, &TestAction) -> TestState, initial_state)
133 .with_middleware(vec![Arc::new(logger_middleware)]);
134
135 let observed_states = Arc::new(Mutex::new(Vec::new()));
136 let observed_states_clone = Arc::clone(&observed_states);
137 store.subscribe(move |state: &TestState| {
138 let mut states = observed_states_clone.lock().unwrap();
139 states.push(state.counter);
140 });
141
142 store.dispatch(&TestAction::Increment);
143 store.dispatch(&TestAction::Increment);
144 store.dispatch(&TestAction::Decrement);
145
146 let observed_states = observed_states.lock().unwrap();
147 assert_eq!(*observed_states, vec![1, 2, 1]);
148 }
149}