WIP: still a bit stumped on DFS vs BFS
This commit is contained in:
1 parent
89f2290692
commit
3740f81383
6 files changed
+205
-291
No files matched your search
@@ -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:
|
||||
// }
|
||||
Reference in new issue
Block a user