fix: all the bugs!

This commit is contained in:
Jonathan Kelley committed 2021-10-11 18:40:00 -04:00
1 parent 4a4c7afca7
commit 478255f40d
9 files changed
+75 -65

No files matched your search

+8 -4
View File
@@ -191,7 +191,7 @@ impl<'src> Context<'src> {
/// rsx!(cx, div { "hello {state.0}" }) /// rsx!(cx, div { "hello {state.0}" })
/// } /// }
/// ``` /// ```
pub fn provide_state<T>(self, value: T) -> Option<Rc<T>> pub fn provide_state<T>(self, value: T)
where where
T: 'static, T: 'static,
{ {
@@ -200,7 +200,7 @@ impl<'src> Context<'src> {
.borrow_mut() .borrow_mut()
.insert(TypeId::of::<T>(), Rc::new(value)) .insert(TypeId::of::<T>(), Rc::new(value))
.map(|f| f.downcast::<T>().ok()) .map(|f| f.downcast::<T>().ok())
.flatten() .flatten();
} }
/// Try to retrive a SharedState with type T from the any parent Scope. /// Try to retrive a SharedState with type T from the any parent Scope.
@@ -279,13 +279,17 @@ impl<'src> Context<'src> {
Output: 'src, Output: 'src,
Init: FnOnce(usize) -> State, Init: FnOnce(usize) -> State,
Run: FnOnce(&'src mut State) -> Output, Run: FnOnce(&'src mut State) -> Output,
Cleanup: FnOnce(&mut State) + 'static, Cleanup: FnOnce(Box<State>) + 'static,
{ {
// If the idx is the same as the hook length, then we need to add the current hook // If the idx is the same as the hook length, then we need to add the current hook
if self.scope.hooks.at_end() { if self.scope.hooks.at_end() {
self.scope.hooks.push_hook( self.scope.hooks.push_hook(
initializer(self.scope.hooks.len()), initializer(self.scope.hooks.len()),
Box::new(|raw| cleanup(raw.downcast_mut::<State>().unwrap())), Box::new(|raw| {
//
let s = raw.downcast::<State>().unwrap();
cleanup(s);
}),
); );
} }
+23 -31
View File
@@ -221,18 +221,12 @@ impl<'bump> DiffMachine<'bump> {
MountType::Replace { old } => { MountType::Replace { old } => {
if let Some(old_id) = old.try_mounted_id() { if let Some(old_id) = old.try_mounted_id() {
self.mutations.replace_with(old_id, nodes_created as u32); self.mutations.replace_with(old_id, nodes_created as u32);
self.remove_nodes(Some(old));
} else { } else {
let mut iter = RealChildIterator::new(old, self.vdom); if let Some(id) = self.find_first_element_id(old) {
let first = iter.next().unwrap(); self.mutations.replace_with(id, nodes_created as u32);
self.mutations }
.replace_with(first.mounted_id(), nodes_created as u32); self.remove_nodes(Some(old));
self.remove_nodes(iter);
}
}
MountType::ReplaceByElementId { el } => {
if let Some(old) = el {
self.mutations.replace_with(old, nodes_created as u32);
} }
} }
@@ -376,6 +370,8 @@ impl<'bump> DiffMachine<'bump> {
let new_component = self.vdom.get_scope_mut(new_idx).unwrap(); let new_component = self.vdom.get_scope_mut(new_idx).unwrap();
log::debug!("initializing component {:?}", new_idx);
// Run the scope for one iteration to initialize it // Run the scope for one iteration to initialize it
if new_component.run_scope(self.vdom) { if new_component.run_scope(self.vdom) {
// Take the node that was just generated from running the component // Take the node that was just generated from running the component
@@ -413,7 +409,7 @@ impl<'bump> DiffMachine<'bump> {
(Fragment(old), Fragment(new)) => self.diff_fragment_nodes(old, new), (Fragment(old), Fragment(new)) => self.diff_fragment_nodes(old, new),
(Anchor(old), Anchor(new)) => new.dom_id.set(old.dom_id.get()), (Anchor(old), Anchor(new)) => new.dom_id.set(old.dom_id.get()),
(Suspended(old), Suspended(new)) => self.diff_suspended_nodes(old, new), (Suspended(old), Suspended(new)) => self.diff_suspended_nodes(old, new),
(Element(old), Element(new)) => self.diff_element_nodes(old, new, new_node), (Element(old), Element(new)) => self.diff_element_nodes(old, new, old_node, new_node),
// Anything else is just a basic replace and create // Anything else is just a basic replace and create
( (
@@ -439,6 +435,7 @@ impl<'bump> DiffMachine<'bump> {
&mut self, &mut self,
old: &'bump VElement<'bump>, old: &'bump VElement<'bump>,
new: &'bump VElement<'bump>, new: &'bump VElement<'bump>,
old_node: &'bump VNode<'bump>,
new_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>,
) { ) {
let root = old.dom_id.get().unwrap(); let root = old.dom_id.get().unwrap();
@@ -452,9 +449,7 @@ impl<'bump> DiffMachine<'bump> {
// issue is that we need the "vnode" but this method only has the velement // issue is that we need the "vnode" but this method only has the velement
self.stack.push_nodes_created(0); self.stack.push_nodes_created(0);
self.stack.push(DiffInstruction::Mount { self.stack.push(DiffInstruction::Mount {
and: MountType::ReplaceByElementId { and: MountType::Replace { old: old_node },
el: old.dom_id.get(),
},
}); });
self.create_element_node(new, new_node); self.create_element_node(new, new_node);
return; return;
@@ -546,6 +541,7 @@ impl<'bump> DiffMachine<'bump> {
// Make sure we're dealing with the same component (by function pointer) // Make sure we're dealing with the same component (by function pointer)
if old.user_fc == new.user_fc { if old.user_fc == new.user_fc {
log::debug!("Diffing component {:?} - {:?}", new.user_fc, scope_addr);
// //
self.stack.scope_stack.push(scope_addr); self.stack.scope_stack.push(scope_addr);
@@ -554,7 +550,6 @@ impl<'bump> DiffMachine<'bump> {
// make sure the component's caller function is up to date // make sure the component's caller function is up to date
let scope = self.vdom.get_scope_mut(scope_addr).unwrap(); let scope = self.vdom.get_scope_mut(scope_addr).unwrap();
scope.update_scope_dependencies(new.caller, ScopeChildren(new.children)); scope.update_scope_dependencies(new.caller, ScopeChildren(new.children));
// React doesn't automatically memoize, but we do. // React doesn't automatically memoize, but we do.
@@ -569,8 +564,6 @@ impl<'bump> DiffMachine<'bump> {
} }
self.stack.scope_stack.pop(); self.stack.scope_stack.pop();
self.seen_scopes.insert(scope_addr);
} else { } else {
self.stack self.stack
.create_node(new_node, MountType::Replace { old: old_node }); .create_node(new_node, MountType::Replace { old: old_node });
@@ -624,17 +617,14 @@ impl<'bump> DiffMachine<'bump> {
self.stack.create_children(new, MountType::Append); self.stack.create_children(new, MountType::Append);
} }
(_, []) => { (_, []) => {
for node in old { self.remove_nodes(old);
self.remove_nodes(Some(node));
}
} }
([VNode::Anchor(old_anchor)], [VNode::Anchor(new_anchor)]) => { ([VNode::Anchor(old_anchor)], [VNode::Anchor(new_anchor)]) => {
old_anchor.dom_id.set(new_anchor.dom_id.get()); old_anchor.dom_id.set(new_anchor.dom_id.get());
} }
([VNode::Anchor(anchor)], _) => { ([VNode::Anchor(_)], _) => {
let el = anchor.dom_id.get();
self.stack self.stack
.create_children(new, MountType::ReplaceByElementId { el }); .create_children(new, MountType::Replace { old: &old[0] });
} }
(_, [VNode::Anchor(_)]) => { (_, [VNode::Anchor(_)]) => {
self.replace_and_create_many_with_one(old, &new[0]); self.replace_and_create_many_with_one(old, &new[0]);
@@ -743,13 +733,13 @@ impl<'bump> DiffMachine<'bump> {
Some(count) => count, Some(count) => count,
None => return, None => return,
}; };
log::debug!( // log::debug!(
"Left offset, right offset, {}, {}", // "Left offset, right offset, {}, {}",
left_offset, // left_offset,
right_offset, // right_offset,
); // );
log::debug!("stack before lo is {:#?}", self.stack.instructions); // log::debug!("stack before lo is {:#?}", self.stack.instructions);
// Ok, we now hopefully have a smaller range of children in the middle // 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 // within which to re-order nodes with the same keys, remove old nodes with
// now-unused keys, and create new nodes with fresh keys. // now-unused keys, and create new nodes with fresh keys.
@@ -1126,9 +1116,11 @@ impl<'bump> DiffMachine<'bump> {
VNode::Component(c) => { VNode::Component(c) => {
let scope_id = c.associated_scope.get().unwrap(); let scope_id = c.associated_scope.get().unwrap();
let scope = self.vdom.get_scope(scope_id).unwrap(); let scope = self.vdom.get_scope_mut(scope_id).unwrap();
let root = scope.root_node(); let root = scope.root_node();
self.remove_nodes(Some(root)); self.remove_nodes(Some(root));
let mut s = self.vdom.try_remove(scope_id).unwrap();
s.hooks.clear_hooks();
} }
} }
} }
-1
View File
@@ -30,7 +30,6 @@ pub enum MountType<'a> {
Absorb, Absorb,
Append, Append,
Replace { old: &'a VNode<'a> }, Replace { old: &'a VNode<'a> },
ReplaceByElementId { el: Option<ElementId> },
InsertAfter { other_node: &'a VNode<'a> }, InsertAfter { other_node: &'a VNode<'a> },
InsertBefore { other_node: &'a VNode<'a> }, InsertBefore { other_node: &'a VNode<'a> },
} }
+9 -7
View File
@@ -12,7 +12,7 @@ use std::{
/// Todo: this could use its very own bump arena, but that might be a tad overkill /// Todo: this could use its very own bump arena, but that might be a tad overkill
#[derive(Default)] #[derive(Default)]
pub(crate) struct HookList { pub(crate) struct HookList {
vals: RefCell<Vec<(UnsafeCell<Box<dyn Any>>, Box<dyn FnOnce(&mut dyn Any)>)>>, vals: RefCell<Vec<(UnsafeCell<Box<dyn Any>>, Box<dyn FnOnce(Box<dyn Any>)>)>>,
idx: Cell<usize>, idx: Cell<usize>,
} }
@@ -35,7 +35,7 @@ impl HookList {
self.idx.set(0); self.idx.set(0);
} }
pub(crate) fn push_hook<T: 'static>(&self, new: T, cleanup: Box<dyn FnOnce(&mut dyn Any)>) { pub(crate) fn push_hook<T: 'static>(&self, new: T, cleanup: Box<dyn FnOnce(Box<dyn Any>)>) {
self.vals self.vals
.borrow_mut() .borrow_mut()
.push((UnsafeCell::new(Box::new(new)), cleanup)) .push((UnsafeCell::new(Box::new(new)), cleanup))
@@ -52,14 +52,16 @@ impl HookList {
pub(crate) fn at_end(&self) -> bool { pub(crate) fn at_end(&self) -> bool {
self.cur_idx() >= self.len() self.cur_idx() >= self.len()
} }
}
// When the scope is dropped, we want to call the cleanup function for each of the hooks pub fn clear_hooks(&mut self) {
impl Drop for HookList {
fn drop(&mut self) {
self.vals self.vals
.borrow_mut() .borrow_mut()
.drain(..) .drain(..)
.for_each(|(mut state, cleanup)| cleanup(state.get_mut())); .for_each(|(mut state, cleanup)| {
//
let s: Box<dyn Any> = state.into_inner();
cleanup(s)
//
});
} }
} }
+2 -2
View File
@@ -63,8 +63,8 @@ impl ResourcePool {
/// return the id, freeing the space of the original node /// return the id, freeing the space of the original node
pub fn collect_garbage(&self, id: ElementId) { pub fn collect_garbage(&self, id: ElementId) {
todo!("garabge collection currently WIP") let els = unsafe { &mut *self.raw_elements.get() };
// self.raw_elements.remove(id.0); els.remove(id.0);
} }
pub fn insert_scope_with_key(&self, f: impl FnOnce(ScopeId) -> Scope) -> ScopeId { pub fn insert_scope_with_key(&self, f: impl FnOnce(ScopeId) -> Scope) -> ScopeId {
+22 -11
View File
@@ -185,7 +185,11 @@ impl Scheduler {
sender: sender.clone(), sender: sender.clone(),
schedule_any_immediate: { schedule_any_immediate: {
let sender = sender.clone(); let sender = sender.clone();
Rc::new(move |id| sender.unbounded_send(SchedulerMsg::Immediate(id)).unwrap()) Rc::new(move |id| {
//
log::debug!("scheduling immedate! {:?}", id);
sender.unbounded_send(SchedulerMsg::Immediate(id)).unwrap()
})
}, },
// todo: we want to get the futures out of the scheduler message // todo: we want to get the futures out of the scheduler message
// the scheduler message should be send/sync // the scheduler message should be send/sync
@@ -374,23 +378,28 @@ impl Scheduler {
if machine.stack.is_empty() { if machine.stack.is_empty() {
let shared = self.pool.clone(); let shared = self.pool.clone();
self.dirty_scopes
.retain(|id| shared.get_scope(*id).is_some());
self.dirty_scopes.sort_by(|a, b| { self.dirty_scopes.sort_by(|a, b| {
let h1 = shared.get_scope(*a).unwrap().height; let h1 = shared.get_scope(*a).unwrap().height;
let h2 = shared.get_scope(*b).unwrap().height; let h2 = shared.get_scope(*b).unwrap().height;
h1.cmp(&h2) h1.cmp(&h2).reverse()
}); });
if let Some(scopeid) = self.dirty_scopes.pop() { if let Some(scopeid) = self.dirty_scopes.pop() {
log::info!("handlng dirty scope {:#?}", scopeid); log::info!("handlng dirty scope {:?}", scopeid);
if !ran_scopes.contains(&scopeid) { if !ran_scopes.contains(&scopeid) {
ran_scopes.insert(scopeid); ran_scopes.insert(scopeid);
log::debug!("about to run scope {:?}", scopeid);
let mut component = self.pool.get_scope_mut(scopeid).unwrap(); if let Some(component) = self.pool.get_scope_mut(scopeid) {
if component.run_scope(&self.pool) { if component.run_scope(&self.pool) {
let (old, new) = (component.frames.wip_head(), component.frames.fin_head()); let (old, new) =
// let (old, new) = (component.frames.wip_head(), component.frames.fin_head()); (component.frames.wip_head(), component.frames.fin_head());
machine.stack.scope_stack.push(scopeid); // let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
machine.stack.push(DiffInstruction::Diff { new, old }); machine.stack.scope_stack.push(scopeid);
machine.stack.push(DiffInstruction::Diff { new, old });
}
} }
} }
} }
@@ -522,8 +531,6 @@ impl Scheduler {
} }
} }
log::debug!("work with deadline completed: {:#?}", committed_mutations);
committed_mutations committed_mutations
} }
@@ -562,6 +569,8 @@ impl Scheduler {
.get_scope_mut(base_scope) .get_scope_mut(base_scope)
.expect("The base scope should never be moved"); .expect("The base scope should never be moved");
log::debug!("rebuild {:?}", base_scope);
// We run the component. If it succeeds, then we can diff it and add the changes to the dom. // We run the component. If it succeeds, then we can diff it and add the changes to the dom.
if cur_component.run_scope(&self.pool) { if cur_component.run_scope(&self.pool) {
diff_machine diff_machine
@@ -588,6 +597,8 @@ impl Scheduler {
.get_scope_mut(base_scope) .get_scope_mut(base_scope)
.expect("The base scope should never be moved"); .expect("The base scope should never be moved");
log::debug!("hard diff {:?}", base_scope);
if cur_component.run_scope(&self.pool) { if cur_component.run_scope(&self.pool) {
let mut diff_machine = DiffMachine::new(Mutations::new(), &mut self.pool); let mut diff_machine = DiffMachine::new(Mutations::new(), &mut self.pool);
diff_machine.cfg.force_diff = true; diff_machine.cfg.force_diff = true;
+1
View File
@@ -218,6 +218,7 @@ impl Scope {
caller: &'creator_node dyn for<'b> Fn(&'b Scope) -> DomTree<'b>, caller: &'creator_node dyn for<'b> Fn(&'b Scope) -> DomTree<'b>,
child_nodes: ScopeChildren, child_nodes: ScopeChildren,
) { ) {
log::debug!("Updating scope dependencies {:?}", self.our_arena_idx);
let caller = caller as *const _; let caller = caller as *const _;
self.caller = unsafe { std::mem::transmute(caller) }; self.caller = unsafe { std::mem::transmute(caller) };
+9 -8
View File
@@ -112,10 +112,10 @@ impl<'a, T: 'static> UseSharedState<'a, T> {
} }
pub fn notify_consumers(self) { pub fn notify_consumers(self) {
if !self.needs_notification.get() { // if !self.needs_notification.get() {
self.needs_notification.set(true); self.root.borrow_mut().notify_consumers();
self.root.borrow_mut().notify_consumers(); // self.needs_notification.set(true);
} // }
} }
pub fn read_write(&self) -> (Ref<'_, T>, &Self) { pub fn read_write(&self) -> (Ref<'_, T>, &Self) {
@@ -161,16 +161,17 @@ where
/// ///
/// ///
/// ///
pub fn use_provide_state<'a, T: 'static>(cx: Context<'a>, f: impl FnOnce() -> T) -> Option<()> { pub fn use_provide_state<'a, T: 'static>(cx: Context<'a>, f: impl FnOnce() -> T) {
cx.use_hook( cx.use_hook(
|_| { |_| {
cx.provide_state(ProvidedStateInner { let state: ProvidedState<T> = RefCell::new(ProvidedStateInner {
value: Rc::new(RefCell::new(f())), value: Rc::new(RefCell::new(f())),
notify_any: cx.schedule_update_any(), notify_any: cx.schedule_update_any(),
consumers: HashSet::new(), consumers: HashSet::new(),
}) });
cx.provide_state(state)
}, },
|inner| inner.as_ref().and_then(|_| Some(())), |inner| {},
|_| {}, |_| {},
) )
} }
+1 -1
View File
@@ -176,7 +176,7 @@ pub async fn run_with_props<T: 'static + Send>(root: FC<T>, root_props: T, cfg:
work_loop.wait_for_raf().await; work_loop.wait_for_raf().await;
for mut edit in mutations { for mut edit in mutations {
log::debug!("edits are {:#?}", edit); // log::debug!("edits are {:#?}", edit);
// actually apply our changes during the animation frame // actually apply our changes during the animation frame
websys_dom.process_edits(&mut edit.edits); websys_dom.process_edits(&mut edit.edits);
} }