WIP: still a bit stumped on DFS vs BFS

This commit is contained in:
Jonathan Kelley committed 2021-03-05 15:02:36 -05:00
1 parent 89f2290692
commit 3740f81383
6 files changed
+205 -291

No files matched your search

+75 -156
View File
@@ -1,7 +1,10 @@
// use crate::{changelist::EditList, nodes::VNode};
use crate::scope::{create_scoped, Scoped};
use crate::{innerlude::*, scope::Properties};
use crate::{
patch::Edit,
scope::{create_scoped, Scoped},
};
use bumpalo::Bump;
use generational_arena::Arena;
use std::{
@@ -25,19 +28,31 @@ pub struct VirtualDom {
/// like a generational typemap bump arena
/// -> IE a cache line for each P type with soem heuristics on optimizing layout
pub(crate) components: Arena<Box<dyn Scoped>>,
// pub(crate) components: Rc<RefCell<Arena<Box<dyn Scoped>>>>,
/// The index of the root component.
/// Will not be ready if the dom is fresh
base_scope: ScopeIdx,
event_queue: RefCell<VecDeque<LifecycleEvent>>,
// todo: encapsulate more state into this so we can better reuse it
diff_bump: Bump,
pub(crate) base_scope: ScopeIdx,
// Type of the original props. This is done so VirtualDom does not need to be generic.
#[doc(hidden)]
_root_prop_type: std::any::TypeId,
// ======================
// DIFF RELATED ITEMs
// ======================
// // todo: encapsulate more state into this so we can better reuse it
pub(crate) diff_bump: Bump,
// // be very very very very very careful
// pub change_list: EditMachine<'static>,
// // vdom: &'a VirtualDom,
// vdom: *mut Arena<Box<dyn Scoped>>,
// // vdom: Rc<RefCell<Arena<Box<dyn Scoped>>>>,
// pub cur_idx: ScopeIdx,
// // todo
// // do an indexmap sorted by height
// dirty_nodes: fxhash::FxHashSet<ScopeIdx>,
}
impl VirtualDom {
@@ -57,51 +72,53 @@ impl VirtualDom {
pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
let mut components = Arena::new();
let event_queue = RefCell::new(VecDeque::new());
// Create a reference to the component in the arena
// Note: we are essentially running the "Mount" lifecycle event manually while the vdom doesnt yet exist
// This puts the dom in a usable state on creation, rather than being potentially invalid
let base_scope = components.insert_with(|id| create_scoped(root, root_props, id, None));
// evaluate the component, pushing any updates its generates into the lifecycle queue
// todo!
let _root_prop_type = TypeId::of::<P>();
let diff_bump = Bump::new();
Self {
components,
base_scope,
event_queue,
diff_bump,
_root_prop_type,
}
todo!()
// Self {
// // components: RefCell::new(components),
// components: components,
// // components: Rc::new(RefCell::new(components)),
// base_scope,
// // event_queue: RefCell::new(VecDeque::new()),
// diff_bump: Bump::new(),
// _root_prop_type: TypeId::of::<P>(),
// }
}
/// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom.
///
///
pub fn rebuild(&mut self) -> Result<EditList<'_>> {
// pub fn rebuild<'s>(&'s mut self) -> Result<> {
// pub fn rebuild<'s>(&'s mut self) -> Result<std::cell::Ref<'_, Arena<Box<dyn Scoped>>>> {
pub fn rebuild<'s>(&'s mut self) -> Result<EditList<'s>> {
// Reset and then build a new diff machine
// The previous edit list cannot be around while &mut is held
// Make sure variance doesnt break this
self.diff_bump.reset();
let mut diff_machine = DiffMachine::new(&self.diff_bump);
// this is still a WIP
// we'll need to re-fecth all the scopes that were changed and build the diff machine
// fetch the component again
let component = self
.components
self.components
.get_mut(self.base_scope)
.expect("Root should always exist");
.expect("Root should always exist")
.run();
component.run();
let b = Bump::new();
diff_machine.diff_node(component.old_frame(), component.new_frame());
let mut diff_machine = DiffMachine::new(self, &b, self.base_scope);
// let mut diff_machine = DiffMachine::new(self, &self.diff_bump, self.base_scope);
Ok(diff_machine.consume())
todo!()
// let component = self.components.get(self.base_scope).unwrap();
// diff_machine.diff_node(component.old_frame(), component.new_frame());
// let edits = diff_machine.consume();
// self.diff_bump = b;
// Ok(edits)
}
/// This method is the most sophisticated way of updating the virtual dom after an external event has been triggered.
@@ -129,23 +146,32 @@ impl VirtualDom {
///
/// ```
pub fn progress_with_event(&mut self, event: EventTrigger) -> Result<EditList<'_>> {
let component = self
.components
.get_mut(event.component_id)
.expect("Component should exist if an event was triggered");
// self.components
// .borrow_mut()
// .get_mut(event.component_id)
// .map(|f| {
// f.call_listener(event);
// f
// })
// .map(|f| f.run())
// .expect("Borrowing should not fail");
component.call_listener(event);
// component.call_listener(event);
// .expect("Component should exist if an event was triggered");
// Reset and then build a new diff machine
// The previous edit list cannot be around while &mut is held
// Make sure variance doesnt break this
self.diff_bump.reset();
let mut diff_machine = DiffMachine::new(&self.diff_bump);
// self.diff_bump.reset();
// let mut diff_machine = DiffMachine::new(&mut self, event.component_id);
// let mut diff_machine =
// DiffMachine::new(&self.diff_bump, &mut self.components, event.component_id);
component.run();
diff_machine.diff_node(component.old_frame(), component.new_frame());
// component.run();
// diff_machine.diff_node(component.old_frame(), component.new_frame());
Ok(diff_machine.consume())
todo!()
// Ok(diff_machine.consume())
// Err(crate::error::Error::NoEvent)
// Mark dirty components. Descend from the highest node until all dirty nodes are updated.
// let mut affected_components = Vec::new();
@@ -159,115 +185,8 @@ impl VirtualDom {
// todo!()
}
/// Using mutable access to the Virtual Dom, progress a given lifecycle event
fn process_lifecycle(&mut self, LifecycleEvent { event_type }: LifecycleEvent) -> Result<()> {
match event_type {
// Component needs to be mounted to the virtual dom
LifecycleType::Mount {
to: _,
under: _,
props: _,
} => {}
// The parent for this component generated new props and the component needs update
LifecycleType::PropsChanged {
props: _,
component: _,
} => {}
// Component was messaged via the internal subscription service
LifecycleType::Callback { component: _ } => {}
}
Ok(())
}
/// Pop the top event of the internal lifecycle event queu
pub fn pop_event(&self) -> Option<LifecycleEvent> {
self.event_queue.borrow_mut().pop_front()
}
/// With access to the virtual dom, schedule an update to the Root component's props.
/// This generates the appropriate Lifecycle even. It's up to the renderer to actually feed this lifecycle event
/// back into the event system to get an edit list.
/// todo
/// change this to accept a modification closure, so the user gets 0-cost access to the props item.
/// Good for cases where the props is changed remotely (or something similar) and building a whole new props item would
/// be wasteful
pub fn update_props<P: 'static>(
&mut self,
updater: impl FnOnce(&mut P),
) -> Result<LifecycleEvent> {
todo!()
// // pub fn update_props<P: 'static>(&mut self, new_props: P) -> Result<LifecycleEvent> {
// // Ensure the props match
// if TypeId::of::<P>() != self._root_prop_type {
// return Err(Error::WrongProps);
// }
// Ok(LifecycleEvent {
// event_type: LifecycleType::PropsChanged {
// props: Box::new(new_props),
// component: self.base_scope,
// },
// })
}
}
pub struct LifecycleEvent {
pub event_type: LifecycleType,
}
pub enum LifecycleType {
// Component needs to be mounted, but its scope doesn't exist yet
Mount {
to: ScopeIdx,
under: usize,
props: Box<dyn std::any::Any>,
},
// Parent was evalauted causing new props to generate
PropsChanged {
props: Box<dyn std::any::Any>,
component: ScopeIdx,
},
// Hook for the subscription API
Callback {
component: ScopeIdx,
},
}
impl LifecycleEvent {
fn index(&self) -> Option<ScopeIdx> {
match &self.event_type {
LifecycleType::Mount {
to: _,
under: _,
props: _,
} => None,
LifecycleType::PropsChanged { component, .. }
| LifecycleType::Callback { component } => Some(component.clone()),
}
}
}
mod tests {
use super::*;
#[test]
fn start_dom() {
let mut dom = VirtualDom::new(|ctx, props| {
todo!()
// ctx.render(|ctx| {
// use crate::builder::*;
// let bump = ctx.bump();
// div(bump).child(text("hello, world")).finish()
// })
});
let edits = dom.rebuild().unwrap();
println!("{:#?}", edits);
}
}
// struct LockedEdits<'src> {
// edits:
// }