diff --git a/TODO.md b/TODO.md index ff7b2f6e..f69987a0 100644 --- a/TODO.md +++ b/TODO.md @@ -292,6 +292,7 @@ - [X] Rename `RecurringTask` to `Sub` - [ ] enum Task{Cmd,Sub} into one unified type. - Sauron just consilidate them into one enum struct for simplicity +- [ ] Remove `Modifier` and `measurements` ## Features - [X] Storage service (May not be needed since the user can directly use web-sys) diff --git a/crates/core/src/dom/dispatch.rs b/crates/core/src/dom/dispatch.rs index 99281f3b..27f781eb 100644 --- a/crates/core/src/dom/dispatch.rs +++ b/crates/core/src/dom/dispatch.rs @@ -139,6 +139,7 @@ where } } + impl From for Dispatch where APP: Application, @@ -153,13 +154,17 @@ impl From> for Dispatch where APP: Application, { - fn from(mut task: Task) -> Self { - Dispatch::new(move |mut program| { - spawn_local(async move { - while let Some(msg) = task.next().await { - program.dispatch(msg) - } - }); + fn from(task: Task) -> Self { + Dispatch::new(move |program| { + for mut command in task.commands.into_iter(){ + let program = program.downgrade(); + spawn_local(async move { + let mut program = program.upgrade().expect("upgrade"); + while let Some(msg) = command.next().await { + program.dispatch(msg) + } + }); + } }) } } diff --git a/crates/core/src/dom/task.rs b/crates/core/src/dom/task.rs index a675d784..745940a9 100644 --- a/crates/core/src/dom/task.rs +++ b/crates/core/src/dom/task.rs @@ -5,15 +5,22 @@ use futures::channel::mpsc::UnboundedReceiver; use futures::StreamExt; use std::future::Future; use std::pin::Pin; +use crate::dom::Effects; /// encapsulate anything a component can do -pub enum Task { +pub enum Command { /// A task with one single resulting MSG - Single(SingleTask), + Action(Action), /// A task with recurring resulting MSG Sub(Sub), } +/// +pub struct Task{ + /// commands + pub(crate) commands: Vec>, +} + impl Task where MSG: 'static, @@ -23,7 +30,67 @@ where where F: Future + 'static, { - Self::Single(SingleTask::new(f)) + Self{ + commands: vec![Command::single(f)] + } + } + /// + pub fn sub(rx: UnboundedReceiver, event_closure: EventClosure) -> Self { + Self{ + commands: vec![Command::sub(rx, event_closure)], + } + } + + /// map the msg of this Task such that Task becomes Task. + pub fn map_msg(self, f: F) -> Task + where + F: Fn(MSG) -> MSG2 + 'static + Clone, + MSG2: 'static, + { + Task{ + commands: self.commands.into_iter().map(|t|t.map_msg(f.clone())).collect(), + } + } + + /// batch together multiple Task into one task + pub fn batch(tasks: impl IntoIterator) -> Self { + let mut commands = vec![]; + for task in tasks.into_iter(){ + commands.extend(task.commands); + } + Self {commands} + } + +} + +impl From> for Task + where MSG: 'static +{ + /// Convert Effects that has only follow ups + fn from(effects: Effects) -> Self { + // we can safely ignore the effects here + // as there is no content on it. + let Effects { + local, + external, + modifier:_, + } = effects; + + Task::batch(local.into_iter().chain(external.into_iter()).map(Task::from)) + } +} + + +impl Command +where + MSG: 'static, +{ + /// + pub fn single(f: F) -> Self + where + F: Future + 'static, + { + Self::Action(Action::new(f)) } /// pub fn sub(rx: UnboundedReceiver, event_closure: EventClosure) -> Self { @@ -34,28 +101,28 @@ where } /// apply a function to the msg to create a different task which has a different msg - pub fn map_msg(self, f: F) -> Task + pub fn map_msg(self, f: F) -> Command where F: Fn(MSG) -> MSG2 + 'static, MSG2: 'static, { match self { - Self::Single(task) => Task::Single(task.map_msg(f)), - Self::Sub(task) => Task::Sub(task.map_msg(f)), + Self::Action(task) => Command::Action(task.map_msg(f)), + Self::Sub(task) => Command::Sub(task.map_msg(f)), } } /// return the next value pub async fn next(&mut self) -> Option { match self { - Self::Single(task) => task.next().await, + Self::Action(task) => task.next().await, Self::Sub(task) => task.next().await, } } } -/// SingleTask is used to do asynchronous operations -pub struct SingleTask { +/// Action is used to do asynchronous operations +pub struct Action { task: Pin>>, /// a marker to indicate if the value of the future is awaited. /// any attempt to await it again will error, @@ -63,7 +130,7 @@ pub struct SingleTask { done: bool, } -impl SingleTask +impl Action where MSG: 'static, { @@ -80,13 +147,13 @@ where /// apply a function to the msg to create a different task which has a different msg - fn map_msg(self, f: F) -> SingleTask + fn map_msg(self, f: F) -> Action where F: Fn(MSG) -> MSG2 + 'static, MSG2: 'static, { let task = self.task; - SingleTask::new(async move { + Action::new(async move { let msg = task.await; f(msg) }) @@ -106,13 +173,13 @@ where } } -impl From for SingleTask +impl From for Action where F: Future + 'static, MSG: 'static, { fn from(f: F) -> Self { - SingleTask::new(f) + Action::new(f) } }