Adding in serialization/deserialization for the todomvc example
This commit is contained in:
parent
3b1bafd0df
commit
cfdf561394
|
@ -6,6 +6,9 @@ authors = ["Pauan <pcxunlimited@gmail.com>"]
|
|||
[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"
|
||||
|
|
|
@ -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<String>,
|
||||
completed: Mutable<bool>,
|
||||
|
||||
#[serde(skip)]
|
||||
editing: Mutable<Option<String>>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct State {
|
||||
todo_id: Cell<u32>,
|
||||
|
||||
#[serde(skip)]
|
||||
new_todo_title: Mutable<String>,
|
||||
|
||||
todo_list: MutableVec<Todo>,
|
||||
|
||||
#[serde(skip)]
|
||||
filter: Mutable<Filter>,
|
||||
}
|
||||
|
||||
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<State>, 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<State>) {
|
||||
|
@ -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 [
|
||||
|
|
|
@ -6,3 +6,5 @@ authors = ["Pauan <pcxunlimited@gmail.com>"]
|
|||
[dependencies]
|
||||
futures = "0.1.18"
|
||||
discard = "1.0.3"
|
||||
# TODO make this optional
|
||||
serde = "1.0.27"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
extern crate futures;
|
||||
extern crate discard;
|
||||
extern crate serde;
|
||||
|
||||
pub mod signal;
|
||||
pub mod signal_vec;
|
||||
|
|
|
@ -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<A> {
|
||||
|
@ -570,6 +571,27 @@ pub mod unsync {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Mutable<T> where T: Serialize {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
self.0.borrow().value.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for Mutable<T> where T: Deserialize<'de> {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
|
||||
T::deserialize(deserializer).map(Mutable::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Default for Mutable<T> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Mutable::new(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct MutableSignal<A: Clone>(Rc<MutableSignalState<A>>);
|
||||
|
||||
|
|
|
@ -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<A> {
|
||||
|
@ -901,13 +902,18 @@ pub mod unsync {
|
|||
|
||||
impl<A> MutableVec<A> {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
pub fn new_with_values(values: Vec<A>) -> 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<A> {
|
||||
self.0.borrow_mut().pop()
|
||||
|
@ -967,6 +973,27 @@ pub mod unsync {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for MutableVec<T> where T: Serialize {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
self.0.borrow().values.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for MutableVec<T> where T: Deserialize<'de> {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
|
||||
<Vec<T>>::deserialize(deserializer).map(MutableVec::new_with_values)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for MutableVec<T> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
MutableVec::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct MutableSignalVec<A> {
|
||||
receiver: mpsc::UnboundedReceiver<VecChange<A>>,
|
||||
|
|
Loading…
Reference in New Issue