Adding in Map2 and map_rc macro
This commit is contained in:
parent
e7e22f3b21
commit
34b22c60f8
|
@ -4,7 +4,10 @@ version = "0.1.0"
|
|||
authors = ["Pauan <pcxunlimited@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
stdweb = { path = "../stdweb" }
|
||||
stdweb-derive = { path = "../stdweb/stdweb-derive" }
|
||||
futures = "0.1.18"
|
||||
lazy_static = "1.0.0"
|
||||
|
||||
[dependencies.stdweb]
|
||||
path = "../stdweb"
|
||||
features = ["experimental_features_which_may_break_on_minor_version_bumps"]
|
||||
|
|
|
@ -4,5 +4,8 @@ version = "0.1.0"
|
|||
authors = ["Pauan <pcxunlimited@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
stdweb = { path = "../../../stdweb" }
|
||||
dominator = { path = "../.." }
|
||||
|
||||
[dependencies.stdweb]
|
||||
path = "../../../stdweb"
|
||||
features = ["experimental_features_which_may_break_on_minor_version_bumps"]
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#![feature(trace_macros)]
|
||||
#![feature(log_syntax)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate stdweb;
|
||||
|
||||
|
@ -31,25 +34,49 @@ fn main() {
|
|||
let (sender_elements, receiver_elements) = signal::unsync::mutable(count);
|
||||
|
||||
|
||||
let mut width = 100;
|
||||
let mut width: u32 = 10;
|
||||
|
||||
let (sender, receiver) = signal::unsync::mutable(width);
|
||||
let (sender1, receiver1) = signal::unsync::mutable(width);
|
||||
let (sender2, receiver2) = signal::unsync::mutable(vec![width]);
|
||||
let (sender3, receiver3) = signal::unsync::mutable(vec![width]);
|
||||
|
||||
|
||||
trace_macros!(true);
|
||||
|
||||
/*let style_width = receiver1.switch(move |x| {
|
||||
receiver2.clone().switch(move |y| {
|
||||
receiver3.clone().map(move |z| {
|
||||
Some(format!("{}px", x + y[0] + z[0]))
|
||||
})
|
||||
})
|
||||
});*/
|
||||
|
||||
let style_width = map_rc! {
|
||||
let x: Rc<u32> = receiver1,
|
||||
let y: Rc<Vec<u32>> = receiver2,
|
||||
let _z: Rc<Vec<u32>> = receiver3 =>
|
||||
Some(format!("{}px", *x + y[0]))
|
||||
};
|
||||
|
||||
trace_macros!(false);
|
||||
|
||||
|
||||
html!("div", {
|
||||
style("border", "10px solid blue");
|
||||
children([
|
||||
html!("div", {
|
||||
style("width", receiver.map(|x| Some(format!("{}px", x))));
|
||||
style("width", style_width);
|
||||
style("height", "50px");
|
||||
style("background-color", "green");
|
||||
event(move |event: ClickEvent| {
|
||||
count += 1;
|
||||
width += 100;
|
||||
width += 5;
|
||||
|
||||
console!(log, &event);
|
||||
|
||||
sender.set(width).unwrap();
|
||||
sender1.set(width).unwrap();
|
||||
sender2.set(vec![width]).unwrap();
|
||||
sender3.set(vec![width]).unwrap();
|
||||
sender_elements.set(count).unwrap();
|
||||
});
|
||||
children(receiver_elements.map(|count| {
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
use std;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Mutex;
|
||||
use stdweb::{Reference, Value, ReferenceType};
|
||||
use stdweb::unstable::{TryFrom, TryInto};
|
||||
use stdweb::web::{IEventTarget, INode, IElement, IHtmlElement, Node, TextNode};
|
||||
use stdweb::web::event::ConcreteEvent;
|
||||
use signal::{Signal, DropHandle};
|
||||
use signal::Signal;
|
||||
|
||||
|
||||
// TODO this should be in stdweb
|
||||
|
|
304
src/signal.rs
304
src/signal.rs
|
@ -30,9 +30,23 @@ pub trait Signal {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn map2<A, B, C>(self, other: A, callback: B) -> Map2<Self, A, B>
|
||||
where A: Signal,
|
||||
B: FnMut(&mut Self::Value, &mut A::Value) -> C,
|
||||
Self: Sized {
|
||||
Map2 {
|
||||
signal1: self,
|
||||
signal2: other,
|
||||
callback,
|
||||
left: None,
|
||||
right: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn map_dedupe<A, B>(self, callback: A) -> MapDedupe<Self, A>
|
||||
where A: FnMut(&Self::Value) -> B,
|
||||
where A: FnMut(&mut Self::Value) -> B,
|
||||
Self: Sized {
|
||||
MapDedupe {
|
||||
old_value: None,
|
||||
|
@ -63,7 +77,7 @@ pub trait Signal {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn and_then<A, B>(self, callback: A) -> Flatten<Map<Self, A>>
|
||||
fn switch<A, B>(self, callback: A) -> Flatten<Map<Self, A>>
|
||||
where A: FnMut(Self::Value) -> B,
|
||||
B: Signal,
|
||||
Self: Sized {
|
||||
|
@ -87,6 +101,32 @@ pub trait Signal {
|
|||
|
||||
handle
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct Always<A> {
|
||||
value: Option<A>,
|
||||
}
|
||||
|
||||
impl<A> Signal for Always<A> {
|
||||
type Value = A;
|
||||
|
||||
#[inline]
|
||||
fn poll(&mut self) -> Async<Self::Value> {
|
||||
self.value.take().map(Async::Ready).unwrap_or(Async::NotReady)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn always<A>(value: A) -> Always<A> {
|
||||
Always {
|
||||
value: Some(value),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,6 +217,60 @@ impl<A, B, C> Signal for Map<A, B>
|
|||
}
|
||||
|
||||
|
||||
pub struct Map2<A: Signal, B: Signal, C> {
|
||||
signal1: A,
|
||||
signal2: B,
|
||||
callback: C,
|
||||
left: Option<A::Value>,
|
||||
right: Option<B::Value>,
|
||||
}
|
||||
|
||||
impl<A, B, C, D> Signal for Map2<A, B, C>
|
||||
where A: Signal,
|
||||
B: Signal,
|
||||
C: FnMut(&mut A::Value, &mut B::Value) -> D {
|
||||
type Value = D;
|
||||
|
||||
// TODO inline this ?
|
||||
fn poll(&mut self) -> Async<Self::Value> {
|
||||
match self.signal1.poll() {
|
||||
Async::Ready(mut left) => {
|
||||
let output = match self.signal2.poll() {
|
||||
Async::Ready(mut right) => {
|
||||
let output = Async::Ready((self.callback)(&mut left, &mut right));
|
||||
self.right = Some(right);
|
||||
output
|
||||
},
|
||||
|
||||
Async::NotReady => match self.right {
|
||||
Some(ref mut right) => Async::Ready((self.callback)(&mut left, right)),
|
||||
None => Async::NotReady,
|
||||
},
|
||||
};
|
||||
|
||||
self.left = Some(left);
|
||||
|
||||
output
|
||||
},
|
||||
|
||||
Async::NotReady => match self.left {
|
||||
Some(ref mut left) => match self.signal2.poll() {
|
||||
Async::Ready(mut right) => {
|
||||
let output = Async::Ready((self.callback)(left, &mut right));
|
||||
self.right = Some(right);
|
||||
output
|
||||
},
|
||||
|
||||
Async::NotReady => Async::NotReady,
|
||||
},
|
||||
|
||||
None => Async::NotReady,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct MapDedupe<A: Signal, B> {
|
||||
old_value: Option<A::Value>,
|
||||
signal: A,
|
||||
|
@ -195,14 +289,14 @@ impl<A, B, C> Signal for MapDedupe<A, B>
|
|||
fn poll(&mut self) -> Async<Self::Value> {
|
||||
loop {
|
||||
match self.signal.poll() {
|
||||
Async::Ready(value) => {
|
||||
Async::Ready(mut value) => {
|
||||
let has_changed = match self.old_value {
|
||||
Some(ref old_value) => *old_value != value,
|
||||
None => true,
|
||||
};
|
||||
|
||||
if has_changed {
|
||||
let output = (self.callback)(&value);
|
||||
let output = (self.callback)(&mut value);
|
||||
self.old_value = Some(value);
|
||||
return Async::Ready(output);
|
||||
}
|
||||
|
@ -315,6 +409,7 @@ pub mod unsync {
|
|||
}
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Receiver<A> {
|
||||
inner: Rc<RefCell<Inner<A>>>,
|
||||
}
|
||||
|
@ -355,3 +450,204 @@ pub mod unsync {
|
|||
(sender, receiver)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*map! {
|
||||
let foo = 1,
|
||||
let bar = 2,
|
||||
let qux = 3 => {
|
||||
let corge = 4;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
/*
|
||||
map!(x, y => x + y)
|
||||
*/
|
||||
|
||||
|
||||
// TODO should this be hidden from the docs ?
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub fn pair_rc<'a, 'b, A, B>(left: &'a mut Rc<A>, right: &'b mut Rc<B>) -> (Rc<A>, Rc<B>) {
|
||||
(left.clone(), right.clone())
|
||||
}
|
||||
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_map_clone {
|
||||
($name:ident) => {
|
||||
::std::clone::Clone::clone($name)
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_map_rc_new {
|
||||
($value:expr) => {
|
||||
$crate::signal::Signal::map($value, ::std::rc::Rc::new)
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_map1 {
|
||||
($name:ident, $value:expr, $f:expr) => {
|
||||
$crate::signal::Signal::map(
|
||||
__internal_map_rc_new!($value),
|
||||
|ref mut $name| $f
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_map2 {
|
||||
($old_expr:expr, $old_pair:pat, $name:ident, $value:expr, $f:expr) => {
|
||||
$crate::signal::Signal::map2(
|
||||
$old_expr,
|
||||
__internal_map_rc_new!($value),
|
||||
|$old_pair, ref mut $name| $f
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_map2_pair {
|
||||
($f:expr, $old_expr:expr, $old_pair:pat, { $($lets:stmt);* }, $name:ident, $t:ty, $value:expr, $($args:tt)+) => {
|
||||
__internal_map_args!(
|
||||
$f,
|
||||
$crate::signal::Signal::map2(
|
||||
$old_expr,
|
||||
__internal_map_rc_new!($value),
|
||||
$crate::signal::pair_rc
|
||||
),
|
||||
&mut ($old_pair, ref mut $name),
|
||||
{ $($lets;)* let $name: $t = __internal_map_clone!($name) },
|
||||
$($args)+
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_map_args_start {
|
||||
($f:expr, $name:ident, $value:expr, { $($lets:stmt);* }, $($args:tt)+) => {
|
||||
__internal_map_args!(
|
||||
$f,
|
||||
__internal_map_rc_new!($value),
|
||||
ref mut $name,
|
||||
{ $($lets);* },
|
||||
$($args)+
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_map_args {
|
||||
($f:expr, $old_expr:expr, $old_pair:pat, { $($lets:stmt);* }, let $name:ident: $t:ty = $value:expr) => {
|
||||
__internal_map2!($old_expr, $old_pair, $name, $value, { $($lets;)* let $name: $t = __internal_map_clone!($name); $f })
|
||||
};
|
||||
($f:expr, $old_expr:expr, $old_pair:pat, { $($lets:stmt);* }, let $name:ident = $value:expr) => {
|
||||
__internal_map2!($old_expr, $old_pair, $name, $value, { $($lets;)* let $name: Rc<_> = __internal_map_clone!($name); $f })
|
||||
};
|
||||
($f:expr, $old_expr:expr, $old_pair:pat, { $($lets:stmt);* }, $name:ident) => {
|
||||
__internal_map2!($old_expr, $old_pair, $name, $name, { $($lets;)* let $name: Rc<_> = __internal_map_clone!($name); $f })
|
||||
};
|
||||
($f:expr, $old_expr:expr, $old_pair:pat, { $($lets:stmt);* }, let $name:ident: $t:ty = $value:expr, $($args:tt)+) => {
|
||||
__internal_map2_pair!($f, $old_expr, $old_pair, { $($lets);* }, $name, $t, $value, $($args)+)
|
||||
};
|
||||
($f:expr, $old_expr:expr, $old_pair:pat, { $($lets:stmt);* }, let $name:ident = $value:expr, $($args:tt)+) => {
|
||||
__internal_map2_pair!($f, $old_expr, $old_pair, { $($lets);* }, $name, Rc<_>, $value, $($args)+)
|
||||
};
|
||||
($f:expr, $old_expr:expr, $old_pair:pat, { $($lets:stmt);* }, $name:ident, $($args:tt)+) => {
|
||||
__internal_map2_pair!($f, $old_expr, $old_pair, { $($lets);* }, $name, Rc<_>, $name, $($args)+)
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_map {
|
||||
($f:expr, let $name:ident: $t:ty = $value:expr) => {
|
||||
__internal_map1!($name, $value, { let $name: $t = __internal_map_clone!($name); $f })
|
||||
};
|
||||
($f:expr, let $name:ident = $value:expr) => {
|
||||
__internal_map1!($name, $value, { let $name: Rc<_> = __internal_map_clone!($name); $f })
|
||||
};
|
||||
($f:expr, $name:ident) => {
|
||||
__internal_map1!($name, $name, { let $name: Rc<_> = __internal_map_clone!($name); $f })
|
||||
};
|
||||
($f:expr, let $name:ident: $t:ty = $value:expr, $($args:tt)+) => {
|
||||
__internal_map_args_start!($f, $name, $value, { let $name: $t = __internal_map_clone!($name) }, $($args)+)
|
||||
};
|
||||
($f:expr, let $name:ident = $value:expr, $($args:tt)+) => {
|
||||
__internal_map_args_start!($f, $name, $value, { let $name: Rc<_> = __internal_map_clone!($name) }, $($args)+)
|
||||
};
|
||||
($f:expr, $name:ident, $($args:tt)+) => {
|
||||
__internal_map_args_start!($f, $name, $name, { let $name: Rc<_> = __internal_map_clone!($name) }, $($args)+)
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_map_split {
|
||||
(($($before:tt)*), => $f:expr) => {
|
||||
__internal_map!($f, $($before)*)
|
||||
};
|
||||
(($($before:tt)*), $t:tt $($after:tt)*) => {
|
||||
__internal_map_split!(($($before)* $t), $($after)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map_rc {
|
||||
($($input:tt)*) => { __internal_map_split!((), $($input)*) };
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use futures::Async;
|
||||
use super::{Signal, always};
|
||||
|
||||
#[test]
|
||||
fn map_macro_ident_1() {
|
||||
let a = always(1);
|
||||
let mut s = map_rc!(a => a + 1);
|
||||
assert_eq!(s.poll(), Async::Ready(2));
|
||||
assert_eq!(s.poll(), Async::NotReady);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_macro_ident_2() {
|
||||
let a = always(1);
|
||||
let b = always(2);
|
||||
let mut s = map_rc!(a, b => *a + *b);
|
||||
assert_eq!(s.poll(), Async::Ready(3));
|
||||
assert_eq!(s.poll(), Async::NotReady);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_macro_ident_3() {
|
||||
let a = always(1);
|
||||
let b = always(2);
|
||||
let c = always(3);
|
||||
let mut s = map_rc!(a, b, c => *a + *b + *c);
|
||||
assert_eq!(s.poll(), Async::Ready(6));
|
||||
assert_eq!(s.poll(), Async::NotReady);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_macro_ident_4() {
|
||||
let a = always(1);
|
||||
let b = always(2);
|
||||
let c = always(3);
|
||||
let d = always(4);
|
||||
let mut s = map_rc!(a, b, c, d => *a + *b + *c + *d);
|
||||
assert_eq!(s.poll(), Async::Ready(10));
|
||||
assert_eq!(s.poll(), Async::NotReady);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue