calc_effect/
calc_effect.rs

1use std::sync::{Arc, Mutex};
2use std::thread;
3
4use rs_store::{DispatchOp, Dispatcher, Effect, EffectResult, StoreBuilder};
5use rs_store::{Reducer, Subscriber};
6
7#[derive(Debug, Clone)]
8enum CalcAction {
9    AddWillProduceThunk(i32),
10    SubtractWillProduceEffectFunction(i32),
11}
12
13struct CalcReducer {}
14
15impl Default for CalcReducer {
16    fn default() -> CalcReducer {
17        CalcReducer {}
18    }
19}
20
21#[derive(Debug, Clone)]
22struct CalcState {
23    count: i32,
24}
25
26impl Default for CalcState {
27    fn default() -> CalcState {
28        CalcState { count: 0 }
29    }
30}
31
32impl Reducer<CalcState, CalcAction> for CalcReducer {
33    fn reduce(&self, state: &CalcState, action: &CalcAction) -> DispatchOp<CalcState, CalcAction> {
34        match action {
35            CalcAction::AddWillProduceThunk(i) => {
36                println!("CalcReducer::reduce: + {}", i);
37                DispatchOp::Dispatch(
38                    CalcState {
39                        count: state.count + i,
40                    },
41                    Some(Effect::Thunk(subtract_effect_thunk(*i))),
42                )
43            }
44            CalcAction::SubtractWillProduceEffectFunction(i) => {
45                println!("CalcReducer::reduce: - {}", i);
46                DispatchOp::Dispatch(
47                    CalcState {
48                        count: state.count - i,
49                    },
50                    // produce effect function
51                    Some(Effect::Function(
52                        "subtract".to_string(),
53                        subtract_effect_fn(*i),
54                    )),
55                )
56            }
57        }
58    }
59}
60
61struct CalcSubscriber {
62    id: i32,
63    last: Mutex<CalcState>,
64}
65
66impl Default for CalcSubscriber {
67    fn default() -> Self {
68        Self {
69            id: 0,
70            last: Mutex::new(CalcState::default()),
71        }
72    }
73}
74
75impl Subscriber<CalcState, CalcAction> for CalcSubscriber {
76    fn on_notify(&self, state: &CalcState, action: &CalcAction) {
77        match action {
78            CalcAction::AddWillProduceThunk(_i) => {
79                println!(
80                    "CalcSubscriber::on_notify: id:{}, state: {:?} <- last: {:?} + action: {:?}",
81                    self.id,
82                    state,
83                    self.last.lock().unwrap(),
84                    action,
85                );
86            }
87            CalcAction::SubtractWillProduceEffectFunction(_i) => {
88                println!(
89                    "CalcSubscriber::on_notify: id:{}, state: {:?} <- last: {:?} + action: {:?}",
90                    self.id,
91                    state,
92                    self.last.lock().unwrap(),
93                    action,
94                );
95            }
96        }
97
98        *self.last.lock().unwrap() = state.clone();
99    }
100}
101
102fn subtract_effect_thunk(i: i32) -> Box<dyn FnOnce(Box<dyn Dispatcher<CalcAction>>) + Send> {
103    Box::new(move |dispatcher| {
104        println!("effect: working on long running task....");
105        thread::sleep(std::time::Duration::from_secs(1));
106
107        println!("effect: dispatching action...");
108        dispatcher
109            .dispatch(CalcAction::SubtractWillProduceEffectFunction(i))
110            .expect("no dispatch failed");
111    })
112}
113
114fn subtract_effect_fn(_i: i32) -> Box<dyn FnOnce() -> EffectResult + Send> {
115    Box::new(move || {
116        println!("effect: working on long running task again....");
117        thread::sleep(std::time::Duration::from_secs(1));
118
119        println!("effect: now returns result");
120        Ok(Box::new(CalcState { count: 0 }))
121    })
122}
123
124pub fn main() {
125    println!("Hello, Effect!");
126
127    let store =
128        StoreBuilder::new_with_reducer(CalcState::default(), Box::new(CalcReducer::default()))
129            .with_name("store-effect".into())
130            .build()
131            .unwrap();
132
133    store.add_subscriber(Arc::new(CalcSubscriber::default()));
134    let _ = store.dispatch(CalcAction::AddWillProduceThunk(1));
135
136    store.stop();
137}