From cfdf561394a79387ae87fb3121f7b3ea0cec2eb0 Mon Sep 17 00:00:00 2001 From: Pauan Date: Thu, 8 Mar 2018 13:04:20 -1000 Subject: [PATCH] Adding in serialization/deserialization for the todomvc example --- examples/todomvc/Cargo.toml | 3 ++ examples/todomvc/src/main.rs | 65 +++++++++++++++++++++++++++++++----- signals/Cargo.toml | 2 ++ signals/src/lib.rs | 1 + signals/src/signal.rs | 22 ++++++++++++ signals/src/signal_vec.rs | 31 +++++++++++++++-- 6 files changed, 114 insertions(+), 10 deletions(-) diff --git a/examples/todomvc/Cargo.toml b/examples/todomvc/Cargo.toml index ebec9f1..c0d8ea4 100644 --- a/examples/todomvc/Cargo.toml +++ b/examples/todomvc/Cargo.toml @@ -6,6 +6,9 @@ authors = ["Pauan "] [dependencies] dominator = { path = "../.." } signals = { path = "../../signals" } +serde = "1.0.27" +serde_json = "1.0.10" +serde_derive = "1.0.27" [dependencies.stdweb] version = "0.4.0" diff --git a/examples/todomvc/src/main.rs b/examples/todomvc/src/main.rs index 8af49d2..f8b9ef5 100644 --- a/examples/todomvc/src/main.rs +++ b/examples/todomvc/src/main.rs @@ -4,6 +4,10 @@ extern crate stdweb; extern crate dominator; #[macro_use] extern crate signals; +#[macro_use] +extern crate serde_derive; +extern crate serde; +extern crate serde_json; use std::rc::Rc; use std::cell::Cell; @@ -28,21 +32,60 @@ enum Filter { All, } -#[derive(Clone)] +impl Default for Filter { + #[inline] + fn default() -> Self { + Filter::All + } +} + + +#[derive(Clone, Serialize, Deserialize)] struct Todo { id: u32, title: Mutable, completed: Mutable, + + #[serde(skip)] editing: Mutable>, } + +#[derive(Serialize, Deserialize)] struct State { todo_id: Cell, + + #[serde(skip)] new_todo_title: Mutable, + todo_list: MutableVec, + + #[serde(skip)] filter: Mutable, } +impl State { + fn new() -> Self { + State { + todo_id: Cell::new(0), + new_todo_title: Mutable::new("".to_owned()), + todo_list: MutableVec::new(), + filter: Mutable::new(Filter::All), + } + } + + fn deserialize() -> Self { + window().local_storage().get("todos-rust-dominator").and_then(|state_json| { + serde_json::from_str(state_json.as_str()).ok() + }).unwrap_or_else(State::new) + } + + fn serialize(&self) { + let state_json = serde_json::to_string(self).unwrap(); + window().local_storage().insert("todos-rust-dominator", state_json.as_str()).unwrap(); + } +} + // TODO make this more efficient #[inline] @@ -105,12 +148,7 @@ fn filter_button(state: Rc, kind: Filter) -> Dom { fn main() { - let state = Rc::new(State { - todo_id: Cell::new(0), - new_todo_title: Mutable::new("".to_owned()), - todo_list: MutableVec::new(), - filter: Mutable::new(Filter::All), - }); + let state = Rc::new(State::deserialize()); fn update_filter(state: &Rc) { @@ -169,6 +207,8 @@ fn main() { completed: Mutable::new(false), editing: Mutable::new(None), }); + + state.serialize(); } } })); @@ -205,6 +245,8 @@ fn main() { for todo in state.todo_list.as_slice().iter() { todo.completed.set(checked); } + + state.serialize(); })); }), html!("label", { @@ -262,8 +304,9 @@ fn main() { attribute("type", "checkbox"); class("toggle", true); property("checked", todo.completed.signal().dynamic()); - event(clone!(todo => move |event: ChangeEvent| { + event(clone!(state, todo => move |event: ChangeEvent| { todo.completed.set(get_checked(&event)); + state.serialize(); })); }), @@ -281,6 +324,8 @@ fn main() { event(clone!(state, todo => move |_: ClickEvent| { // TODO make this more efficient ? state.todo_list.retain(|x| x.id != todo.id); + + state.serialize(); })); }), ]); @@ -319,6 +364,8 @@ fn main() { // TODO make this more efficient ? state.todo_list.retain(|x| x.id != todo.id); } + + state.serialize(); } })); }), @@ -387,6 +434,8 @@ fn main() { event(clone!(state => move |_: ClickEvent| { state.todo_list.retain(|todo| todo.completed.get() == false); + + state.serialize(); })); children(&mut [ diff --git a/signals/Cargo.toml b/signals/Cargo.toml index e636260..dd3c8e3 100644 --- a/signals/Cargo.toml +++ b/signals/Cargo.toml @@ -6,3 +6,5 @@ authors = ["Pauan "] [dependencies] futures = "0.1.18" discard = "1.0.3" +# TODO make this optional +serde = "1.0.27" diff --git a/signals/src/lib.rs b/signals/src/lib.rs index 822af98..e0d1547 100644 --- a/signals/src/lib.rs +++ b/signals/src/lib.rs @@ -2,6 +2,7 @@ extern crate futures; extern crate discard; +extern crate serde; pub mod signal; pub mod signal_vec; diff --git a/signals/src/signal.rs b/signals/src/signal.rs index dfcce61..2afaed2 100644 --- a/signals/src/signal.rs +++ b/signals/src/signal.rs @@ -479,6 +479,7 @@ pub mod unsync { use std::cell::{Cell, RefCell, RefMut}; use futures::task; use futures::task::Task; + use serde::{Serialize, Deserialize, Serializer, Deserializer}; struct MutableState { @@ -570,6 +571,27 @@ pub mod unsync { } } + impl Serialize for Mutable where T: Serialize { + #[inline] + fn serialize(&self, serializer: S) -> Result where S: Serializer { + self.0.borrow().value.serialize(serializer) + } + } + + impl<'de, T> Deserialize<'de> for Mutable where T: Deserialize<'de> { + #[inline] + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + T::deserialize(deserializer).map(Mutable::new) + } + } + + impl Default for Mutable { + #[inline] + fn default() -> Self { + Mutable::new(Default::default()) + } + } + pub struct MutableSignal(Rc>); diff --git a/signals/src/signal_vec.rs b/signals/src/signal_vec.rs index ef7d8d3..893c41f 100644 --- a/signals/src/signal_vec.rs +++ b/signals/src/signal_vec.rs @@ -734,6 +734,7 @@ pub mod unsync { use std::cell::{RefCell, Ref}; use futures::unsync::mpsc; use futures::{Async, Stream}; + use serde::{Serialize, Deserialize, Serializer, Deserializer}; struct MutableVecState { @@ -901,13 +902,18 @@ pub mod unsync { impl MutableVec { #[inline] - pub fn new() -> Self { + pub fn new_with_values(values: Vec) -> Self { MutableVec(Rc::new(RefCell::new(MutableVecState { - values: vec![], + values, senders: vec![], }))) } + #[inline] + pub fn new() -> Self { + Self::new_with_values(vec![]) + } + #[inline] pub fn pop(&self) -> Option { self.0.borrow_mut().pop() @@ -967,6 +973,27 @@ pub mod unsync { } } + impl Serialize for MutableVec where T: Serialize { + #[inline] + fn serialize(&self, serializer: S) -> Result where S: Serializer { + self.0.borrow().values.serialize(serializer) + } + } + + impl<'de, T> Deserialize<'de> for MutableVec where T: Deserialize<'de> { + #[inline] + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + >::deserialize(deserializer).map(MutableVec::new_with_values) + } + } + + impl Default for MutableVec { + #[inline] + fn default() -> Self { + MutableVec::new() + } + } + pub struct MutableSignalVec { receiver: mpsc::UnboundedReceiver>,