diff --git a/examples/todomvc.rs b/examples/todomvc.rs index a28059c3e..d7126cb4c 100644 --- a/examples/todomvc.rs +++ b/examples/todomvc.rs @@ -3,8 +3,8 @@ use dioxus::prelude::*; use im_rc::HashMap; use std::rc::Rc; -fn main() -> anyhow::Result<()> { - dioxus::desktop::launch(App, |c| c) +fn main() { + dioxus::desktop::launch(App, |c| c); } #[derive(PartialEq)] diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index bb959fe45..69584d749 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -330,9 +330,6 @@ impl<'bump> DiffMachine<'bump> { } if !children.is_empty() { - // self.stack.element_id_stack.push(real_id); - // push our element_id onto the stack - // drop our element off the stack self.stack.create_children(children, MountType::Append); } } @@ -543,11 +540,15 @@ impl<'bump> DiffMachine<'bump> { } } - if has_comitted { - self.mutations.pop(); + if old.children.len() == 0 && new.children.len() != 0 { + please_commit(&mut self.mutations.edits); + self.stack.create_children(new.children, MountType::Append); + } else { + self.diff_children(old.children, new.children); + if has_comitted { + self.mutations.pop(); + } } - - self.diff_children(old.children, new.children); } fn diff_component_nodes( @@ -601,6 +602,9 @@ impl<'bump> DiffMachine<'bump> { return; } + debug_assert!(old.children.len() != 0); + debug_assert!(new.children.len() != 0); + self.diff_children(old.children, new.children); } @@ -633,6 +637,7 @@ impl<'bump> DiffMachine<'bump> { match (old, new) { ([], []) => {} ([], _) => { + // we need to push the self.stack.create_children(new, MountType::Append); } (_, []) => { @@ -761,13 +766,57 @@ impl<'bump> DiffMachine<'bump> { right_offset, ); + log::debug!("stack before lo is {:#?}", self.stack.instructions); // Ok, we now hopefully have a smaller range of children in the middle // within which to re-order nodes with the same keys, remove old nodes with // now-unused keys, and create new nodes with fresh keys. - self.diff_keyed_middle( - &old[left_offset..(old.len() - right_offset)], - &new[left_offset..(new.len() - right_offset)], + + let old_middle = &old[left_offset..(old.len() - right_offset)]; + let new_middle = &new[left_offset..(new.len() - right_offset)]; + + debug_assert!( + !((old_middle.len() == new_middle.len()) && old_middle.len() == 0), + "keyed children must have the same number of children" ); + if new_middle.len() == 0 { + // remove the old elements + self.remove_nodes(old_middle); + } else if old_middle.len() == 0 { + // there were no old elements, so just create the new elements + // we need to find the right "foothold" though - we shouldnt use the "append" at all + if left_offset == 0 { + // insert at the beginning of the old list + let foothold = &old[old.len() - right_offset]; + self.stack.create_children( + new_middle, + MountType::InsertBefore { + other_node: foothold, + }, + ); + } else if right_offset == 0 { + // insert at the end the old list + let foothold = old.last().unwrap(); + self.stack.create_children( + new_middle, + MountType::InsertAfter { + other_node: foothold, + }, + ); + } else { + // inserting in the middle + let foothold = &old[left_offset - 1]; + self.stack.create_children( + new_middle, + MountType::InsertAfter { + other_node: foothold, + }, + ); + } + } else { + self.diff_keyed_middle(old_middle, new_middle); + } + + log::debug!("stack after km is {:#?}", self.stack.instructions); } /// Diff both ends of the children that share keys. @@ -893,6 +942,14 @@ impl<'bump> DiffMachine<'bump> { // If none of the old keys are reused by the new children, then we remove all the remaining old children and // create the new children afresh. if shared_keys.is_empty() { + log::debug!( + "no shared keys, replacing and creating many with many, {:#?}, {:#?}", + old, + new + ); + log::debug!("old_key_to_old_index, {:#?}", old_key_to_old_index); + log::debug!("new_index_to_old_index, {:#?}", new_index_to_old_index); + log::debug!("shared_keys, {:#?}", shared_keys); self.replace_and_create_many_with_many(old, new); return; } diff --git a/packages/core/src/diff_stack.rs b/packages/core/src/diff_stack.rs index 3d8d6e81f..480712df2 100644 --- a/packages/core/src/diff_stack.rs +++ b/packages/core/src/diff_stack.rs @@ -36,7 +36,7 @@ pub enum MountType<'a> { } pub(crate) struct DiffStack<'bump> { - instructions: Vec>, + pub(crate) instructions: Vec>, nodes_created_stack: SmallVec<[usize; 10]>, pub scope_stack: SmallVec<[ScopeId; 5]>, } diff --git a/packages/core/src/scheduler.rs b/packages/core/src/scheduler.rs index f774ae6f3..3f2c09a15 100644 --- a/packages/core/src/scheduler.rs +++ b/packages/core/src/scheduler.rs @@ -107,8 +107,6 @@ pub enum SchedulerMsg { } pub enum TaskMsg { - // SubmitTask(FiberTask, u64), - // SubmitTask(FiberTask, u64), ToggleTask(u64), PauseTask(u64), ResumeTask(u64), @@ -322,6 +320,9 @@ impl Scheduler { unsafe fn load_work(&mut self) -> SavedDiffWork<'static> { self.saved_state.take().unwrap().extend() } + pub fn handle_task(&mut self, evt: TaskMsg) { + // + } pub fn handle_channel_msg(&mut self, msg: SchedulerMsg) { match msg { @@ -480,6 +481,18 @@ impl Scheduler { let mut committed_mutations = Vec::>::new(); while self.has_any_work() { + while let Ok(Some(msg)) = self.receiver.try_next() { + match msg { + SchedulerMsg::Task(t) => todo!(), + SchedulerMsg::Immediate(im) => { + self.dirty_scopes.insert(im); + } + SchedulerMsg::UiEvent(evt) => { + self.ui_events.push_back(evt); + } + } + } + // switch our priority, pop off any work while let Some(event) = self.ui_events.pop_front() { if let Some(scope) = self.pool.get_scope_mut(event.scope) { diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 153933e0c..55857e091 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -360,25 +360,21 @@ impl VirtualDom { /// Waits for the scheduler to have work /// This lets us poll async tasks during idle periods without blocking the main thread. pub async fn wait_for_work(&mut self) { + // todo: poll the events once even if there is work to do to prevent starvation if self.scheduler.has_any_work() { - log::debug!("No need to wait for work, we already have some"); return; } - log::debug!("No active work.... waiting for some..."); use futures_util::StreamExt; - // right now this won't poll events if there is ongoing work - // in the future we want to prioritize some events over ongoing work - // this is coming in the "priorities" PR - // Wait for any new events if we have nothing to do - // todo: poll the events once even if there is work to do to prevent starvation futures_util::select! { _ = self.scheduler.async_tasks.next() => {} msg = self.scheduler.receiver.next() => { match msg.unwrap() { - SchedulerMsg::Task(t) => todo!(), + SchedulerMsg::Task(t) => { + self.scheduler.handle_task(t); + }, SchedulerMsg::Immediate(im) => { self.scheduler.dirty_scopes.insert(im); } @@ -388,18 +384,6 @@ impl VirtualDom { } }, } - - while let Ok(Some(msg)) = self.scheduler.receiver.try_next() { - match msg { - SchedulerMsg::Task(t) => todo!(), - SchedulerMsg::Immediate(im) => { - self.scheduler.dirty_scopes.insert(im); - } - SchedulerMsg::UiEvent(evt) => { - self.scheduler.ui_events.push_back(evt); - } - } - } } } diff --git a/packages/hooks/src/usestate.rs b/packages/hooks/src/usestate.rs index 763c44666..649f90ef8 100644 --- a/packages/hooks/src/usestate.rs +++ b/packages/hooks/src/usestate.rs @@ -121,8 +121,8 @@ impl<'a, T: 'static> UseState<'a, T> { self.inner.wip.borrow_mut() } - pub fn classic(self) -> (&'a T, &'a Rc) { - todo!() + pub fn classic(self) -> (&'a T, Rc) { + (&self.inner.current_val, self.setter()) } pub fn setter(&self) -> Rc { diff --git a/packages/html/src/lib.rs b/packages/html/src/lib.rs index c99877386..9aba10101 100644 --- a/packages/html/src/lib.rs +++ b/packages/html/src/lib.rs @@ -1530,7 +1530,7 @@ builder_constructors! { // This has a manual implementation below // r#type: InputType, - value: String, + // value: String, width: isize, }; @@ -1538,7 +1538,7 @@ builder_constructors! { /// [`