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, 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, 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); } } }