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]
|
[dependencies]
|
||||||
dominator = { path = "../.." }
|
dominator = { path = "../.." }
|
||||||
signals = { path = "../../signals" }
|
signals = { path = "../../signals" }
|
||||||
|
serde = "1.0.27"
|
||||||
|
serde_json = "1.0.10"
|
||||||
|
serde_derive = "1.0.27"
|
||||||
|
|
||||||
[dependencies.stdweb]
|
[dependencies.stdweb]
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
|
@ -4,6 +4,10 @@ extern crate stdweb;
|
||||||
extern crate dominator;
|
extern crate dominator;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate signals;
|
extern crate signals;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
extern crate serde;
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
@ -28,21 +32,60 @@ enum Filter {
|
||||||
All,
|
All,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
impl Default for Filter {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
Filter::All
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
struct Todo {
|
struct Todo {
|
||||||
id: u32,
|
id: u32,
|
||||||
title: Mutable<String>,
|
title: Mutable<String>,
|
||||||
completed: Mutable<bool>,
|
completed: Mutable<bool>,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
editing: Mutable<Option<String>>,
|
editing: Mutable<Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
struct State {
|
struct State {
|
||||||
todo_id: Cell<u32>,
|
todo_id: Cell<u32>,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
new_todo_title: Mutable<String>,
|
new_todo_title: Mutable<String>,
|
||||||
|
|
||||||
todo_list: MutableVec<Todo>,
|
todo_list: MutableVec<Todo>,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
filter: Mutable<Filter>,
|
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
|
// TODO make this more efficient
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -105,12 +148,7 @@ fn filter_button(state: Rc<State>, kind: Filter) -> Dom {
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let state = Rc::new(State {
|
let state = Rc::new(State::deserialize());
|
||||||
todo_id: Cell::new(0),
|
|
||||||
new_todo_title: Mutable::new("".to_owned()),
|
|
||||||
todo_list: MutableVec::new(),
|
|
||||||
filter: Mutable::new(Filter::All),
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
fn update_filter(state: &Rc<State>) {
|
fn update_filter(state: &Rc<State>) {
|
||||||
|
@ -169,6 +207,8 @@ fn main() {
|
||||||
completed: Mutable::new(false),
|
completed: Mutable::new(false),
|
||||||
editing: Mutable::new(None),
|
editing: Mutable::new(None),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
state.serialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -205,6 +245,8 @@ fn main() {
|
||||||
for todo in state.todo_list.as_slice().iter() {
|
for todo in state.todo_list.as_slice().iter() {
|
||||||
todo.completed.set(checked);
|
todo.completed.set(checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.serialize();
|
||||||
}));
|
}));
|
||||||
}),
|
}),
|
||||||
html!("label", {
|
html!("label", {
|
||||||
|
@ -262,8 +304,9 @@ fn main() {
|
||||||
attribute("type", "checkbox");
|
attribute("type", "checkbox");
|
||||||
class("toggle", true);
|
class("toggle", true);
|
||||||
property("checked", todo.completed.signal().dynamic());
|
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));
|
todo.completed.set(get_checked(&event));
|
||||||
|
state.serialize();
|
||||||
}));
|
}));
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -281,6 +324,8 @@ fn main() {
|
||||||
event(clone!(state, todo => move |_: ClickEvent| {
|
event(clone!(state, todo => move |_: ClickEvent| {
|
||||||
// TODO make this more efficient ?
|
// TODO make this more efficient ?
|
||||||
state.todo_list.retain(|x| x.id != todo.id);
|
state.todo_list.retain(|x| x.id != todo.id);
|
||||||
|
|
||||||
|
state.serialize();
|
||||||
}));
|
}));
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
@ -319,6 +364,8 @@ fn main() {
|
||||||
// TODO make this more efficient ?
|
// TODO make this more efficient ?
|
||||||
state.todo_list.retain(|x| x.id != todo.id);
|
state.todo_list.retain(|x| x.id != todo.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.serialize();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}),
|
}),
|
||||||
|
@ -387,6 +434,8 @@ fn main() {
|
||||||
|
|
||||||
event(clone!(state => move |_: ClickEvent| {
|
event(clone!(state => move |_: ClickEvent| {
|
||||||
state.todo_list.retain(|todo| todo.completed.get() == false);
|
state.todo_list.retain(|todo| todo.completed.get() == false);
|
||||||
|
|
||||||
|
state.serialize();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
children(&mut [
|
children(&mut [
|
||||||
|
|
|
@ -6,3 +6,5 @@ authors = ["Pauan <pcxunlimited@gmail.com>"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.1.18"
|
futures = "0.1.18"
|
||||||
discard = "1.0.3"
|
discard = "1.0.3"
|
||||||
|
# TODO make this optional
|
||||||
|
serde = "1.0.27"
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate discard;
|
extern crate discard;
|
||||||
|
extern crate serde;
|
||||||
|
|
||||||
pub mod signal;
|
pub mod signal;
|
||||||
pub mod signal_vec;
|
pub mod signal_vec;
|
||||||
|
|
|
@ -479,6 +479,7 @@ pub mod unsync {
|
||||||
use std::cell::{Cell, RefCell, RefMut};
|
use std::cell::{Cell, RefCell, RefMut};
|
||||||
use futures::task;
|
use futures::task;
|
||||||
use futures::task::Task;
|
use futures::task::Task;
|
||||||
|
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||||
|
|
||||||
|
|
||||||
struct MutableState<A> {
|
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>>);
|
pub struct MutableSignal<A: Clone>(Rc<MutableSignalState<A>>);
|
||||||
|
|
||||||
|
|
|
@ -734,6 +734,7 @@ pub mod unsync {
|
||||||
use std::cell::{RefCell, Ref};
|
use std::cell::{RefCell, Ref};
|
||||||
use futures::unsync::mpsc;
|
use futures::unsync::mpsc;
|
||||||
use futures::{Async, Stream};
|
use futures::{Async, Stream};
|
||||||
|
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||||
|
|
||||||
|
|
||||||
struct MutableVecState<A> {
|
struct MutableVecState<A> {
|
||||||
|
@ -901,13 +902,18 @@ pub mod unsync {
|
||||||
|
|
||||||
impl<A> MutableVec<A> {
|
impl<A> MutableVec<A> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> Self {
|
pub fn new_with_values(values: Vec<A>) -> Self {
|
||||||
MutableVec(Rc::new(RefCell::new(MutableVecState {
|
MutableVec(Rc::new(RefCell::new(MutableVecState {
|
||||||
values: vec![],
|
values,
|
||||||
senders: vec![],
|
senders: vec![],
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::new_with_values(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pop(&self) -> Option<A> {
|
pub fn pop(&self) -> Option<A> {
|
||||||
self.0.borrow_mut().pop()
|
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> {
|
pub struct MutableSignalVec<A> {
|
||||||
receiver: mpsc::UnboundedReceiver<VecChange<A>>,
|
receiver: mpsc::UnboundedReceiver<VecChange<A>>,
|
||||||
|
|
Loading…
Reference in New Issue