|
@@ -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");
|
|
|
-
|
|
|
- component.call_listener(event);
|
|
|
-
|
|
|
+ // 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);
|
|
|
+
|
|
|
+ // .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:
|
|
|
+// }
|