Adding in serialization/deserialization for the todomvc example

This commit is contained in:
Pauan 2018-03-08 13:04:20 -10:00
parent 3b1bafd0df
commit cfdf561394
6 changed files with 114 additions and 10 deletions

View File

@ -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"

View File

@ -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 [

View File

@ -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"

View File

@ -2,6 +2,7 @@
extern crate futures;
extern crate discard;
extern crate serde;
pub mod signal;
pub mod signal_vec;

View File

@ -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>>);

View File

@ -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>>,