redux-rs 0.3.3

A Rust implementation of Redux.
Documentation
mod dispatch;
mod mailbox;
mod select;
mod subscribe;
mod work;

pub use dispatch::Dispatch;
pub use mailbox::{Address, Mailbox};
pub use select::Select;
pub use subscribe::Subscribe;
pub use work::Work;

use crate::{Reducer, Selector, Subscriber};
use async_trait::async_trait;
use work::HandleWork;

pub struct StateWorker<State, Action, RootReducer>
where
    State: Send,
    RootReducer: Send,
{
    mailbox: Mailbox<State, Action, RootReducer>,
    root_reducer: RootReducer,
    state: Option<State>,

    subscribers: Vec<Box<dyn Subscriber<State> + Send>>,
}

impl<State, Action, RootReducer> StateWorker<State, Action, RootReducer>
where
    RootReducer: Reducer<State, Action>,
    State: Send,
    RootReducer: Send,
{
    pub fn new(root_reducer: RootReducer, state: State) -> Self {
        Self {
            mailbox: Mailbox::new(),
            root_reducer,
            state: Some(state),

            subscribers: Default::default(),
        }
    }

    pub fn address(&self) -> Address<State, Action, RootReducer> {
        self.mailbox.address()
    }

    pub async fn run(&mut self) {
        while let Some(work) = self.mailbox.recv().await {
            work.execute(self).await;
        }
    }
}

#[async_trait]
impl<State, Action, RootReducer> HandleWork<Dispatch<Action>> for StateWorker<State, Action, RootReducer>
where
    RootReducer: Reducer<State, Action>,
    State: Send,
    RootReducer: Send,
    Action: Send,
{
    async fn handle_work(&mut self, work: Dispatch<Action>) {
        let action = work.into_action();

        let old_state = self.state.take().unwrap();
        let new_state = self.root_reducer.reduce(old_state, action);

        self.state = Some(new_state);

        if !self.subscribers.is_empty() {
            let new_state = self.state.as_ref().unwrap();
            for subscriber in &self.subscribers {
                subscriber.notify(new_state)
            }
        }
    }
}

#[async_trait]
impl<State, Action, RootReducer, S, Result> HandleWork<Select<State, S>> for StateWorker<State, Action, RootReducer>
where
    RootReducer: Reducer<State, Action>,
    State: Send,
    RootReducer: Send,
    S: Selector<State, Result = Result> + Send + 'static,
    Result: Send,
{
    async fn handle_work(&mut self, work: Select<State, S>) -> Result {
        let state = self.state.as_ref().unwrap();
        let selector = work.into_selector();
        selector.select(state)
    }
}

#[async_trait]
impl<State, Action, RootReducer> HandleWork<Subscribe<State>> for StateWorker<State, Action, RootReducer>
where
    RootReducer: Reducer<State, Action>,
    State: Send,
    RootReducer: Send,
{
    async fn handle_work(&mut self, work: Subscribe<State>) {
        let subscriber = work.into_subscriber();
        self.subscribers.push(subscriber);
    }
}