gstore 0.10.4

Global and local state management in redux style for applications written in Rust
Documentation
// SPDX-License-Identifier: GPL-3.0-or-later

use gstore::{self, Actionable, Keybinding};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct State {
    current_page: String,
    page_history: Vec<String>,
    selection: (u32, u32),
}

impl Default for State {
    fn default() -> Self {
        Self {
            current_page: "home".to_string(),
            page_history: vec![],
            selection: Default::default(),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Action {
    A,
    B,
    C,
}

impl Actionable for Action {
    fn list() -> Vec<Self> {
        vec![Action::A, Action::B, Action::C]
    }
    fn try_from_name(name: &str) -> Option<Self> {
        match name {
            "a" => Some(Action::A),
            "b" => Some(Action::B),
            "c" => Some(Action::C),
            _ => None,
        }
    }
    fn keybinding(&self) -> Option<Keybinding> {
        None
    }

    fn name(&self) -> &'static str {
        match self {
            Action::A => "a",
            Action::B => "b",
            Action::C => "c",
        }
    }
}

mod dispatch_during_reduce_works_but_is_not_smart {
    use std::sync::mpsc::sync_channel;

    use super::*;

    gstore::store!(Action, State);

    #[test]
    fn test() {
        env_logger::try_init().ok();

        let (s, r) = sync_channel(100);
        let reduce = store().init(
            |a, _| {
                println!("Reduce: {:?}", a);
                if a == &Action::A {
                    store().dispatch(Action::C);
                    store().dispatch(Action::B);
                    store().dispatch(Action::B);
                    store().dispatch(Action::C);
                    store().dispatch(Action::C);
                }
            },
            move |a| {
                s.send(a).expect("Failed to send");
            },
        );
        std::thread::spawn(|| {
            for _ in 0..5 {
                store().dispatch(Action::A);
                std::thread::sleep(std::time::Duration::from_millis(10));
                store().dispatch(Action::B);
                std::thread::sleep(std::time::Duration::from_millis(10));
            }
        });
        println!("waiting for actions");

        const EXPECTED: u32 = 35;
        let mut actions = Vec::new();
        for _ in 0..EXPECTED {
            if let Ok(a) = r.recv_timeout(std::time::Duration::from_secs(1)) {
                actions.push(a.name());
                reduce(a);
            } else {
                assert!(false, "Test ran into timeout");
            }
        }

        assert_eq!(
            actions.join(""),
            "a cbbcc ba cbbcc ba cbbcc ba cbbcc ba cbbcc b".replace(" ", "")
        )
    }
}