Various changes
This commit is contained in:
parent
8d1395d293
commit
129a0ca09e
|
@ -64,7 +64,7 @@ fn main() {
|
||||||
dominator::append_dom(&document().query_selector("body").unwrap().unwrap(),
|
dominator::append_dom(&document().query_selector("body").unwrap().unwrap(),
|
||||||
html!("div", {
|
html!("div", {
|
||||||
style("border", "10px solid blue");
|
style("border", "10px solid blue");
|
||||||
children([
|
children(&mut [
|
||||||
text("Testing testing!!!"),
|
text("Testing testing!!!"),
|
||||||
|
|
||||||
text(text_receiver.dynamic()),
|
text(text_receiver.dynamic()),
|
||||||
|
@ -100,13 +100,13 @@ fn main() {
|
||||||
style("width", "50px");
|
style("width", "50px");
|
||||||
style("height", "50px");
|
style("height", "50px");
|
||||||
style("background-color", "red");
|
style("background-color", "red");
|
||||||
children([
|
children(&mut [
|
||||||
html!("div", {
|
html!("div", {
|
||||||
style("width", "10px");
|
style("width", "10px");
|
||||||
style("height", "10px");
|
style("height", "10px");
|
||||||
style("background-color", "orange");
|
style("background-color", "orange");
|
||||||
})
|
})
|
||||||
].as_mut());
|
]);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
html!("div", {
|
html!("div", {
|
||||||
|
@ -114,13 +114,13 @@ fn main() {
|
||||||
style("height", "50px");
|
style("height", "50px");
|
||||||
style("background-color", "red");
|
style("background-color", "red");
|
||||||
class(&foobar, true);
|
class(&foobar, true);
|
||||||
children([
|
children(&mut [
|
||||||
html!("div", {
|
html!("div", {
|
||||||
style("width", "10px");
|
style("width", "10px");
|
||||||
style("height", "10px");
|
style("height", "10px");
|
||||||
style("background-color", "orange");
|
style("background-color", "orange");
|
||||||
})
|
})
|
||||||
].as_mut());
|
]);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Dom::with_state(Rc::new(vec![1, 2, 3]), |a| {
|
Dom::with_state(Rc::new(vec![1, 2, 3]), |a| {
|
||||||
|
@ -139,7 +139,7 @@ fn main() {
|
||||||
html!("input", {
|
html!("input", {
|
||||||
focused(true);
|
focused(true);
|
||||||
}),
|
}),
|
||||||
].as_mut());
|
]);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,911 +3,5 @@
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate discard;
|
extern crate discard;
|
||||||
|
|
||||||
use std::rc::{Rc, Weak};
|
pub mod signal;
|
||||||
use std::cell::RefCell;
|
pub mod signal_list;
|
||||||
use futures::{Async, Poll, task};
|
|
||||||
use futures::future::{Future, IntoFuture};
|
|
||||||
use futures::stream::{Stream, ForEach};
|
|
||||||
use discard::{Discard, DiscardOnDrop};
|
|
||||||
|
|
||||||
|
|
||||||
// TODO add in Done to allow the Signal to end ?
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum State<A> {
|
|
||||||
Changed(A),
|
|
||||||
NotChanged,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A> State<A> {
|
|
||||||
#[inline]
|
|
||||||
pub fn map<B, F>(self, f: F) -> State<B> where F: FnOnce(A) -> B {
|
|
||||||
match self {
|
|
||||||
State::Changed(value) => State::Changed(f(value)),
|
|
||||||
State::NotChanged => State::NotChanged,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub trait Signal {
|
|
||||||
type Item;
|
|
||||||
|
|
||||||
fn poll(&mut self) -> State<Self::Item>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_stream(self) -> SignalStream<Self>
|
|
||||||
where Self: Sized {
|
|
||||||
SignalStream {
|
|
||||||
signal: self,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn map<A, B>(self, callback: A) -> Map<Self, A>
|
|
||||||
where A: FnMut(Self::Item) -> B,
|
|
||||||
Self: Sized {
|
|
||||||
Map {
|
|
||||||
signal: self,
|
|
||||||
callback,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn map2<A, B, C>(self, other: A, callback: B) -> Map2<Self, A, B>
|
|
||||||
where A: Signal,
|
|
||||||
B: FnMut(&mut Self::Item, &mut A::Item) -> 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(&mut Self::Item) -> B,
|
|
||||||
Self: Sized {
|
|
||||||
MapDedupe {
|
|
||||||
old_value: None,
|
|
||||||
signal: self,
|
|
||||||
callback,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn filter_map<A, B>(self, callback: A) -> FilterMap<Self, A>
|
|
||||||
where A: FnMut(Self::Item) -> Option<B>,
|
|
||||||
Self: Sized {
|
|
||||||
FilterMap {
|
|
||||||
signal: self,
|
|
||||||
callback,
|
|
||||||
first: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn flatten(self) -> Flatten<Self>
|
|
||||||
where Self::Item: Signal,
|
|
||||||
Self: Sized {
|
|
||||||
Flatten {
|
|
||||||
signal: self,
|
|
||||||
inner: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn switch<A, B>(self, callback: A) -> Flatten<Map<Self, A>>
|
|
||||||
where A: FnMut(Self::Item) -> B,
|
|
||||||
B: Signal,
|
|
||||||
Self: Sized {
|
|
||||||
self.map(callback).flatten()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
// TODO file Rust bug about bad error message when `callback` isn't marked as `mut`
|
|
||||||
fn for_each<F, U>(self, callback: F) -> ForEach<SignalStream<Self>, F, U>
|
|
||||||
where F: FnMut(Self::Item) -> U,
|
|
||||||
// TODO allow for errors ?
|
|
||||||
U: IntoFuture<Item = (), Error = ()>,
|
|
||||||
Self:Sized {
|
|
||||||
|
|
||||||
self.to_stream().for_each(callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn as_mut(&mut self) -> &mut Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct Always<A> {
|
|
||||||
value: Option<A>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A> Signal for Always<A> {
|
|
||||||
type Item = A;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn poll(&mut self) -> State<Self::Item> {
|
|
||||||
match self.value.take() {
|
|
||||||
Some(value) => State::Changed(value),
|
|
||||||
None => State::NotChanged,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn always<A>(value: A) -> Always<A> {
|
|
||||||
Always {
|
|
||||||
value: Some(value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct CancelableFutureState {
|
|
||||||
is_cancelled: bool,
|
|
||||||
task: Option<task::Task>,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct CancelableFutureHandle {
|
|
||||||
state: Weak<RefCell<CancelableFutureState>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Discard for CancelableFutureHandle {
|
|
||||||
fn discard(self) {
|
|
||||||
if let Some(state) = self.state.upgrade() {
|
|
||||||
let mut borrow = state.borrow_mut();
|
|
||||||
|
|
||||||
borrow.is_cancelled = true;
|
|
||||||
|
|
||||||
if let Some(task) = borrow.task.take() {
|
|
||||||
drop(borrow);
|
|
||||||
task.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct CancelableFuture<A, B> {
|
|
||||||
state: Rc<RefCell<CancelableFutureState>>,
|
|
||||||
future: Option<A>,
|
|
||||||
when_cancelled: Option<B>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B> Future for CancelableFuture<A, B>
|
|
||||||
where A: Future,
|
|
||||||
B: FnOnce(A) -> A::Item {
|
|
||||||
|
|
||||||
type Item = A::Item;
|
|
||||||
type Error = A::Error;
|
|
||||||
|
|
||||||
// TODO should this inline ?
|
|
||||||
#[inline]
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
|
||||||
let borrow = self.state.borrow();
|
|
||||||
|
|
||||||
if borrow.is_cancelled {
|
|
||||||
let future = self.future.take().unwrap();
|
|
||||||
let callback = self.when_cancelled.take().unwrap();
|
|
||||||
// TODO figure out how to call the callback immediately when discard is called, e.g. using two Rc<RefCell<>>
|
|
||||||
Ok(Async::Ready(callback(future)))
|
|
||||||
|
|
||||||
} else {
|
|
||||||
drop(borrow);
|
|
||||||
|
|
||||||
match self.future.as_mut().unwrap().poll() {
|
|
||||||
Ok(Async::NotReady) => {
|
|
||||||
self.state.borrow_mut().task = Some(task::current());
|
|
||||||
Ok(Async::NotReady)
|
|
||||||
},
|
|
||||||
a => a,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO figure out a more efficient way to implement this
|
|
||||||
// TODO this should be implemented in the futures crate
|
|
||||||
#[inline]
|
|
||||||
pub fn cancelable_future<A, B>(future: A, when_cancelled: B) -> (DiscardOnDrop<CancelableFutureHandle>, CancelableFuture<A, B>)
|
|
||||||
where A: Future,
|
|
||||||
B: FnOnce(A) -> A::Item {
|
|
||||||
|
|
||||||
let state = Rc::new(RefCell::new(CancelableFutureState {
|
|
||||||
is_cancelled: false,
|
|
||||||
task: None,
|
|
||||||
}));
|
|
||||||
|
|
||||||
let cancel_handle = DiscardOnDrop::new(CancelableFutureHandle {
|
|
||||||
state: Rc::downgrade(&state),
|
|
||||||
});
|
|
||||||
|
|
||||||
let cancel_future = CancelableFuture {
|
|
||||||
state,
|
|
||||||
future: Some(future),
|
|
||||||
when_cancelled: Some(when_cancelled),
|
|
||||||
};
|
|
||||||
|
|
||||||
(cancel_handle, cancel_future)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct SignalStream<A> {
|
|
||||||
signal: A,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Signal> Stream for SignalStream<A> {
|
|
||||||
type Item = A::Item;
|
|
||||||
// TODO use Void instead ?
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
|
||||||
Ok(match self.signal.poll() {
|
|
||||||
State::Changed(value) => Async::Ready(Some(value)),
|
|
||||||
State::NotChanged => Async::NotReady,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct Map<A, B> {
|
|
||||||
signal: A,
|
|
||||||
callback: B,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B, C> Signal for Map<A, B>
|
|
||||||
where A: Signal,
|
|
||||||
B: FnMut(A::Item) -> C {
|
|
||||||
type Item = C;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn poll(&mut self) -> State<Self::Item> {
|
|
||||||
self.signal.poll().map(|value| (self.callback)(value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct Map2<A: Signal, B: Signal, C> {
|
|
||||||
signal1: A,
|
|
||||||
signal2: B,
|
|
||||||
callback: C,
|
|
||||||
left: Option<A::Item>,
|
|
||||||
right: Option<B::Item>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B, C, D> Signal for Map2<A, B, C>
|
|
||||||
where A: Signal,
|
|
||||||
B: Signal,
|
|
||||||
C: FnMut(&mut A::Item, &mut B::Item) -> D {
|
|
||||||
type Item = D;
|
|
||||||
|
|
||||||
// TODO inline this ?
|
|
||||||
fn poll(&mut self) -> State<Self::Item> {
|
|
||||||
match self.signal1.poll() {
|
|
||||||
State::Changed(mut left) => {
|
|
||||||
let output = match self.signal2.poll() {
|
|
||||||
State::Changed(mut right) => {
|
|
||||||
let output = State::Changed((self.callback)(&mut left, &mut right));
|
|
||||||
self.right = Some(right);
|
|
||||||
output
|
|
||||||
},
|
|
||||||
|
|
||||||
State::NotChanged => match self.right {
|
|
||||||
Some(ref mut right) => State::Changed((self.callback)(&mut left, right)),
|
|
||||||
None => State::NotChanged,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
self.left = Some(left);
|
|
||||||
|
|
||||||
output
|
|
||||||
},
|
|
||||||
|
|
||||||
State::NotChanged => match self.left {
|
|
||||||
Some(ref mut left) => match self.signal2.poll() {
|
|
||||||
State::Changed(mut right) => {
|
|
||||||
let output = State::Changed((self.callback)(left, &mut right));
|
|
||||||
self.right = Some(right);
|
|
||||||
output
|
|
||||||
},
|
|
||||||
|
|
||||||
State::NotChanged => State::NotChanged,
|
|
||||||
},
|
|
||||||
|
|
||||||
None => State::NotChanged,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct MapDedupe<A: Signal, B> {
|
|
||||||
old_value: Option<A::Item>,
|
|
||||||
signal: A,
|
|
||||||
callback: B,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B, C> Signal for MapDedupe<A, B>
|
|
||||||
where A: Signal,
|
|
||||||
A::Item: PartialEq,
|
|
||||||
// TODO should this use Fn instead ?
|
|
||||||
B: FnMut(&A::Item) -> C {
|
|
||||||
|
|
||||||
type Item = C;
|
|
||||||
|
|
||||||
// TODO should this use #[inline] ?
|
|
||||||
fn poll(&mut self) -> State<Self::Item> {
|
|
||||||
loop {
|
|
||||||
match self.signal.poll() {
|
|
||||||
State::Changed(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)(&mut value);
|
|
||||||
self.old_value = Some(value);
|
|
||||||
return State::Changed(output);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State::NotChanged => return State::NotChanged,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct FilterMap<A, B> {
|
|
||||||
signal: A,
|
|
||||||
callback: B,
|
|
||||||
first: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B, C> Signal for FilterMap<A, B>
|
|
||||||
where A: Signal,
|
|
||||||
B: FnMut(A::Item) -> Option<C> {
|
|
||||||
type Item = Option<C>;
|
|
||||||
|
|
||||||
// TODO should this use #[inline] ?
|
|
||||||
#[inline]
|
|
||||||
fn poll(&mut self) -> State<Self::Item> {
|
|
||||||
loop {
|
|
||||||
match self.signal.poll() {
|
|
||||||
State::Changed(value) => match (self.callback)(value) {
|
|
||||||
Some(value) => {
|
|
||||||
self.first = false;
|
|
||||||
return State::Changed(Some(value));
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
if self.first {
|
|
||||||
self.first = false;
|
|
||||||
return State::Changed(None);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
State::NotChanged => return State::NotChanged,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct Flatten<A: Signal> {
|
|
||||||
signal: A,
|
|
||||||
inner: Option<A::Item>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A> Signal for Flatten<A>
|
|
||||||
where A: Signal,
|
|
||||||
A::Item: Signal {
|
|
||||||
type Item = <<A as Signal>::Item as Signal>::Item;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn poll(&mut self) -> State<Self::Item> {
|
|
||||||
match self.signal.poll() {
|
|
||||||
State::Changed(mut inner) => {
|
|
||||||
let poll = inner.poll();
|
|
||||||
self.inner = Some(inner);
|
|
||||||
poll
|
|
||||||
},
|
|
||||||
|
|
||||||
State::NotChanged => match self.inner {
|
|
||||||
Some(ref mut inner) => inner.poll(),
|
|
||||||
None => State::NotChanged,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO verify that this is correct
|
|
||||||
pub mod unsync {
|
|
||||||
use super::{Signal, State};
|
|
||||||
use std::rc::{Rc, Weak};
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use futures::task;
|
|
||||||
|
|
||||||
|
|
||||||
struct Inner<A> {
|
|
||||||
value: Option<A>,
|
|
||||||
task: Option<task::Task>,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct Sender<A> {
|
|
||||||
inner: Weak<RefCell<Inner<A>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A> Sender<A> {
|
|
||||||
pub fn set(&self, value: A) -> Result<(), A> {
|
|
||||||
if let Some(inner) = self.inner.upgrade() {
|
|
||||||
let mut inner = inner.borrow_mut();
|
|
||||||
|
|
||||||
inner.value = Some(value);
|
|
||||||
|
|
||||||
if let Some(task) = inner.task.take() {
|
|
||||||
drop(inner);
|
|
||||||
task.notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Err(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Receiver<A> {
|
|
||||||
inner: Rc<RefCell<Inner<A>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A> Signal for Receiver<A> {
|
|
||||||
type Item = A;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn poll(&mut self) -> State<Self::Item> {
|
|
||||||
let mut inner = self.inner.borrow_mut();
|
|
||||||
|
|
||||||
// TODO is this correct ?
|
|
||||||
match inner.value.take() {
|
|
||||||
Some(value) => State::Changed(value),
|
|
||||||
None => {
|
|
||||||
inner.task = Some(task::current());
|
|
||||||
State::NotChanged
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn mutable<A>(initial_value: A) -> (Sender<A>, Receiver<A>) {
|
|
||||||
let inner = Rc::new(RefCell::new(Inner {
|
|
||||||
value: Some(initial_value),
|
|
||||||
task: None,
|
|
||||||
}));
|
|
||||||
|
|
||||||
let sender = Sender {
|
|
||||||
inner: Rc::downgrade(&inner),
|
|
||||||
};
|
|
||||||
|
|
||||||
let receiver = Receiver {
|
|
||||||
inner,
|
|
||||||
};
|
|
||||||
|
|
||||||
(sender, receiver)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO should this be hidden from the docs ?
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
pub fn pair_clone<'a, 'b, A: Clone, B: Clone>(left: &'a mut A, right: &'b mut B) -> (A, 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::map($value, ::std::rc::Rc::new)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! __internal_map2 {
|
|
||||||
($f:expr, $old_pair:pat, $old_expr:expr, { $($lets:stmt);* }, let $name:ident: $t:ty = $value:expr;) => {
|
|
||||||
$crate::Signal::map2(
|
|
||||||
$old_expr,
|
|
||||||
__internal_map_rc_new!($value),
|
|
||||||
|&mut $old_pair, $name| {
|
|
||||||
$($lets;)*
|
|
||||||
let $name: $t = __internal_map_clone!($name);
|
|
||||||
$f
|
|
||||||
}
|
|
||||||
)
|
|
||||||
};
|
|
||||||
($f:expr, $old_pair:pat, $old_expr:expr, { $($lets:stmt);* }, let $name:ident: $t:ty = $value:expr; $($args:tt)+) => {
|
|
||||||
__internal_map2!(
|
|
||||||
$f,
|
|
||||||
($old_pair, ref mut $name),
|
|
||||||
$crate::Signal::map2(
|
|
||||||
$old_expr,
|
|
||||||
__internal_map_rc_new!($value),
|
|
||||||
$crate::pair_clone
|
|
||||||
),
|
|
||||||
{ $($lets;)* let $name: $t = __internal_map_clone!($name) },
|
|
||||||
$($args)+
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! __internal_map {
|
|
||||||
($f:expr, let $name:ident: $t:ty = $value:expr;) => {
|
|
||||||
$crate::Signal::map($value, |$name| {
|
|
||||||
let $name: $t = ::std::rc::Rc::new($name);
|
|
||||||
$f
|
|
||||||
})
|
|
||||||
};
|
|
||||||
($f:expr, let $name1:ident: $t1:ty = $value1:expr;
|
|
||||||
let $name2:ident: $t2:ty = $value2:expr;) => {
|
|
||||||
$crate::Signal::map2(
|
|
||||||
__internal_map_rc_new!($value1),
|
|
||||||
__internal_map_rc_new!($value2),
|
|
||||||
|$name1, $name2| {
|
|
||||||
let $name1: $t1 = __internal_map_clone!($name1);
|
|
||||||
let $name2: $t2 = __internal_map_clone!($name2);
|
|
||||||
$f
|
|
||||||
}
|
|
||||||
)
|
|
||||||
};
|
|
||||||
($f:expr, let $name:ident: $t:ty = $value:expr; $($args:tt)+) => {
|
|
||||||
__internal_map2!(
|
|
||||||
$f,
|
|
||||||
ref mut $name,
|
|
||||||
__internal_map_rc_new!($value),
|
|
||||||
{ let $name: $t = __internal_map_clone!($name) },
|
|
||||||
$($args)+
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! __internal_map_lets {
|
|
||||||
($f:expr, { $($lets:tt)* },) => {
|
|
||||||
__internal_map!($f, $($lets)*)
|
|
||||||
};
|
|
||||||
($f:expr, { $($lets:tt)* }, let $name:ident: $t:ty = $value:expr, $($args:tt)*) => {
|
|
||||||
__internal_map_lets!($f, { $($lets)* let $name: $t = $value; }, $($args)*)
|
|
||||||
};
|
|
||||||
($f:expr, { $($lets:tt)* }, let $name:ident = $value:expr, $($args:tt)*) => {
|
|
||||||
__internal_map_lets!($f, { $($lets)* let $name: ::std::rc::Rc<_> = $value; }, $($args)*)
|
|
||||||
};
|
|
||||||
($f:expr, { $($lets:tt)* }, $name:ident, $($args:tt)*) => {
|
|
||||||
__internal_map_lets!($f, { $($lets)* let $name: ::std::rc::Rc<_> = $name; }, $($args)*)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO this is pretty inefficient, it iterates over the token tree one token at a time
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! __internal_map_split {
|
|
||||||
(($($before:tt)*), => $f:expr) => {
|
|
||||||
__internal_map_lets!($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 {
|
|
||||||
#[test]
|
|
||||||
fn map_macro_ident_1() {
|
|
||||||
let a = super::always(1);
|
|
||||||
|
|
||||||
let mut s = map_rc!(a => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
*a + 1
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(2));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_ident_2() {
|
|
||||||
let a = super::always(1);
|
|
||||||
let b = super::always(2);
|
|
||||||
|
|
||||||
let mut s = map_rc!(a, b => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
let b: ::std::rc::Rc<u32> = b;
|
|
||||||
*a + *b
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(3));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_ident_3() {
|
|
||||||
let a = super::always(1);
|
|
||||||
let b = super::always(2);
|
|
||||||
let c = super::always(3);
|
|
||||||
|
|
||||||
let mut s = map_rc!(a, b, c => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
let b: ::std::rc::Rc<u32> = b;
|
|
||||||
let c: ::std::rc::Rc<u32> = c;
|
|
||||||
*a + *b + *c
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(6));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_ident_4() {
|
|
||||||
let a = super::always(1);
|
|
||||||
let b = super::always(2);
|
|
||||||
let c = super::always(3);
|
|
||||||
let d = super::always(4);
|
|
||||||
|
|
||||||
let mut s = map_rc!(a, b, c, d => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
let b: ::std::rc::Rc<u32> = b;
|
|
||||||
let c: ::std::rc::Rc<u32> = c;
|
|
||||||
let d: ::std::rc::Rc<u32> = d;
|
|
||||||
*a + *b + *c + *d
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(10));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_ident_5() {
|
|
||||||
let a = super::always(1);
|
|
||||||
let b = super::always(2);
|
|
||||||
let c = super::always(3);
|
|
||||||
let d = super::always(4);
|
|
||||||
let e = super::always(5);
|
|
||||||
|
|
||||||
let mut s = map_rc!(a, b, c, d, e => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
let b: ::std::rc::Rc<u32> = b;
|
|
||||||
let c: ::std::rc::Rc<u32> = c;
|
|
||||||
let d: ::std::rc::Rc<u32> = d;
|
|
||||||
let e: ::std::rc::Rc<u32> = e;
|
|
||||||
*a + *b + *c + *d + *e
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(15));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_let_1() {
|
|
||||||
let a2 = super::always(1);
|
|
||||||
|
|
||||||
let mut s = map_rc!(let a = a2 => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
*a + 1
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(2));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_let_2() {
|
|
||||||
let a2 = super::always(1);
|
|
||||||
let b2 = super::always(2);
|
|
||||||
|
|
||||||
let mut s = map_rc!(let a = a2, let b = b2 => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
let b: ::std::rc::Rc<u32> = b;
|
|
||||||
*a + *b
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(3));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_let_3() {
|
|
||||||
let a2 = super::always(1);
|
|
||||||
let b2 = super::always(2);
|
|
||||||
let c2 = super::always(3);
|
|
||||||
|
|
||||||
let mut s = map_rc!(let a = a2, let b = b2, let c = c2 => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
let b: ::std::rc::Rc<u32> = b;
|
|
||||||
let c: ::std::rc::Rc<u32> = c;
|
|
||||||
*a + *b + *c
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(6));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_let_4() {
|
|
||||||
let a2 = super::always(1);
|
|
||||||
let b2 = super::always(2);
|
|
||||||
let c2 = super::always(3);
|
|
||||||
let d2 = super::always(4);
|
|
||||||
|
|
||||||
let mut s = map_rc!(let a = a2, let b = b2, let c = c2, let d = d2 => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
let b: ::std::rc::Rc<u32> = b;
|
|
||||||
let c: ::std::rc::Rc<u32> = c;
|
|
||||||
let d: ::std::rc::Rc<u32> = d;
|
|
||||||
*a + *b + *c + *d
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(10));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_let_5() {
|
|
||||||
let a2 = super::always(1);
|
|
||||||
let b2 = super::always(2);
|
|
||||||
let c2 = super::always(3);
|
|
||||||
let d2 = super::always(4);
|
|
||||||
let e2 = super::always(5);
|
|
||||||
|
|
||||||
let mut s = map_rc!(let a = a2, let b = b2, let c = c2, let d = d2, let e = e2 => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
let b: ::std::rc::Rc<u32> = b;
|
|
||||||
let c: ::std::rc::Rc<u32> = c;
|
|
||||||
let d: ::std::rc::Rc<u32> = d;
|
|
||||||
let e: ::std::rc::Rc<u32> = e;
|
|
||||||
*a + *b + *c + *d + *e
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(15));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_let_type_1() {
|
|
||||||
let a2 = super::always(1);
|
|
||||||
|
|
||||||
let mut s = map_rc! {
|
|
||||||
let a: ::std::rc::Rc<u32> = a2 => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
*a + 1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(2));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_let_type_2() {
|
|
||||||
let a2 = super::always(1);
|
|
||||||
let b2 = super::always(2);
|
|
||||||
|
|
||||||
let mut s = map_rc! {
|
|
||||||
let a: ::std::rc::Rc<u32> = a2,
|
|
||||||
let b: ::std::rc::Rc<u32> = b2 => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
let b: ::std::rc::Rc<u32> = b;
|
|
||||||
*a + *b
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(3));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_let_type_3() {
|
|
||||||
let a2 = super::always(1);
|
|
||||||
let b2 = super::always(2);
|
|
||||||
let c2 = super::always(3);
|
|
||||||
|
|
||||||
let mut s = map_rc! {
|
|
||||||
let a: ::std::rc::Rc<u32> = a2,
|
|
||||||
let b: ::std::rc::Rc<u32> = b2,
|
|
||||||
let c: ::std::rc::Rc<u32> = c2 => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
let b: ::std::rc::Rc<u32> = b;
|
|
||||||
let c: ::std::rc::Rc<u32> = c;
|
|
||||||
*a + *b + *c
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(6));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_let_type_4() {
|
|
||||||
let a2 = super::always(1);
|
|
||||||
let b2 = super::always(2);
|
|
||||||
let c2 = super::always(3);
|
|
||||||
let d2 = super::always(4);
|
|
||||||
|
|
||||||
let mut s = map_rc! {
|
|
||||||
let a: ::std::rc::Rc<u32> = a2,
|
|
||||||
let b: ::std::rc::Rc<u32> = b2,
|
|
||||||
let c: ::std::rc::Rc<u32> = c2,
|
|
||||||
let d: ::std::rc::Rc<u32> = d2 => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
let b: ::std::rc::Rc<u32> = b;
|
|
||||||
let c: ::std::rc::Rc<u32> = c;
|
|
||||||
let d: ::std::rc::Rc<u32> = d;
|
|
||||||
*a + *b + *c + *d
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(10));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_macro_let_type_5() {
|
|
||||||
let a2 = super::always(1);
|
|
||||||
let b2 = super::always(2);
|
|
||||||
let c2 = super::always(3);
|
|
||||||
let d2 = super::always(4);
|
|
||||||
let e2 = super::always(5);
|
|
||||||
|
|
||||||
let mut s = map_rc! {
|
|
||||||
let a: ::std::rc::Rc<u32> = a2,
|
|
||||||
let b: ::std::rc::Rc<u32> = b2,
|
|
||||||
let c: ::std::rc::Rc<u32> = c2,
|
|
||||||
let d: ::std::rc::Rc<u32> = d2,
|
|
||||||
let e: ::std::rc::Rc<u32> = e2 => {
|
|
||||||
let a: ::std::rc::Rc<u32> = a;
|
|
||||||
let b: ::std::rc::Rc<u32> = b;
|
|
||||||
let c: ::std::rc::Rc<u32> = c;
|
|
||||||
let d: ::std::rc::Rc<u32> = d;
|
|
||||||
let e: ::std::rc::Rc<u32> = e;
|
|
||||||
*a + *b + *c + *d + *e
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(15));
|
|
||||||
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,908 @@
|
||||||
|
use std::rc::{Rc, Weak};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use futures::{Async, Poll, task};
|
||||||
|
use futures::future::{Future, IntoFuture};
|
||||||
|
use futures::stream::{Stream, ForEach};
|
||||||
|
use discard::{Discard, DiscardOnDrop};
|
||||||
|
|
||||||
|
|
||||||
|
// TODO add in Done to allow the Signal to end ?
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum State<A> {
|
||||||
|
Changed(A),
|
||||||
|
NotChanged,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> State<A> {
|
||||||
|
#[inline]
|
||||||
|
pub fn map<B, F>(self, f: F) -> State<B> where F: FnOnce(A) -> B {
|
||||||
|
match self {
|
||||||
|
State::Changed(value) => State::Changed(f(value)),
|
||||||
|
State::NotChanged => State::NotChanged,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub trait Signal {
|
||||||
|
type Item;
|
||||||
|
|
||||||
|
fn poll(&mut self) -> State<Self::Item>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_stream(self) -> SignalStream<Self>
|
||||||
|
where Self: Sized {
|
||||||
|
SignalStream {
|
||||||
|
signal: self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn map<A, B>(self, callback: A) -> Map<Self, A>
|
||||||
|
where A: FnMut(Self::Item) -> B,
|
||||||
|
Self: Sized {
|
||||||
|
Map {
|
||||||
|
signal: self,
|
||||||
|
callback,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn map2<A, B, C>(self, other: A, callback: B) -> Map2<Self, A, B>
|
||||||
|
where A: Signal,
|
||||||
|
B: FnMut(&mut Self::Item, &mut A::Item) -> 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(&mut Self::Item) -> B,
|
||||||
|
Self: Sized {
|
||||||
|
MapDedupe {
|
||||||
|
old_value: None,
|
||||||
|
signal: self,
|
||||||
|
callback,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn filter_map<A, B>(self, callback: A) -> FilterMap<Self, A>
|
||||||
|
where A: FnMut(Self::Item) -> Option<B>,
|
||||||
|
Self: Sized {
|
||||||
|
FilterMap {
|
||||||
|
signal: self,
|
||||||
|
callback,
|
||||||
|
first: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn flatten(self) -> Flatten<Self>
|
||||||
|
where Self::Item: Signal,
|
||||||
|
Self: Sized {
|
||||||
|
Flatten {
|
||||||
|
signal: self,
|
||||||
|
inner: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn switch<A, B>(self, callback: A) -> Flatten<Map<Self, A>>
|
||||||
|
where A: FnMut(Self::Item) -> B,
|
||||||
|
B: Signal,
|
||||||
|
Self: Sized {
|
||||||
|
self.map(callback).flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
// TODO file Rust bug about bad error message when `callback` isn't marked as `mut`
|
||||||
|
fn for_each<F, U>(self, callback: F) -> ForEach<SignalStream<Self>, F, U>
|
||||||
|
where F: FnMut(Self::Item) -> U,
|
||||||
|
// TODO allow for errors ?
|
||||||
|
U: IntoFuture<Item = (), Error = ()>,
|
||||||
|
Self:Sized {
|
||||||
|
|
||||||
|
self.to_stream().for_each(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn as_mut(&mut self) -> &mut Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Always<A> {
|
||||||
|
value: Option<A>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> Signal for Always<A> {
|
||||||
|
type Item = A;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll(&mut self) -> State<Self::Item> {
|
||||||
|
match self.value.take() {
|
||||||
|
Some(value) => State::Changed(value),
|
||||||
|
None => State::NotChanged,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn always<A>(value: A) -> Always<A> {
|
||||||
|
Always {
|
||||||
|
value: Some(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct CancelableFutureState {
|
||||||
|
is_cancelled: bool,
|
||||||
|
task: Option<task::Task>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct CancelableFutureHandle {
|
||||||
|
state: Weak<RefCell<CancelableFutureState>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Discard for CancelableFutureHandle {
|
||||||
|
fn discard(self) {
|
||||||
|
if let Some(state) = self.state.upgrade() {
|
||||||
|
let mut borrow = state.borrow_mut();
|
||||||
|
|
||||||
|
borrow.is_cancelled = true;
|
||||||
|
|
||||||
|
if let Some(task) = borrow.task.take() {
|
||||||
|
drop(borrow);
|
||||||
|
task.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct CancelableFuture<A, B> {
|
||||||
|
state: Rc<RefCell<CancelableFutureState>>,
|
||||||
|
future: Option<A>,
|
||||||
|
when_cancelled: Option<B>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B> Future for CancelableFuture<A, B>
|
||||||
|
where A: Future,
|
||||||
|
B: FnOnce(A) -> A::Item {
|
||||||
|
|
||||||
|
type Item = A::Item;
|
||||||
|
type Error = A::Error;
|
||||||
|
|
||||||
|
// TODO should this inline ?
|
||||||
|
#[inline]
|
||||||
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
|
let borrow = self.state.borrow();
|
||||||
|
|
||||||
|
if borrow.is_cancelled {
|
||||||
|
let future = self.future.take().unwrap();
|
||||||
|
let callback = self.when_cancelled.take().unwrap();
|
||||||
|
// TODO figure out how to call the callback immediately when discard is called, e.g. using two Rc<RefCell<>>
|
||||||
|
Ok(Async::Ready(callback(future)))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
drop(borrow);
|
||||||
|
|
||||||
|
match self.future.as_mut().unwrap().poll() {
|
||||||
|
Ok(Async::NotReady) => {
|
||||||
|
self.state.borrow_mut().task = Some(task::current());
|
||||||
|
Ok(Async::NotReady)
|
||||||
|
},
|
||||||
|
a => a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO figure out a more efficient way to implement this
|
||||||
|
// TODO this should be implemented in the futures crate
|
||||||
|
#[inline]
|
||||||
|
pub fn cancelable_future<A, B>(future: A, when_cancelled: B) -> (DiscardOnDrop<CancelableFutureHandle>, CancelableFuture<A, B>)
|
||||||
|
where A: Future,
|
||||||
|
B: FnOnce(A) -> A::Item {
|
||||||
|
|
||||||
|
let state = Rc::new(RefCell::new(CancelableFutureState {
|
||||||
|
is_cancelled: false,
|
||||||
|
task: None,
|
||||||
|
}));
|
||||||
|
|
||||||
|
let cancel_handle = DiscardOnDrop::new(CancelableFutureHandle {
|
||||||
|
state: Rc::downgrade(&state),
|
||||||
|
});
|
||||||
|
|
||||||
|
let cancel_future = CancelableFuture {
|
||||||
|
state,
|
||||||
|
future: Some(future),
|
||||||
|
when_cancelled: Some(when_cancelled),
|
||||||
|
};
|
||||||
|
|
||||||
|
(cancel_handle, cancel_future)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct SignalStream<A> {
|
||||||
|
signal: A,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Signal> Stream for SignalStream<A> {
|
||||||
|
type Item = A::Item;
|
||||||
|
// TODO use Void instead ?
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||||
|
Ok(match self.signal.poll() {
|
||||||
|
State::Changed(value) => Async::Ready(Some(value)),
|
||||||
|
State::NotChanged => Async::NotReady,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Map<A, B> {
|
||||||
|
signal: A,
|
||||||
|
callback: B,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, C> Signal for Map<A, B>
|
||||||
|
where A: Signal,
|
||||||
|
B: FnMut(A::Item) -> C {
|
||||||
|
type Item = C;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll(&mut self) -> State<Self::Item> {
|
||||||
|
self.signal.poll().map(|value| (self.callback)(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Map2<A: Signal, B: Signal, C> {
|
||||||
|
signal1: A,
|
||||||
|
signal2: B,
|
||||||
|
callback: C,
|
||||||
|
left: Option<A::Item>,
|
||||||
|
right: Option<B::Item>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, C, D> Signal for Map2<A, B, C>
|
||||||
|
where A: Signal,
|
||||||
|
B: Signal,
|
||||||
|
C: FnMut(&mut A::Item, &mut B::Item) -> D {
|
||||||
|
type Item = D;
|
||||||
|
|
||||||
|
// TODO inline this ?
|
||||||
|
fn poll(&mut self) -> State<Self::Item> {
|
||||||
|
match self.signal1.poll() {
|
||||||
|
State::Changed(mut left) => {
|
||||||
|
let output = match self.signal2.poll() {
|
||||||
|
State::Changed(mut right) => {
|
||||||
|
let output = State::Changed((self.callback)(&mut left, &mut right));
|
||||||
|
self.right = Some(right);
|
||||||
|
output
|
||||||
|
},
|
||||||
|
|
||||||
|
State::NotChanged => match self.right {
|
||||||
|
Some(ref mut right) => State::Changed((self.callback)(&mut left, right)),
|
||||||
|
None => State::NotChanged,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
self.left = Some(left);
|
||||||
|
|
||||||
|
output
|
||||||
|
},
|
||||||
|
|
||||||
|
State::NotChanged => match self.left {
|
||||||
|
Some(ref mut left) => match self.signal2.poll() {
|
||||||
|
State::Changed(mut right) => {
|
||||||
|
let output = State::Changed((self.callback)(left, &mut right));
|
||||||
|
self.right = Some(right);
|
||||||
|
output
|
||||||
|
},
|
||||||
|
|
||||||
|
State::NotChanged => State::NotChanged,
|
||||||
|
},
|
||||||
|
|
||||||
|
None => State::NotChanged,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct MapDedupe<A: Signal, B> {
|
||||||
|
old_value: Option<A::Item>,
|
||||||
|
signal: A,
|
||||||
|
callback: B,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, C> Signal for MapDedupe<A, B>
|
||||||
|
where A: Signal,
|
||||||
|
A::Item: PartialEq,
|
||||||
|
// TODO should this use Fn instead ?
|
||||||
|
B: FnMut(&A::Item) -> C {
|
||||||
|
|
||||||
|
type Item = C;
|
||||||
|
|
||||||
|
// TODO should this use #[inline] ?
|
||||||
|
fn poll(&mut self) -> State<Self::Item> {
|
||||||
|
loop {
|
||||||
|
match self.signal.poll() {
|
||||||
|
State::Changed(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)(&mut value);
|
||||||
|
self.old_value = Some(value);
|
||||||
|
return State::Changed(output);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State::NotChanged => return State::NotChanged,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct FilterMap<A, B> {
|
||||||
|
signal: A,
|
||||||
|
callback: B,
|
||||||
|
first: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, C> Signal for FilterMap<A, B>
|
||||||
|
where A: Signal,
|
||||||
|
B: FnMut(A::Item) -> Option<C> {
|
||||||
|
type Item = Option<C>;
|
||||||
|
|
||||||
|
// TODO should this use #[inline] ?
|
||||||
|
#[inline]
|
||||||
|
fn poll(&mut self) -> State<Self::Item> {
|
||||||
|
loop {
|
||||||
|
match self.signal.poll() {
|
||||||
|
State::Changed(value) => match (self.callback)(value) {
|
||||||
|
Some(value) => {
|
||||||
|
self.first = false;
|
||||||
|
return State::Changed(Some(value));
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
if self.first {
|
||||||
|
self.first = false;
|
||||||
|
return State::Changed(None);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
State::NotChanged => return State::NotChanged,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Flatten<A: Signal> {
|
||||||
|
signal: A,
|
||||||
|
inner: Option<A::Item>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> Signal for Flatten<A>
|
||||||
|
where A: Signal,
|
||||||
|
A::Item: Signal {
|
||||||
|
type Item = <<A as Signal>::Item as Signal>::Item;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll(&mut self) -> State<Self::Item> {
|
||||||
|
match self.signal.poll() {
|
||||||
|
State::Changed(mut inner) => {
|
||||||
|
let poll = inner.poll();
|
||||||
|
self.inner = Some(inner);
|
||||||
|
poll
|
||||||
|
},
|
||||||
|
|
||||||
|
State::NotChanged => match self.inner {
|
||||||
|
Some(ref mut inner) => inner.poll(),
|
||||||
|
None => State::NotChanged,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO verify that this is correct
|
||||||
|
pub mod unsync {
|
||||||
|
use super::{Signal, State};
|
||||||
|
use std::rc::{Rc, Weak};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use futures::task;
|
||||||
|
|
||||||
|
|
||||||
|
struct Inner<A> {
|
||||||
|
value: Option<A>,
|
||||||
|
task: Option<task::Task>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Sender<A> {
|
||||||
|
inner: Weak<RefCell<Inner<A>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> Sender<A> {
|
||||||
|
pub fn set(&self, value: A) -> Result<(), A> {
|
||||||
|
if let Some(inner) = self.inner.upgrade() {
|
||||||
|
let mut inner = inner.borrow_mut();
|
||||||
|
|
||||||
|
inner.value = Some(value);
|
||||||
|
|
||||||
|
if let Some(task) = inner.task.take() {
|
||||||
|
drop(inner);
|
||||||
|
task.notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Err(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Receiver<A> {
|
||||||
|
inner: Rc<RefCell<Inner<A>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> Signal for Receiver<A> {
|
||||||
|
type Item = A;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll(&mut self) -> State<Self::Item> {
|
||||||
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
|
||||||
|
// TODO is this correct ?
|
||||||
|
match inner.value.take() {
|
||||||
|
Some(value) => State::Changed(value),
|
||||||
|
None => {
|
||||||
|
inner.task = Some(task::current());
|
||||||
|
State::NotChanged
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn mutable<A>(initial_value: A) -> (Sender<A>, Receiver<A>) {
|
||||||
|
let inner = Rc::new(RefCell::new(Inner {
|
||||||
|
value: Some(initial_value),
|
||||||
|
task: None,
|
||||||
|
}));
|
||||||
|
|
||||||
|
let sender = Sender {
|
||||||
|
inner: Rc::downgrade(&inner),
|
||||||
|
};
|
||||||
|
|
||||||
|
let receiver = Receiver {
|
||||||
|
inner,
|
||||||
|
};
|
||||||
|
|
||||||
|
(sender, receiver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO should this be hidden from the docs ?
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline]
|
||||||
|
pub fn pair_clone<'a, 'b, A: Clone, B: Clone>(left: &'a mut A, right: &'b mut B) -> (A, 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_map2 {
|
||||||
|
($f:expr, $old_pair:pat, $old_expr:expr, { $($lets:stmt);* }, let $name:ident: $t:ty = $value:expr;) => {
|
||||||
|
$crate::signal::Signal::map2(
|
||||||
|
$old_expr,
|
||||||
|
__internal_map_rc_new!($value),
|
||||||
|
|&mut $old_pair, $name| {
|
||||||
|
$($lets;)*
|
||||||
|
let $name: $t = __internal_map_clone!($name);
|
||||||
|
$f
|
||||||
|
}
|
||||||
|
)
|
||||||
|
};
|
||||||
|
($f:expr, $old_pair:pat, $old_expr:expr, { $($lets:stmt);* }, let $name:ident: $t:ty = $value:expr; $($args:tt)+) => {
|
||||||
|
__internal_map2!(
|
||||||
|
$f,
|
||||||
|
($old_pair, ref mut $name),
|
||||||
|
$crate::signal::Signal::map2(
|
||||||
|
$old_expr,
|
||||||
|
__internal_map_rc_new!($value),
|
||||||
|
$crate::signal::pair_clone
|
||||||
|
),
|
||||||
|
{ $($lets;)* let $name: $t = __internal_map_clone!($name) },
|
||||||
|
$($args)+
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! __internal_map {
|
||||||
|
($f:expr, let $name:ident: $t:ty = $value:expr;) => {
|
||||||
|
$crate::signal::Signal::map($value, |$name| {
|
||||||
|
let $name: $t = ::std::rc::Rc::new($name);
|
||||||
|
$f
|
||||||
|
})
|
||||||
|
};
|
||||||
|
($f:expr, let $name1:ident: $t1:ty = $value1:expr;
|
||||||
|
let $name2:ident: $t2:ty = $value2:expr;) => {
|
||||||
|
$crate::signal::Signal::map2(
|
||||||
|
__internal_map_rc_new!($value1),
|
||||||
|
__internal_map_rc_new!($value2),
|
||||||
|
|$name1, $name2| {
|
||||||
|
let $name1: $t1 = __internal_map_clone!($name1);
|
||||||
|
let $name2: $t2 = __internal_map_clone!($name2);
|
||||||
|
$f
|
||||||
|
}
|
||||||
|
)
|
||||||
|
};
|
||||||
|
($f:expr, let $name:ident: $t:ty = $value:expr; $($args:tt)+) => {
|
||||||
|
__internal_map2!(
|
||||||
|
$f,
|
||||||
|
ref mut $name,
|
||||||
|
__internal_map_rc_new!($value),
|
||||||
|
{ let $name: $t = __internal_map_clone!($name) },
|
||||||
|
$($args)+
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! __internal_map_lets {
|
||||||
|
($f:expr, { $($lets:tt)* },) => {
|
||||||
|
__internal_map!($f, $($lets)*)
|
||||||
|
};
|
||||||
|
($f:expr, { $($lets:tt)* }, let $name:ident: $t:ty = $value:expr, $($args:tt)*) => {
|
||||||
|
__internal_map_lets!($f, { $($lets)* let $name: $t = $value; }, $($args)*)
|
||||||
|
};
|
||||||
|
($f:expr, { $($lets:tt)* }, let $name:ident = $value:expr, $($args:tt)*) => {
|
||||||
|
__internal_map_lets!($f, { $($lets)* let $name: ::std::rc::Rc<_> = $value; }, $($args)*)
|
||||||
|
};
|
||||||
|
($f:expr, { $($lets:tt)* }, $name:ident, $($args:tt)*) => {
|
||||||
|
__internal_map_lets!($f, { $($lets)* let $name: ::std::rc::Rc<_> = $name; }, $($args)*)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO this is pretty inefficient, it iterates over the token tree one token at a time
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! __internal_map_split {
|
||||||
|
(($($before:tt)*), => $f:expr) => {
|
||||||
|
__internal_map_lets!($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 {
|
||||||
|
#[test]
|
||||||
|
fn map_macro_ident_1() {
|
||||||
|
let a = super::always(1);
|
||||||
|
|
||||||
|
let mut s = map_rc!(a => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
*a + 1
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(2));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_ident_2() {
|
||||||
|
let a = super::always(1);
|
||||||
|
let b = super::always(2);
|
||||||
|
|
||||||
|
let mut s = map_rc!(a, b => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
let b: ::std::rc::Rc<u32> = b;
|
||||||
|
*a + *b
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(3));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_ident_3() {
|
||||||
|
let a = super::always(1);
|
||||||
|
let b = super::always(2);
|
||||||
|
let c = super::always(3);
|
||||||
|
|
||||||
|
let mut s = map_rc!(a, b, c => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
let b: ::std::rc::Rc<u32> = b;
|
||||||
|
let c: ::std::rc::Rc<u32> = c;
|
||||||
|
*a + *b + *c
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(6));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_ident_4() {
|
||||||
|
let a = super::always(1);
|
||||||
|
let b = super::always(2);
|
||||||
|
let c = super::always(3);
|
||||||
|
let d = super::always(4);
|
||||||
|
|
||||||
|
let mut s = map_rc!(a, b, c, d => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
let b: ::std::rc::Rc<u32> = b;
|
||||||
|
let c: ::std::rc::Rc<u32> = c;
|
||||||
|
let d: ::std::rc::Rc<u32> = d;
|
||||||
|
*a + *b + *c + *d
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(10));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_ident_5() {
|
||||||
|
let a = super::always(1);
|
||||||
|
let b = super::always(2);
|
||||||
|
let c = super::always(3);
|
||||||
|
let d = super::always(4);
|
||||||
|
let e = super::always(5);
|
||||||
|
|
||||||
|
let mut s = map_rc!(a, b, c, d, e => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
let b: ::std::rc::Rc<u32> = b;
|
||||||
|
let c: ::std::rc::Rc<u32> = c;
|
||||||
|
let d: ::std::rc::Rc<u32> = d;
|
||||||
|
let e: ::std::rc::Rc<u32> = e;
|
||||||
|
*a + *b + *c + *d + *e
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(15));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_let_1() {
|
||||||
|
let a2 = super::always(1);
|
||||||
|
|
||||||
|
let mut s = map_rc!(let a = a2 => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
*a + 1
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(2));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_let_2() {
|
||||||
|
let a2 = super::always(1);
|
||||||
|
let b2 = super::always(2);
|
||||||
|
|
||||||
|
let mut s = map_rc!(let a = a2, let b = b2 => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
let b: ::std::rc::Rc<u32> = b;
|
||||||
|
*a + *b
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(3));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_let_3() {
|
||||||
|
let a2 = super::always(1);
|
||||||
|
let b2 = super::always(2);
|
||||||
|
let c2 = super::always(3);
|
||||||
|
|
||||||
|
let mut s = map_rc!(let a = a2, let b = b2, let c = c2 => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
let b: ::std::rc::Rc<u32> = b;
|
||||||
|
let c: ::std::rc::Rc<u32> = c;
|
||||||
|
*a + *b + *c
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(6));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_let_4() {
|
||||||
|
let a2 = super::always(1);
|
||||||
|
let b2 = super::always(2);
|
||||||
|
let c2 = super::always(3);
|
||||||
|
let d2 = super::always(4);
|
||||||
|
|
||||||
|
let mut s = map_rc!(let a = a2, let b = b2, let c = c2, let d = d2 => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
let b: ::std::rc::Rc<u32> = b;
|
||||||
|
let c: ::std::rc::Rc<u32> = c;
|
||||||
|
let d: ::std::rc::Rc<u32> = d;
|
||||||
|
*a + *b + *c + *d
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(10));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_let_5() {
|
||||||
|
let a2 = super::always(1);
|
||||||
|
let b2 = super::always(2);
|
||||||
|
let c2 = super::always(3);
|
||||||
|
let d2 = super::always(4);
|
||||||
|
let e2 = super::always(5);
|
||||||
|
|
||||||
|
let mut s = map_rc!(let a = a2, let b = b2, let c = c2, let d = d2, let e = e2 => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
let b: ::std::rc::Rc<u32> = b;
|
||||||
|
let c: ::std::rc::Rc<u32> = c;
|
||||||
|
let d: ::std::rc::Rc<u32> = d;
|
||||||
|
let e: ::std::rc::Rc<u32> = e;
|
||||||
|
*a + *b + *c + *d + *e
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(15));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_let_type_1() {
|
||||||
|
let a2 = super::always(1);
|
||||||
|
|
||||||
|
let mut s = map_rc! {
|
||||||
|
let a: ::std::rc::Rc<u32> = a2 => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
*a + 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(2));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_let_type_2() {
|
||||||
|
let a2 = super::always(1);
|
||||||
|
let b2 = super::always(2);
|
||||||
|
|
||||||
|
let mut s = map_rc! {
|
||||||
|
let a: ::std::rc::Rc<u32> = a2,
|
||||||
|
let b: ::std::rc::Rc<u32> = b2 => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
let b: ::std::rc::Rc<u32> = b;
|
||||||
|
*a + *b
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(3));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_let_type_3() {
|
||||||
|
let a2 = super::always(1);
|
||||||
|
let b2 = super::always(2);
|
||||||
|
let c2 = super::always(3);
|
||||||
|
|
||||||
|
let mut s = map_rc! {
|
||||||
|
let a: ::std::rc::Rc<u32> = a2,
|
||||||
|
let b: ::std::rc::Rc<u32> = b2,
|
||||||
|
let c: ::std::rc::Rc<u32> = c2 => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
let b: ::std::rc::Rc<u32> = b;
|
||||||
|
let c: ::std::rc::Rc<u32> = c;
|
||||||
|
*a + *b + *c
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(6));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_let_type_4() {
|
||||||
|
let a2 = super::always(1);
|
||||||
|
let b2 = super::always(2);
|
||||||
|
let c2 = super::always(3);
|
||||||
|
let d2 = super::always(4);
|
||||||
|
|
||||||
|
let mut s = map_rc! {
|
||||||
|
let a: ::std::rc::Rc<u32> = a2,
|
||||||
|
let b: ::std::rc::Rc<u32> = b2,
|
||||||
|
let c: ::std::rc::Rc<u32> = c2,
|
||||||
|
let d: ::std::rc::Rc<u32> = d2 => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
let b: ::std::rc::Rc<u32> = b;
|
||||||
|
let c: ::std::rc::Rc<u32> = c;
|
||||||
|
let d: ::std::rc::Rc<u32> = d;
|
||||||
|
*a + *b + *c + *d
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(10));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_macro_let_type_5() {
|
||||||
|
let a2 = super::always(1);
|
||||||
|
let b2 = super::always(2);
|
||||||
|
let c2 = super::always(3);
|
||||||
|
let d2 = super::always(4);
|
||||||
|
let e2 = super::always(5);
|
||||||
|
|
||||||
|
let mut s = map_rc! {
|
||||||
|
let a: ::std::rc::Rc<u32> = a2,
|
||||||
|
let b: ::std::rc::Rc<u32> = b2,
|
||||||
|
let c: ::std::rc::Rc<u32> = c2,
|
||||||
|
let d: ::std::rc::Rc<u32> = d2,
|
||||||
|
let e: ::std::rc::Rc<u32> = e2 => {
|
||||||
|
let a: ::std::rc::Rc<u32> = a;
|
||||||
|
let b: ::std::rc::Rc<u32> = b;
|
||||||
|
let c: ::std::rc::Rc<u32> = c;
|
||||||
|
let d: ::std::rc::Rc<u32> = d;
|
||||||
|
let e: ::std::rc::Rc<u32> = e;
|
||||||
|
*a + *b + *c + *d + *e
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::Changed(15));
|
||||||
|
assert_eq!(super::Signal::poll(&mut s), super::State::NotChanged);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
use futures::Async;
|
||||||
|
//use std::iter::Iterator;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ListChange<A> {
|
||||||
|
Replace {
|
||||||
|
values: Vec<A>,
|
||||||
|
},
|
||||||
|
|
||||||
|
InsertAt {
|
||||||
|
index: usize,
|
||||||
|
value: A,
|
||||||
|
},
|
||||||
|
|
||||||
|
RemoveAt {
|
||||||
|
index: usize,
|
||||||
|
},
|
||||||
|
|
||||||
|
Swap {
|
||||||
|
old_index: usize,
|
||||||
|
new_index: usize,
|
||||||
|
},
|
||||||
|
|
||||||
|
Push {
|
||||||
|
value: A,
|
||||||
|
},
|
||||||
|
|
||||||
|
Pop {},
|
||||||
|
|
||||||
|
Clear {},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> ListChange<A> {
|
||||||
|
// TODO inline this ?
|
||||||
|
fn map<B, F>(self, mut callback: F) -> ListChange<B> where F: FnMut(A) -> B {
|
||||||
|
match self {
|
||||||
|
// TODO figure out a more efficient way of implementing this
|
||||||
|
ListChange::Replace { values } => ListChange::Replace { values: values.into_iter().map(callback).collect() },
|
||||||
|
ListChange::InsertAt { index, value } => ListChange::InsertAt { index, value: callback(value) },
|
||||||
|
ListChange::RemoveAt { index } => ListChange::RemoveAt { index },
|
||||||
|
ListChange::Swap { old_index, new_index } => ListChange::Swap { old_index, new_index },
|
||||||
|
ListChange::Push { value } => ListChange::Push { value: callback(value) },
|
||||||
|
ListChange::Pop {} => ListChange::Pop {},
|
||||||
|
ListChange::Clear {} => ListChange::Clear {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub trait SignalList {
|
||||||
|
type Item;
|
||||||
|
|
||||||
|
fn poll(&mut self) -> Async<Option<ListChange<Self::Item>>>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn map<A, F>(self, callback: F) -> Map<Self, F>
|
||||||
|
where F: FnMut(Self::Item) -> A,
|
||||||
|
Self: Sized {
|
||||||
|
Map {
|
||||||
|
signal: self,
|
||||||
|
callback,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*#[inline]
|
||||||
|
fn filter_map<A, F>(self, callback: F) -> Map<Self, F>
|
||||||
|
where F: FnMut(Self::Item) -> A,
|
||||||
|
Self: Sized {
|
||||||
|
Map {
|
||||||
|
signal: self,
|
||||||
|
callback,
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn as_mut(&mut self) -> &mut Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Map<A, B> {
|
||||||
|
signal: A,
|
||||||
|
callback: B,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, F> SignalList for Map<A, F>
|
||||||
|
where A: SignalList,
|
||||||
|
F: FnMut(A::Item) -> B {
|
||||||
|
type Item = B;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll(&mut self) -> Async<Option<ListChange<Self::Item>>> {
|
||||||
|
self.signal.poll().map(|some| some.map(|change| change.map(|value| (self.callback)(value))))
|
||||||
|
}
|
||||||
|
}
|
|
@ -194,7 +194,7 @@ pub fn insert_children_signal<A, B, C>(element: &A, callbacks: &mut Callbacks, s
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn insert_children_slice<A: INode>(element: &A, callbacks: &mut Callbacks, value: &mut [Dom]) {
|
pub fn insert_children_iter<'a, A: INode, B: IntoIterator<Item = &'a mut Dom>>(element: &A, callbacks: &mut Callbacks, value: B) {
|
||||||
for dom in value.into_iter() {
|
for dom in value.into_iter() {
|
||||||
callbacks.after_insert.append(&mut dom.callbacks.after_insert);
|
callbacks.after_insert.append(&mut dom.callbacks.after_insert);
|
||||||
callbacks.after_remove.append(&mut dom.callbacks.after_remove);
|
callbacks.after_remove.append(&mut dom.callbacks.after_remove);
|
||||||
|
|
|
@ -92,10 +92,10 @@ impl Focused for bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO figure out how to make this owned rather than &mut
|
// TODO figure out how to make this owned rather than &mut
|
||||||
impl<'a> Children for &'a mut [Dom] {
|
impl<'a, A: IntoIterator<Item = &'a mut Dom>> Children for A {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn insert_children<A: INode>(self, element: &A, callbacks: &mut Callbacks) {
|
fn insert_children<B: INode>(self, element: &B, callbacks: &mut Callbacks) {
|
||||||
operations::insert_children_slice(element, callbacks, self)
|
operations::insert_children_iter(element, callbacks, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue