rust-elm 0.1.0

Elm Architecture for Rust: composable reducers, pure effects, async runtime.
Documentation
use rust_elm::{
    reducer::coerce_fn, reducers, Cmd, CombineReducers, Reduce, Reducer, ReducerProgram, Runtime,
    panic_on_state_clone, Sub, Environment,
};

panic_on_state_clone! {
    #[derive(Default, Debug, PartialEq, Eq)]
    struct App {
        count: i32,
        doubled: i32,
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Action {
    N(i32),
}

fn init() -> (App, Cmd<Action>) {
    (App::default(), Cmd::none())
}

fn subscriptions(_: &App) -> Sub<Action> {
    Sub::none()
}

fn count_reducer(state: &mut App, action: Action) -> Cmd<Action> {
    if let Action::N(n) = action {
        state.count += n;
    }
    Cmd::none()
}

fn double_reducer(state: &mut App, action: Action) -> Cmd<Action> {
    if let Action::N(n) = action {
        state.doubled += n * 2;
    }
    Cmd::none()
}

#[test]
fn combine_reducers_apply_in_order() {
    let combined = CombineReducers((coerce_fn(count_reducer), coerce_fn(double_reducer)));
    let mut app = App::default();
    combined.reduce(&mut app, Action::N(3));
    assert_eq!(app.count, 3);
    assert_eq!(app.doubled, 6);
}

#[test]
fn reducers_macro_matches_manual_combine() {
    let manual = CombineReducers((coerce_fn(count_reducer), coerce_fn(double_reducer)));
    let from_macro = reducers![count_reducer, double_reducer];

    let mut a = App::default();
    let mut b = App::default();
    manual.reduce(&mut a, Action::N(5));
    from_macro.reduce(&mut b, Action::N(5));
    assert_eq!(a, b);
}

#[test]
fn reduce_wrapper_is_reducer() {
    let r = Reduce::new(count_reducer);
    let mut app = App::default();
    r.reduce(&mut app, Action::N(1));
    assert_eq!(app.count, 1);
}

#[test]
fn runtime_from_reducer_program() {
    let program = ReducerProgram::new(
        reducers![count_reducer, double_reducer],
        init,
        subscriptions,
    );
    let runtime = Runtime::from_reducer_program(program, Environment::new(), 8);
    runtime.dispatch(Action::N(4));
    std::thread::sleep(std::time::Duration::from_millis(100));
    let state = runtime.state.lock();
    assert_eq!(state.count, 4);
    assert_eq!(state.doubled, 8);
    drop(state);
    runtime.shutdown();
}