Feat: re-enable stack machine approach
This commit is contained in:
1 parent
1781ebba86
commit
e3ede7fcbf
15 files changed
+1124
-614
No files matched your search
@@ -19,6 +19,8 @@
|
||||
//!
|
||||
//!
|
||||
|
||||
use bumpalo::Bump;
|
||||
|
||||
use crate::innerlude::{Listener, VirtualDom};
|
||||
|
||||
/// The `Edit` represents a single modifcation of the renderer tree.
|
||||
@@ -31,6 +33,7 @@ use crate::innerlude::{Listener, VirtualDom};
|
||||
///
|
||||
///
|
||||
///
|
||||
#[derive(Debug)]
|
||||
pub enum Edit<'d> {
|
||||
SetText { text: &'d str },
|
||||
RemoveSelfAndNextSiblings {},
|
||||
@@ -57,14 +60,23 @@ pub enum Edit<'d> {
|
||||
}
|
||||
|
||||
pub struct EditList<'src> {
|
||||
traversal: Traversal,
|
||||
pub traversal: Traversal,
|
||||
next_temporary: u32,
|
||||
forcing_new_listeners: bool,
|
||||
emitter: Vec<Edit<'src>>,
|
||||
pub emitter: Vec<Edit<'src>>,
|
||||
}
|
||||
|
||||
/// Traversal methods.
|
||||
impl EditList<'_> {
|
||||
impl<'b> EditList<'b> {
|
||||
pub fn new(bump: &'b Bump) -> Self {
|
||||
Self {
|
||||
traversal: Traversal::new(),
|
||||
next_temporary: 0,
|
||||
forcing_new_listeners: false,
|
||||
emitter: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Traversal methods.
|
||||
pub fn go_down(&mut self) {
|
||||
self.traversal.down();
|
||||
}
|
||||
@@ -98,36 +110,37 @@ impl EditList<'_> {
|
||||
|
||||
pub fn commit_traversal(&mut self) {
|
||||
if self.traversal.is_committed() {
|
||||
log::debug!("Traversal already committed");
|
||||
return;
|
||||
}
|
||||
|
||||
for mv in self.traversal.commit() {
|
||||
match mv {
|
||||
MoveTo::Parent => {
|
||||
// debug!("emit: pop");
|
||||
log::debug!("emit: pop");
|
||||
self.emitter.push(Edit::Pop {});
|
||||
// self.emitter.pop();
|
||||
}
|
||||
MoveTo::Child(n) => {
|
||||
// debug!("emit: push_child({})", n);
|
||||
log::debug!("emit: push_child({})", n);
|
||||
self.emitter.push(Edit::PushChild { n });
|
||||
}
|
||||
MoveTo::ReverseChild(n) => {
|
||||
// debug!("emit: push_reverse_child({})", n);
|
||||
log::debug!("emit: push_reverse_child({})", n);
|
||||
self.emitter.push(Edit::PushReverseChild { n });
|
||||
// self.emitter.push_reverse_child(n);
|
||||
}
|
||||
MoveTo::Sibling(n) => {
|
||||
// debug!("emit: pop_push_child({})", n);
|
||||
log::debug!("emit: pop_push_child({})", n);
|
||||
self.emitter.push(Edit::PopPushChild { n });
|
||||
// self.emitter.pop_push_child(n);
|
||||
}
|
||||
MoveTo::ReverseSibling(n) => {
|
||||
// debug!("emit: pop_push_reverse_child({})", n);
|
||||
log::debug!("emit: pop_push_reverse_child({})", n);
|
||||
self.emitter.push(Edit::PopPushReverseChild { n });
|
||||
}
|
||||
MoveTo::TempChild(temp) => {
|
||||
// debug!("emit: push_temporary({})", temp);
|
||||
log::debug!("emit: push_temporary({})", temp);
|
||||
self.emitter.push(Edit::PushTemporary { temp });
|
||||
// self.emitter.push_temporary(temp);
|
||||
}
|
||||
@@ -477,8 +490,8 @@ impl Traversal {
|
||||
#[inline]
|
||||
pub fn is_committed(&self) -> bool {
|
||||
// is_empty is not inlined?
|
||||
// self.uncommitted.is_empty()
|
||||
self.uncommitted.len() == 0
|
||||
self.uncommitted.is_empty()
|
||||
// self.uncommitted.len() == 0
|
||||
}
|
||||
|
||||
/// Commit this traversals moves and return the optimized path from the last
|
||||
|
||||
@@ -238,6 +238,8 @@ mod tests {
|
||||
.for_each(|f| assert_eq!(compare_patch(f.0, f.1), true, "{}", description));
|
||||
}
|
||||
|
||||
// todo: make this actually perform real comparisons
|
||||
// by default, nothing is derived for vnodes or patches
|
||||
fn compare_patch(patch1: &Patch, patch2: &Patch) -> bool {
|
||||
match (patch1, patch2) {
|
||||
(Patch::AppendChildren(_, _), Patch::AppendChildren(_, _)) => true,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use bumpalo::Bump;
|
||||
/// Diff the `old` node with the `new` node. Emits instructions to modify a
|
||||
/// physical DOM node that reflects `old` into something that reflects `new`.
|
||||
///
|
||||
@@ -36,7 +37,7 @@ use fxhash::{FxHashMap, FxHashSet};
|
||||
use generational_arena::Index;
|
||||
|
||||
use crate::{
|
||||
changelist::EditList,
|
||||
changelist::{Edit, EditList},
|
||||
innerlude::{Attribute, Listener, Scope, VElement, VNode, VText},
|
||||
virtual_dom::LifecycleEvent,
|
||||
};
|
||||
@@ -55,8 +56,8 @@ use std::cmp::Ordering;
|
||||
/// The order of these re-entrances is stored in the DiffState itself. The DiffState comes pre-loaded with a set of components
|
||||
/// that were modified by the eventtrigger. This prevents doubly evaluating components if they wereboth updated via
|
||||
/// subscriptions and props changes.
|
||||
struct DiffingMachine<'a> {
|
||||
change_list: &'a mut EditList<'a>,
|
||||
pub struct DiffMachine<'a> {
|
||||
pub change_list: EditList<'a>,
|
||||
immediate_queue: Vec<Index>,
|
||||
diffed: FxHashSet<Index>,
|
||||
need_to_diff: FxHashSet<Index>,
|
||||
@@ -67,8 +68,21 @@ enum NeedToDiff {
|
||||
Subscription,
|
||||
}
|
||||
|
||||
impl<'a> DiffingMachine<'a> {
|
||||
fn diff_node(&mut self, old: &VNode<'a>, new: &VNode<'a>) {
|
||||
impl<'a> DiffMachine<'a> {
|
||||
pub fn new(bump: &'a Bump) -> Self {
|
||||
Self {
|
||||
change_list: EditList::new(bump),
|
||||
immediate_queue: Vec::new(),
|
||||
diffed: FxHashSet::default(),
|
||||
need_to_diff: FxHashSet::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn consume(self) -> Vec<Edit<'a>> {
|
||||
self.change_list.emitter
|
||||
}
|
||||
|
||||
pub fn diff_node(&mut self, old: &VNode<'a>, new: &VNode<'a>) {
|
||||
/*
|
||||
For each valid case, we "commit traversal", meaning we save this current position in the tree.
|
||||
Then, we diff and queue an edit event (via chagelist). s single trees - when components show up, we save that traversal and then re-enter later.
|
||||
@@ -107,6 +121,7 @@ impl<'a> DiffingMachine<'a> {
|
||||
// compare elements
|
||||
// if different, schedule different types of update
|
||||
(VNode::Element(eold), VNode::Element(enew)) => {
|
||||
log::debug!("elements are different");
|
||||
// If the element type is completely different, the element needs to be re-rendered completely
|
||||
if enew.tag_name != eold.tag_name || enew.namespace != eold.namespace {
|
||||
self.change_list.commit_traversal();
|
||||
|
||||
@@ -65,13 +65,13 @@
|
||||
//! - dioxus-liveview (SSR + StringRenderer)
|
||||
//!
|
||||
|
||||
// pub mod changelist; // An "edit phase" described by transitions and edit operations
|
||||
pub mod changelist; // An "edit phase" described by transitions and edit operations
|
||||
pub mod component; // Logic for extending FC
|
||||
pub mod context; // Logic for providing hook + context functionality to user components
|
||||
pub mod debug_renderer; // Test harness for validating that lifecycles and diffs work appropriately
|
||||
pub mod diff;
|
||||
pub mod patch; // The diffing algorithm that builds the ChangeList
|
||||
// pub mod dodriodiff; // The diffing algorithm that builds the ChangeList
|
||||
// pub mod diff;
|
||||
// pub mod patch; // The diffing algorithm that builds the ChangeList
|
||||
pub mod dodriodiff; // The diffing algorithm that builds the ChangeList
|
||||
pub mod error; // Error type we expose to the renderers
|
||||
pub mod events; // Manages the synthetic event API
|
||||
pub mod hooks; // Built-in hooks
|
||||
@@ -99,7 +99,7 @@ pub(crate) mod innerlude {
|
||||
// pub use nodes::iterables::IterableNodes;
|
||||
/// This type alias is an internal way of abstracting over the static functions that represent components.
|
||||
|
||||
pub type FC<P> = for<'a> fn(Context<'a>, &'a P) -> VNode<'a>;
|
||||
pub type FC<P> = for<'a> fn(Context<'a>, &'a P) -> &'a VNode<'a>;
|
||||
// pub type FC<P> = for<'a> fn(Context<'a, P>) -> VNode<'a>;
|
||||
|
||||
// TODO @Jon, fix this
|
||||
@@ -139,7 +139,8 @@ pub mod prelude {
|
||||
pub use dioxus_core_macro::fc;
|
||||
pub use dioxus_html_2::html;
|
||||
|
||||
pub use crate::diff::DiffMachine;
|
||||
// pub use crate::diff::DiffMachine;
|
||||
pub use crate::dodriodiff::DiffMachine;
|
||||
|
||||
pub use crate::hooks::*;
|
||||
}
|
||||
@@ -192,7 +192,7 @@ mod velement {
|
||||
/// Keys must be unique among siblings.
|
||||
///
|
||||
/// If any sibling is keyed, then they all must be keyed.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct NodeKey(pub(crate) u32);
|
||||
|
||||
impl Default for NodeKey {
|
||||
|
||||
+138
-53
@@ -3,11 +3,82 @@ use crate::innerlude::*;
|
||||
use crate::nodes::VNode;
|
||||
use bumpalo::Bump;
|
||||
use generational_arena::Index;
|
||||
use owning_ref::StableAddress;
|
||||
use std::{
|
||||
any::TypeId, borrow::Borrow, cell::RefCell, future::Future, marker::PhantomData,
|
||||
sync::atomic::AtomicUsize, todo,
|
||||
any::TypeId,
|
||||
borrow::{Borrow, BorrowMut},
|
||||
cell::{RefCell, UnsafeCell},
|
||||
future::Future,
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::atomic::AtomicUsize,
|
||||
todo,
|
||||
};
|
||||
|
||||
pub struct BumpContainer(pub UnsafeCell<Bump>);
|
||||
impl BumpContainer {
|
||||
fn new() -> Self {
|
||||
Self(UnsafeCell::new(Bump::new()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for BumpContainer {
|
||||
type Target = Bump;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
todo!()
|
||||
// self.0.borrow()
|
||||
}
|
||||
}
|
||||
impl DerefMut for BumpContainer {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
todo!()
|
||||
// self.0.borrow_mut()
|
||||
}
|
||||
}
|
||||
unsafe impl StableAddress for BumpContainer {}
|
||||
|
||||
#[ouroboros::self_referencing]
|
||||
pub struct BumpFrame {
|
||||
pub bump: BumpContainer,
|
||||
|
||||
#[covariant]
|
||||
#[borrows(bump)]
|
||||
pub head_node: &'this VNode<'this>,
|
||||
}
|
||||
|
||||
pub struct ActiveFrame {
|
||||
pub idx: AtomicUsize,
|
||||
pub frames: [BumpFrame; 2],
|
||||
}
|
||||
|
||||
impl ActiveFrame {
|
||||
fn from_frames(a: BumpFrame, b: BumpFrame) -> Self {
|
||||
Self {
|
||||
idx: 0.into(),
|
||||
frames: [a, b],
|
||||
}
|
||||
}
|
||||
|
||||
fn next(&self) -> &BumpFrame {
|
||||
self.idx.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
let cur = self.idx.borrow().load(std::sync::atomic::Ordering::Relaxed);
|
||||
match cur % 1 {
|
||||
1 => &self.frames[1],
|
||||
0 => &self.frames[0],
|
||||
_ => unreachable!("mod cannot by non-zero"),
|
||||
}
|
||||
}
|
||||
// fn next(&self) -> &BumpFrame {
|
||||
// self.idx.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
// let cur = self.idx.borrow().load(std::sync::atomic::Ordering::Relaxed);
|
||||
// match cur % 2_usize {
|
||||
// 1 => &self.frames[1],
|
||||
// 0 => &self.frames[0],
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/// Every component in Dioxus is represented by a `Scope`.
|
||||
///
|
||||
/// Scopes contain the state for hooks, the component's props, and other lifecycle information.
|
||||
@@ -26,16 +97,12 @@ pub struct Scope {
|
||||
pub parent: Option<Index>,
|
||||
|
||||
// todo, do better with the active frame stuff
|
||||
pub frames: [Bump; 2],
|
||||
|
||||
// somehow build this vnode with a lifetime tied to self
|
||||
// This root node has "static" lifetime, but it's really not static.
|
||||
// It's goverened by the oldest of the two frames and is switched every time a new render occurs
|
||||
// Use this node as if it were static is unsafe, and needs to be fixed with ourborous or owning ref
|
||||
// ! do not copy this reference are things WILL break !
|
||||
pub root_node: *mut VNode<'static>,
|
||||
|
||||
pub active_frame: ActiveFrame,
|
||||
pub frames: ActiveFrame,
|
||||
|
||||
// IE Which listeners need to be woken up?
|
||||
pub listeners: Vec<Box<dyn Fn()>>,
|
||||
@@ -45,19 +112,19 @@ pub struct Scope {
|
||||
pub caller: *const i32,
|
||||
}
|
||||
|
||||
pub enum ActiveFrame {
|
||||
First,
|
||||
Second,
|
||||
}
|
||||
// pub enum ActiveFrame {
|
||||
// First,
|
||||
// Second,
|
||||
// }
|
||||
|
||||
impl ActiveFrame {
|
||||
fn next(&mut self) {
|
||||
match self {
|
||||
ActiveFrame::First => *self = ActiveFrame::Second,
|
||||
ActiveFrame::Second => *self = ActiveFrame::First,
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl ActiveFrame {
|
||||
// fn next(&mut self) {
|
||||
// match self {
|
||||
// ActiveFrame::First => *self = ActiveFrame::Second,
|
||||
// ActiveFrame::Second => *self = ActiveFrame::First,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Scope {
|
||||
// create a new scope from a function
|
||||
@@ -72,26 +139,31 @@ impl Scope {
|
||||
|
||||
// Create the two buffers the componetn will render into
|
||||
// There will always be an "old" and "new"
|
||||
let frames = [Bump::new(), Bump::new()];
|
||||
|
||||
let listeners = Vec::new();
|
||||
|
||||
let active_frame = ActiveFrame::First;
|
||||
let new_frame = BumpFrameBuilder {
|
||||
bump: BumpContainer::new(),
|
||||
head_node_builder: |bump| bump.alloc(VNode::text("")),
|
||||
}
|
||||
.build();
|
||||
|
||||
let new = frames[0].alloc(VNode::Text(VText::new("")));
|
||||
let old_frame = BumpFrameBuilder {
|
||||
bump: BumpContainer::new(),
|
||||
head_node_builder: |bump| bump.alloc(VNode::text("")),
|
||||
}
|
||||
.build();
|
||||
|
||||
let cur_node = new as *mut _;
|
||||
let frames = ActiveFrame::from_frames(old_frame, new_frame);
|
||||
|
||||
Self {
|
||||
hook_arena,
|
||||
hooks,
|
||||
props_type,
|
||||
caller,
|
||||
active_frame,
|
||||
frames,
|
||||
listeners,
|
||||
parent,
|
||||
frames,
|
||||
root_node: cur_node,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,37 +171,50 @@ impl Scope {
|
||||
/// This function downcasts the function pointer based on the stored props_type
|
||||
///
|
||||
/// Props is ?Sized because we borrow the props and don't need to know the size. P (sized) is used as a marker (unsized)
|
||||
pub(crate) fn run<'a, P: Properties + ?Sized>(&self, props: &'a P) {
|
||||
let bump = match self.active_frame {
|
||||
// If the active frame is the first, then we need to bump into the second
|
||||
ActiveFrame::First => &self.frames[1],
|
||||
// If the active frame is the second, then we need to bump into the first
|
||||
ActiveFrame::Second => &self.frames[0],
|
||||
}; // n.b, there might be a better way of doing this active frame stuff - perhaps swapping
|
||||
pub(crate) fn run<'a, 'bump, P: Properties + ?Sized>(&'bump mut self, props: &'a P) {
|
||||
// I really wanted to do this safely, but I don't think we can.
|
||||
// We want to reset the bump before writing into it. This requires &mut to the bump
|
||||
// Ouroborous lets us borrow with self, but the heads (IE the source) cannot be changed while the ref is live
|
||||
|
||||
let ctx = Context {
|
||||
scope: &*self,
|
||||
_p: PhantomData {},
|
||||
arena: &self.hook_arena,
|
||||
hooks: &self.hooks,
|
||||
idx: 0.into(),
|
||||
bump,
|
||||
};
|
||||
// n.b, there might be a better way of doing this active frame stuff - perhaps swapping
|
||||
let frame = self.frames.next();
|
||||
|
||||
/*
|
||||
SAFETY ALERT
|
||||
frame.with_bump(|bump_container| {
|
||||
let bump: &mut Bump = unsafe { &mut *bump_container.0.get() };
|
||||
bump.reset();
|
||||
|
||||
This particular usage of transmute is outlined in its docs https://doc.rust-lang.org/std/mem/fn.transmute.html
|
||||
We hide the generic bound on the function item by casting it to raw pointer. When the function is actually called,
|
||||
we transmute the function back using the props as reference.
|
||||
let bump = &*bump;
|
||||
|
||||
we could do a better check to make sure that the TypeID is correct before casting
|
||||
--
|
||||
This is safe because we check that the generic type matches before casting.
|
||||
*/
|
||||
let caller = unsafe { std::mem::transmute::<*const i32, FC<P>>(self.caller) };
|
||||
let new_nodes = caller(ctx, props);
|
||||
let old_nodes: &mut VNode<'static> = unsafe { &mut *self.root_node };
|
||||
let ctx: Context<'bump> = Context {
|
||||
scope: &*self,
|
||||
_p: PhantomData {},
|
||||
arena: &self.hook_arena,
|
||||
hooks: &self.hooks,
|
||||
idx: 0.into(),
|
||||
bump,
|
||||
};
|
||||
|
||||
/*
|
||||
SAFETY ALERT
|
||||
|
||||
This particular usage of transmute is outlined in its docs https://doc.rust-lang.org/std/mem/fn.transmute.html
|
||||
We hide the generic bound on the function item by casting it to raw pointer. When the function is actually called,
|
||||
we transmute the function back using the props as reference.
|
||||
|
||||
we could do a better check to make sure that the TypeID is correct before casting
|
||||
--
|
||||
This is safe because we check that the generic type matches before casting.
|
||||
*/
|
||||
let caller = unsafe { std::mem::transmute::<*const i32, FC<P>>(self.caller) };
|
||||
let nodes: &'bump VNode = caller(ctx, props);
|
||||
});
|
||||
|
||||
// let new_nodes = caller(ctx, props);
|
||||
// let r = new_nodes as *const _;
|
||||
// self.old_root = self.new_root;
|
||||
// self.new_root = new_nodes as *const _;
|
||||
|
||||
// let old_nodes: &mut VNode<'static> = unsafe { &mut *self.root_node };
|
||||
|
||||
// TODO: Iterate through the new nodes
|
||||
// move any listeners into ourself
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
// use crate::{changelist::EditList, nodes::VNode};
|
||||
use crate::nodes::VNode;
|
||||
use crate::{dodriodiff::DiffMachine, nodes::VNode};
|
||||
use crate::{events::EventTrigger, innerlude::*};
|
||||
use any::Any;
|
||||
use bumpalo::Bump;
|
||||
use generational_arena::{Arena, Index};
|
||||
use std::{
|
||||
any::{self, TypeId},
|
||||
borrow::BorrowMut,
|
||||
cell::{RefCell, UnsafeCell},
|
||||
collections::{vec_deque, VecDeque},
|
||||
future::Future,
|
||||
marker::PhantomData,
|
||||
rc::Rc,
|
||||
@@ -24,7 +26,7 @@ pub struct VirtualDom {
|
||||
/// The index of the root component.
|
||||
base_scope: Index,
|
||||
|
||||
event_queue: Rc<RefCell<Vec<LifecycleEvent>>>,
|
||||
event_queue: Rc<RefCell<VecDeque<LifecycleEvent>>>,
|
||||
|
||||
// Mark the root props with P, even though they're held by the root component
|
||||
// This is done so we don't have a "generic" vdom, making it easier to hold references to it, especially when the holders
|
||||
@@ -65,7 +67,7 @@ impl VirtualDom {
|
||||
let first_event = LifecycleEvent::mount(base_scope, None, 0, root_props);
|
||||
|
||||
// Create an event queue with a mount for the base scope
|
||||
let event_queue = Rc::new(RefCell::new(vec![first_event]));
|
||||
let event_queue = Rc::new(RefCell::new(vec![first_event].into_iter().collect()));
|
||||
|
||||
let _root_prop_type = TypeId::of::<P>();
|
||||
|
||||
@@ -84,12 +86,15 @@ impl VirtualDom {
|
||||
return Err(Error::WrongProps);
|
||||
}
|
||||
|
||||
self.event_queue.borrow_mut().push(LifecycleEvent {
|
||||
event_type: LifecycleType::PropsChanged {
|
||||
props: Box::new(new_props),
|
||||
},
|
||||
index: self.base_scope,
|
||||
});
|
||||
self.event_queue
|
||||
.as_ref()
|
||||
.borrow_mut()
|
||||
.push_back(LifecycleEvent {
|
||||
event_type: LifecycleType::PropsChanged {
|
||||
props: Box::new(new_props),
|
||||
},
|
||||
component_index: self.base_scope,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -103,8 +108,13 @@ impl VirtualDom {
|
||||
/// Update the root props, and progress
|
||||
/// Takes a bump arena to allocate into, making the diff phase as fast as possible
|
||||
pub fn progress(&mut self) -> Result<()> {
|
||||
let event = self.event_queue.borrow_mut().pop().ok_or(Error::NoEvent)?;
|
||||
process_event(&mut self.components, event)
|
||||
let event = self
|
||||
.event_queue
|
||||
.as_ref()
|
||||
.borrow_mut()
|
||||
.pop_front()
|
||||
.ok_or(Error::NoEvent)?;
|
||||
self.process_event(event)
|
||||
}
|
||||
|
||||
/// This method is the most sophisticated way of updating the virtual dom after an external event has been triggered.
|
||||
@@ -151,85 +161,93 @@ impl VirtualDom {
|
||||
// Prop updates take prescedence over subscription updates
|
||||
// Run all prop updates *first* as they will cascade into children.
|
||||
// *then* run the non-prop updates that were not already covered by props
|
||||
let mut events = self.event_queue.borrow_mut();
|
||||
|
||||
// for now, just naively process each event in the queue
|
||||
for event in events.drain(..) {
|
||||
process_event(&mut self.components, event)?;
|
||||
let mut affected_components = Vec::new();
|
||||
// It's essentially draining the vec, but with some dancing to release the RefMut
|
||||
// We also want to be able to push events into the queue from processing the event
|
||||
while let Some(event) = {
|
||||
let new_evt = self.event_queue.as_ref().borrow_mut().pop_front();
|
||||
new_evt
|
||||
} {
|
||||
affected_components.push(event.component_index);
|
||||
self.process_event(event)?;
|
||||
}
|
||||
|
||||
// todo!()
|
||||
let diff_bump = Bump::new();
|
||||
let diff_machine = DiffMachine::new(&diff_bump);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn progress_completely(&mut self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
/// Using mutable access to the Virtual Dom, progress a given lifecycle event
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
fn process_event(
|
||||
&mut self,
|
||||
LifecycleEvent {
|
||||
component_index: index,
|
||||
event_type,
|
||||
}: LifecycleEvent,
|
||||
) -> Result<()> {
|
||||
let scope = self.components.get_mut(index).ok_or(Error::NoEvent)?;
|
||||
|
||||
/// Using mutable access to the Virtual Dom, progress a given lifecycle event
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
fn process_event(
|
||||
// dom: &mut VirtualDom<P>,
|
||||
components: &mut Arena<Scope>,
|
||||
LifecycleEvent { index, event_type }: LifecycleEvent,
|
||||
) -> Result<()> {
|
||||
let scope = components.get(index).ok_or(Error::NoEvent)?;
|
||||
match event_type {
|
||||
// Component needs to be mounted to the virtual dom
|
||||
LifecycleType::Mount { to, under, props } => {
|
||||
if let Some(other) = to {
|
||||
// mount to another component
|
||||
} else {
|
||||
// mount to the root
|
||||
}
|
||||
|
||||
match event_type {
|
||||
// Component needs to be mounted to the virtual dom
|
||||
LifecycleType::Mount { to, under, props } => {
|
||||
if let Some(other) = to {
|
||||
// mount to another component
|
||||
} else {
|
||||
// mount to the root
|
||||
let g = props.as_ref();
|
||||
scope.run(g);
|
||||
// scope.run(runner, props, dom);
|
||||
}
|
||||
|
||||
let g = props.as_ref();
|
||||
scope.run(g);
|
||||
// scope.run(runner, props, dom);
|
||||
}
|
||||
// The parent for this component generated new props and the component needs update
|
||||
LifecycleType::PropsChanged { props } => {
|
||||
//
|
||||
}
|
||||
|
||||
// The parent for this component generated new props and the component needs update
|
||||
LifecycleType::PropsChanged { props } => {
|
||||
// Component was successfully mounted to the dom
|
||||
LifecycleType::Mounted {} => {
|
||||
//
|
||||
}
|
||||
|
||||
// Component was removed from the DOM
|
||||
// Run any destructors and cleanup for the hooks and the dump the component
|
||||
LifecycleType::Removed {} => {
|
||||
let f = self.components.remove(index);
|
||||
// let f = dom.components.remove(index);
|
||||
}
|
||||
|
||||
// Component was messaged via the internal subscription service
|
||||
LifecycleType::Messaged => {
|
||||
//
|
||||
}
|
||||
|
||||
// Event from renderer was fired with a given listener ID
|
||||
//
|
||||
LifecycleType::Callback { listener_id } => {}
|
||||
|
||||
// Run any post-render callbacks on a component
|
||||
LifecycleType::Rendered => {}
|
||||
}
|
||||
|
||||
// Component was successfully mounted to the dom
|
||||
LifecycleType::Mounted {} => {
|
||||
//
|
||||
}
|
||||
|
||||
// Component was removed from the DOM
|
||||
// Run any destructors and cleanup for the hooks and the dump the component
|
||||
LifecycleType::Removed {} => {
|
||||
let f = components.remove(index);
|
||||
// let f = dom.components.remove(index);
|
||||
}
|
||||
|
||||
// Component was messaged via the internal subscription service
|
||||
LifecycleType::Messaged => {
|
||||
//
|
||||
}
|
||||
|
||||
// Event from renderer was fired with a given listener ID
|
||||
//
|
||||
LifecycleType::Callback { listener_id } => {}
|
||||
|
||||
// Run any post-render callbacks on a component
|
||||
LifecycleType::Rendered => {}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct LifecycleEvent {
|
||||
pub index: Index,
|
||||
pub component_index: Index,
|
||||
pub event_type: LifecycleType,
|
||||
}
|
||||
|
||||
@@ -265,7 +283,7 @@ impl LifecycleEvent {
|
||||
props: P,
|
||||
) -> Self {
|
||||
Self {
|
||||
index: which,
|
||||
component_index: which,
|
||||
event_type: LifecycleType::Mount {
|
||||
to,
|
||||
under,
|
||||
|
||||
Reference in new issue
Block a user