sovran_example/
sovran_example.rs

1use sovran_state::{Store, State, Action};
2use std::sync::Arc;
3use std::thread;
4use std::time::Duration;
5
6// Define our state
7#[derive(Clone, Debug)]
8struct BankState {
9    balance: f64,
10    transaction_count: u32,
11}
12
13impl State for BankState {}
14
15// Define our actions
16struct DepositAction(f64);
17struct WithdrawAction(f64);
18
19impl Action<BankState> for DepositAction {
20    fn reduce(&self, state: BankState) -> BankState {
21        BankState {
22            balance: state.balance + self.0,
23            transaction_count: state.transaction_count + 1,
24        }
25    }
26}
27
28impl Action<BankState> for WithdrawAction {
29    fn reduce(&self, state: BankState) -> BankState {
30        BankState {
31            balance: state.balance - self.0,
32            transaction_count: state.transaction_count + 1,
33        }
34    }
35}
36
37// Define some example components that use the state
38struct AccountMonitor {
39    store: Arc<Store>,
40}
41
42struct TransactionLogger {
43    store: Arc<Store>,
44}
45
46impl AccountMonitor {
47    fn new(store: Arc<Store>) -> Self {
48        let monitor = AccountMonitor { store: store.clone() };
49
50        // Subscribe to state changes
51        monitor.store.subscribe(move |state: &BankState| {
52            println!("🏦 Account Monitor: Balance changed to ${:.2}", state.balance);
53        }).expect("Failed to subscribe to state changes");
54
55        monitor
56    }
57
58    fn check_balance(&self) -> f64 {
59        self.store.get_state::<BankState>()
60            .map(|state| state.balance)
61            .unwrap_or(0.0)
62    }
63}
64
65impl TransactionLogger {
66    fn new(store: Arc<Store>) -> Self {
67        let logger = TransactionLogger { store: store.clone() };
68
69        // Subscribe to state changes
70        logger.store.subscribe(move |state: &BankState| {
71            println!("📝 Transaction Logger: Transaction #{} processed",
72                     state.transaction_count);
73        }).expect("Failed to subscribe to state changes");
74
75        logger
76    }
77}
78
79fn main() {
80    // Create store and provide initial state
81    let store = Arc::new(Store::new());
82    store.provide(BankState {
83        balance: 1000.0,
84        transaction_count: 0,
85    }).expect("Failed to provide initial state");
86
87    // Create our components
88    let monitor = AccountMonitor::new(store.clone());
89    let _logger = TransactionLogger::new(store.clone());
90
91    println!("Initial balance: ${:.2}", monitor.check_balance());
92
93    // Simulate some transactions
94    println!("\nProcessing transactions...\n");
95
96    // Deposit
97    store.dispatch(DepositAction(500.0))
98        .expect("Failed to process deposit");
99    thread::sleep(Duration::from_millis(500));
100
101    // Withdraw
102    store.dispatch(WithdrawAction(200.0))
103        .expect("Failed to process withdrawal");
104    thread::sleep(Duration::from_millis(500));
105
106    // Deposit again
107    store.dispatch(DepositAction(750.0))
108        .expect("Failed to process deposit");
109    thread::sleep(Duration::from_millis(500));
110
111    println!("\nFinal balance: ${:.2}", monitor.check_balance());
112}