redux-rs 0.1.0

A Rust implementation of Redux.
Documentation
[![Build Status][build-img]][build-url]
[![Crates.io][crates-io-img]][crates-io-url]
[![Documentation][docs-img]][docs-url]
[![Code Coverage][coverage-img]][coverage-url]

# redux-rs

> A Rust implementation of Redux.

## Redux

[Redux][redux-wikipedia-url], [originally implemented in JavaScript][redux-js-url], is an functional approach to state management.
The core concept is that you have a _state_ and a _reducer_, a function to create a new state from the old one and an _action_, a description of what to change.
Because the state itself is immutable, this results in a very clean way of managing application state, where every possible action is defined beforehand and dispatched later on.

## Usage

You might want to read the [documentation][docs-url], which also provides examples.

Also consider checking out the [examples](examples).

To run an example:

```
cargo run --example <name of the example>
```

To jump right into it, here is the simple counter example from [examples/counter.rs](examples/counter.rs):

```rust
use redux_rs::{Store, Subscription};

#[derive(Default)]
// This is a state. It describes an immutable object.
// It is changed via a 'reducer', a function which receives an action and returns a new state modified based on the action.
struct State {
    counter: i8
}

// The actions describe what the reducer has to do.
// Rust enums can carry a payload, which one can use to pass some value to the reducer.
enum Action {
    Increment,
    Decrement
}

// Here comes the reducer. It gets the current state plus an action to perform and returns a new state.
fn counter_reducer(state: &State, action: &Action) -> State {
    match action {
        Action::Increment => State {
            counter: state.counter + 1
        },
        Action::Decrement => State {
            counter: state.counter - 1
        }
    }
}

fn main() {
    // A store is a way to handle a state. It gets created once and after that it can be read and changed via dispatching actions.
    let mut store = Store::new(counter_reducer, State::default());

    // A listener getting triggered whenever the state changes.
    let listener: Subscription<State> = |state: &State| {
        println!("Counter changed! New value: {}", state.counter);
    };

    // Listener gets subscribed to the store.
    store.subscribe(listener);

    // Now, let's dispatch some actions!
    store.dispatch(Action::Increment);
    store.dispatch(Action::Increment);
    store.dispatch(Action::Increment);
    store.dispatch(Action::Decrement);
    store.dispatch(Action::Decrement);

    // Retrieve the value at any time.
    println!("Final value: {}", store.state().counter);
}
```

### `no_std` support

redux-rs supports the `no_std` feature via disabling the default features.

_**Note:**_ This requires a nightly compiler and the availability of the `alloc` crate for the target.

In your `Cargo.toml`:

```toml
[dependencies]
redux-rs = { version = "...", default-features = false }
```

## Benchmarks

Running benchmarks requires a nightly compiler.

```
cargo +nightly bench
```

```
test counter_decrement                         ... bench:           2 ns/iter (+/- 0)
test counter_increment_with_reverse_middleware ... bench:           6 ns/iter (+/- 0)
test counter_increment_with_subscription       ... bench:           3 ns/iter (+/- 0)
```

[build-img]: https://travis-ci.com/redux-rs/redux-rs.svg?branch=master
[build-url]: https://travis-ci.com/redux-rs/redux-rs
[crates-io-img]: https://img.shields.io/crates/v/redux-rs.svg
[crates-io-url]: https://crates.io/crates/redux-rs
[docs-img]: https://docs.rs/redux-rs/badge.svg
[docs-url]: https://docs.rs/redux-rs
[coverage-img]: https://codecov.io/gh/redux-rs/redux-rs/branch/master/graph/badge.svg
[coverage-url]: https://codecov.io/gh/redux-rs/redux-rs
[redux-wikipedia-url]: https://en.wikipedia.org/wiki/Redux_(JavaScript_library)
[redux-js-url]: https://redux.js.org