tutorials/rust/hello-server/src/store.rs

107 lines
3.3 KiB
Rust

use rustc_serialize::json::{self, Json, ToJson};
use store::Action::{ Visibility };
use todo::{ Todo, TodoAction, todo_reducer };
// Ripping off the canonical Redux todo example we'll add a
// visibility filter to our state in addation to the todos we already had
// This state struct will be the single source of state for our todo list program
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct State {
pub todos: Vec<Todo>,
pub visibility_filter: VisibilityFilter
}
// By implementing a struct we are creating something very much like
// a class, we can attach methods to it refering to `&self` or `&mut self`
impl State {
// Can be called with State::default()
pub fn default() -> State {
State {
todos: Vec::new(),
visibility_filter: VisibilityFilter::ShowAll,
}
}
}
impl ToJson for State {
fn to_json(&self) -> Json {
Json::from_str(&json::encode(&self).unwrap()).unwrap()
}
}
// Rust has enums, so the enum type can replace the "type" property of Redux objects
// The enums will replace `action_creators` too since Todos(Add("Todo item".to_string()))
// is pretty clear
#[derive(Clone, Debug)]
pub enum Action {
Todos(TodoAction),
Visibility(VisibilityFilter),
}
// Our 3 visibility states
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum VisibilityFilter {
ShowActive,
ShowAll,
ShowCompleted,
}
// Our main reducer, returns a new State with the results of the child-reducers
// No combineReducers is implemented here, so it calls the child reducers
// by function name
pub fn reducer(state: &State, action: Action) -> State {
// Always return a new state
State {
todos: todo_reducer(&state.todos, &action),
visibility_filter: visibility_reducer(&state.visibility_filter, &action),
}
}
// Very simple reducer since the action will either be a VisibilityFilter, in which
// case we will return that, otherwise just return the incoming state
fn visibility_reducer(state: &VisibilityFilter, action: &Action) -> VisibilityFilter {
match *action {
Visibility(ref vis_action) => vis_action.clone(),
_ => state.clone(),
}
}
// Redux store implementation
pub struct Store {
state: State,
listeners: Vec<fn(&State)>,
reducer: fn(&State, Action) -> State,
}
impl Store {
// Takes a reducer function as the only argument
// To keep it simple, State::default() privides the initial state in this example
pub fn create_store(reducer: fn(&State, Action) -> State) -> Store {
Store {
state: State::default(),
listeners: Vec::new(),
reducer: reducer,
}
}
// Pushes a listener that will be called for any state change
pub fn subscribe(&mut self, listener: fn(&State)) {
self.listeners.push(listener);
}
// Simply returns a borrowed reference to the state
#[allow(dead_code)]
pub fn get_state(&self) -> &State {
&self.state
}
// Called for every new action, calls the reducer to update the state
// and then calls every listener with the new State
pub fn dispatch(&mut self, action: Action) {
self.state = (self.reducer)(&self.state, action);
for listener in &self.listeners {
listener(&self.state);
}
}
}