Adding in Map2 and map_rc macro

This commit is contained in:
Pauan 2018-02-23 16:50:03 -10:00
parent e7e22f3b21
commit 34b22c60f8
5 changed files with 341 additions and 14 deletions

View File

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

View File

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

View File

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

View File

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

View File

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