mirror of
https://github.com/DioxusLabs/dioxus
synced 2025-02-17 14:18:27 +00:00
wip: remove old create
This commit is contained in:
parent
64f289a61c
commit
7b068202ce
1 changed files with 144 additions and 280 deletions
|
@ -103,6 +103,11 @@ pub struct DiffMachine<'bump> {
|
||||||
|
|
||||||
pub seen_scopes: FxHashSet<ScopeId>,
|
pub seen_scopes: FxHashSet<ScopeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The stack instructions we use to diff and create new nodes.
|
||||||
|
///
|
||||||
|
/// Right now, we insert an instruction for every child node we want to create and diff. This can be less efficient than
|
||||||
|
/// a custom iterator type - but this is current easier to implement. In the future, let's try interact with the stack less.
|
||||||
pub enum DiffInstruction<'a> {
|
pub enum DiffInstruction<'a> {
|
||||||
DiffNode {
|
DiffNode {
|
||||||
old: &'a VNode<'a>,
|
old: &'a VNode<'a>,
|
||||||
|
@ -111,6 +116,7 @@ pub enum DiffInstruction<'a> {
|
||||||
},
|
},
|
||||||
|
|
||||||
Append {},
|
Append {},
|
||||||
|
|
||||||
Replace {
|
Replace {
|
||||||
with: usize,
|
with: usize,
|
||||||
},
|
},
|
||||||
|
@ -189,27 +195,47 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
}
|
}
|
||||||
|
|
||||||
DiffInstruction::Create { node, .. } => {
|
DiffInstruction::Create { node, .. } => {
|
||||||
|
// defer to individual functions so the compiler produces better code
|
||||||
|
// large functions tend to be difficult for the compiler to work with
|
||||||
match &node {
|
match &node {
|
||||||
VNode::Text(text) => {
|
VNode::Text(vtext) => self.create_text_node(vtext),
|
||||||
|
VNode::Suspended(suspended) => self.create_suspended_node(suspended),
|
||||||
|
VNode::Anchor(anchor) => self.create_anchor_node(anchor),
|
||||||
|
VNode::Element(element) => self.create_element_node(element),
|
||||||
|
VNode::Fragment(frag) => self.create_fragment_node(frag),
|
||||||
|
VNode::Component(_) => {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_text_node(&mut self, vtext: &'bump VText<'bump>) {
|
||||||
let real_id = self.vdom.reserve_node();
|
let real_id = self.vdom.reserve_node();
|
||||||
self.edit_create_text_node(text.text, real_id);
|
self.edit_create_text_node(vtext.text, real_id);
|
||||||
text.dom_id.set(Some(real_id));
|
vtext.dom_id.set(Some(real_id));
|
||||||
*self.nodes_created_stack.last_mut().unwrap() += 1;
|
*self.nodes_created_stack.last_mut().unwrap() += 1;
|
||||||
}
|
}
|
||||||
VNode::Suspended(suspended) => {
|
|
||||||
|
fn create_suspended_node(&mut self, suspended: &'bump VSuspended) {
|
||||||
let real_id = self.vdom.reserve_node();
|
let real_id = self.vdom.reserve_node();
|
||||||
self.edit_create_placeholder(real_id);
|
self.edit_create_placeholder(real_id);
|
||||||
suspended.node.set(Some(real_id));
|
suspended.node.set(Some(real_id));
|
||||||
*self.nodes_created_stack.last_mut().unwrap() += 1;
|
*self.nodes_created_stack.last_mut().unwrap() += 1;
|
||||||
}
|
}
|
||||||
VNode::Anchor(anchor) => {
|
|
||||||
|
fn create_anchor_node(&mut self, anchor: &'bump VAnchor) {
|
||||||
let real_id = self.vdom.reserve_node();
|
let real_id = self.vdom.reserve_node();
|
||||||
self.edit_create_placeholder(real_id);
|
self.edit_create_placeholder(real_id);
|
||||||
anchor.dom_id.set(Some(real_id));
|
anchor.dom_id.set(Some(real_id));
|
||||||
*self.nodes_created_stack.last_mut().unwrap() += 1;
|
*self.nodes_created_stack.last_mut().unwrap() += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
VNode::Element(el) => {
|
fn create_element_node(&mut self, element: &'bump VElement<'bump>) {
|
||||||
let VElement {
|
let VElement {
|
||||||
tag_name,
|
tag_name,
|
||||||
listeners,
|
listeners,
|
||||||
|
@ -221,7 +247,7 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
static_listeners: _,
|
static_listeners: _,
|
||||||
dom_id,
|
dom_id,
|
||||||
key,
|
key,
|
||||||
} = el;
|
} = element;
|
||||||
|
|
||||||
let real_id = self.vdom.reserve_node();
|
let real_id = self.vdom.reserve_node();
|
||||||
self.edit_create_element(tag_name, *namespace, real_id);
|
self.edit_create_element(tag_name, *namespace, real_id);
|
||||||
|
@ -253,61 +279,77 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VNode::Fragment(frag) => {
|
fn create_fragment_node(&mut self, frag: &'bump VFragment<'bump>) {
|
||||||
for node in frag.children {
|
for node in frag.children {
|
||||||
self.node_stack.push(DiffInstruction::Create { node })
|
self.node_stack.push(DiffInstruction::Create { node })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VNode::Component(_) => {
|
fn create_component_node(&mut self, vcomponent: &'bump VComponent<'bump>) {
|
||||||
//
|
let caller = vcomponent.caller.clone();
|
||||||
}
|
|
||||||
|
let parent_idx = self.scope_stack.last().unwrap().clone();
|
||||||
|
|
||||||
|
// Insert a new scope into our component list
|
||||||
|
let new_idx = self.vdom.insert_scope_with_key(|new_idx| {
|
||||||
|
let parent_scope = self.get_scope(&parent_idx).unwrap();
|
||||||
|
let height = parent_scope.height + 1;
|
||||||
|
Scope::new(
|
||||||
|
caller,
|
||||||
|
new_idx,
|
||||||
|
Some(parent_idx),
|
||||||
|
height,
|
||||||
|
ScopeChildren(vcomponent.children),
|
||||||
|
self.vdom.clone(),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Actually initialize the caller's slot with the right address
|
||||||
|
vcomponent.ass_scope.set(Some(new_idx));
|
||||||
|
|
||||||
|
if !vcomponent.can_memoize {
|
||||||
|
let cur_scope = self.get_scope_mut(&parent_idx).unwrap();
|
||||||
|
let extended = vcomponent as *const VComponent;
|
||||||
|
let extended: *const VComponent<'static> = unsafe { std::mem::transmute(extended) };
|
||||||
|
cur_scope.borrowed_props.borrow_mut().push(extended);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// add noderefs to current noderef list Noderefs
|
||||||
|
// add effects to current effect list Effects
|
||||||
|
|
||||||
|
let new_component = self.get_scope_mut(&new_idx).unwrap();
|
||||||
|
|
||||||
|
// Run the scope for one iteration to initialize it
|
||||||
|
match new_component.run_scope() {
|
||||||
|
Ok(_) => {
|
||||||
|
// all good, new nodes exist
|
||||||
}
|
}
|
||||||
|
Err(err) => {
|
||||||
|
// failed to run. this is the first time the component ran, and it failed
|
||||||
|
// we manually set its head node to an empty fragment
|
||||||
|
panic!("failing components not yet implemented");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
// Take the node that was just generated from running the component
|
||||||
|
let nextnode = new_component.frames.fin_head();
|
||||||
|
|
||||||
|
// Push the new scope onto the stack
|
||||||
|
self.scope_stack.push(new_idx);
|
||||||
|
|
||||||
|
// Run the creation algorithm with this scope on the stack
|
||||||
|
let meta = self.create_vnode(nextnode);
|
||||||
|
|
||||||
|
// pop the scope off the stack
|
||||||
|
self.scope_stack.pop();
|
||||||
|
|
||||||
|
if meta.added_to_stack == 0 {
|
||||||
|
panic!("Components should *always* generate nodes - even if they fail");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_text_node(&mut self) {}
|
// Finally, insert this scope as a seen node.
|
||||||
|
self.seen_scopes.insert(new_idx);
|
||||||
/// Create the new node, pushing instructions on our instruction stack to create any further children
|
|
||||||
///
|
|
||||||
///
|
|
||||||
pub fn create_iterative(&mut self, node: &'bump VNode<'bump>) {
|
|
||||||
match &node {
|
|
||||||
// singles
|
|
||||||
// update the parent
|
|
||||||
VNode::Text(text) => {
|
|
||||||
let real_id = self.vdom.reserve_node();
|
|
||||||
self.edit_create_text_node(text.text, real_id);
|
|
||||||
text.dom_id.set(Some(real_id));
|
|
||||||
*self.nodes_created_stack.last_mut().unwrap() += 1;
|
|
||||||
}
|
|
||||||
VNode::Suspended(suspended) => {
|
|
||||||
let real_id = self.vdom.reserve_node();
|
|
||||||
self.edit_create_placeholder(real_id);
|
|
||||||
suspended.node.set(Some(real_id));
|
|
||||||
*self.nodes_created_stack.last_mut().unwrap() += 1;
|
|
||||||
}
|
|
||||||
VNode::Anchor(anchor) => {
|
|
||||||
let real_id = self.vdom.reserve_node();
|
|
||||||
self.edit_create_placeholder(real_id);
|
|
||||||
anchor.dom_id.set(Some(real_id));
|
|
||||||
*self.nodes_created_stack.last_mut().unwrap() += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
VNode::Element(el) => {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
VNode::Fragment(frag) => {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
VNode::Component(comp) => {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diff_iterative(&mut self, old_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>) {
|
pub fn diff_iterative(&mut self, old_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>) {
|
||||||
|
@ -734,184 +776,6 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit instructions to create the given virtual node.
|
|
||||||
//
|
|
||||||
// The change list stack may have any shape upon entering this function:
|
|
||||||
//
|
|
||||||
// [...]
|
|
||||||
//
|
|
||||||
// When this function returns, the new node is on top of the change list stack:
|
|
||||||
//
|
|
||||||
// [... node]
|
|
||||||
pub fn create_vnode(&mut self, node: &'bump VNode<'bump>) -> CreateMeta {
|
|
||||||
match &node {
|
|
||||||
VNode::Text(text) => {
|
|
||||||
let real_id = self.vdom.reserve_node();
|
|
||||||
self.edit_create_text_node(text.text, real_id);
|
|
||||||
text.dom_id.set(Some(real_id));
|
|
||||||
CreateMeta::new(text.is_static, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
VNode::Anchor(anchor) => {
|
|
||||||
let real_id = self.vdom.reserve_node();
|
|
||||||
self.edit_create_placeholder(real_id);
|
|
||||||
anchor.dom_id.set(Some(real_id));
|
|
||||||
CreateMeta::new(false, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
VNode::Element(el) => {
|
|
||||||
// we have the potential to completely eliminate working on this node in the future(!)
|
|
||||||
//
|
|
||||||
// This can only be done if all of the elements properties (attrs, children, listeners, etc) are static
|
|
||||||
// While creating these things, keep track if we can memoize this element.
|
|
||||||
// At the end, we'll set this flag on the element to skip it
|
|
||||||
let mut is_static: bool = true;
|
|
||||||
|
|
||||||
let VElement {
|
|
||||||
tag_name,
|
|
||||||
listeners,
|
|
||||||
attributes,
|
|
||||||
children,
|
|
||||||
namespace,
|
|
||||||
static_attrs: _,
|
|
||||||
static_children: _,
|
|
||||||
static_listeners: _,
|
|
||||||
dom_id,
|
|
||||||
key,
|
|
||||||
} = el;
|
|
||||||
|
|
||||||
let real_id = self.vdom.reserve_node();
|
|
||||||
self.edit_create_element(tag_name, *namespace, real_id);
|
|
||||||
dom_id.set(Some(real_id));
|
|
||||||
|
|
||||||
let cur_scope = self.current_scope().unwrap();
|
|
||||||
|
|
||||||
listeners.iter().for_each(|listener| {
|
|
||||||
self.fix_listener(listener);
|
|
||||||
listener.mounted_node.set(Some(real_id));
|
|
||||||
self.edit_new_event_listener(listener, cur_scope.clone());
|
|
||||||
|
|
||||||
// if the node has an event listener, then it must be visited ?
|
|
||||||
is_static = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
for attr in *attributes {
|
|
||||||
is_static = is_static && attr.is_static;
|
|
||||||
self.edit_set_attribute(attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fast path: if there is a single text child, it is faster to
|
|
||||||
// create-and-append the text node all at once via setting the
|
|
||||||
// parent's `textContent` in a single change list instruction than
|
|
||||||
// to emit three instructions to (1) create a text node, (2) set its
|
|
||||||
// text content, and finally (3) append the text node to this
|
|
||||||
// parent.
|
|
||||||
//
|
|
||||||
// Notice: this is a web-specific optimization and may be changed in the future
|
|
||||||
//
|
|
||||||
// TODO move over
|
|
||||||
// if children.len() == 1 {
|
|
||||||
// if let VNodeKind::Text(text) = &children[0] {
|
|
||||||
// self.set_text(text.text);
|
|
||||||
// return CreateMeta::new(is_static, 1);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
for child in *children {
|
|
||||||
let child_meta = self.create_vnode(child);
|
|
||||||
is_static = is_static && child_meta.is_static;
|
|
||||||
|
|
||||||
// append whatever children were generated by this call
|
|
||||||
self.edit_append_children(child_meta.added_to_stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateMeta::new(is_static, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
VNode::Component(vcomponent) => {
|
|
||||||
let caller = vcomponent.caller.clone();
|
|
||||||
|
|
||||||
let parent_idx = self.scope_stack.last().unwrap().clone();
|
|
||||||
|
|
||||||
// Insert a new scope into our component list
|
|
||||||
let new_idx = self.vdom.insert_scope_with_key(|new_idx| {
|
|
||||||
let parent_scope = self.get_scope(&parent_idx).unwrap();
|
|
||||||
let height = parent_scope.height + 1;
|
|
||||||
Scope::new(
|
|
||||||
caller,
|
|
||||||
new_idx,
|
|
||||||
Some(parent_idx),
|
|
||||||
height,
|
|
||||||
ScopeChildren(vcomponent.children),
|
|
||||||
self.vdom.clone(),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Actually initialize the caller's slot with the right address
|
|
||||||
vcomponent.ass_scope.set(Some(new_idx));
|
|
||||||
|
|
||||||
if !vcomponent.can_memoize {
|
|
||||||
let cur_scope = self.get_scope_mut(&parent_idx).unwrap();
|
|
||||||
let extended = *vcomponent as *const VComponent;
|
|
||||||
let extended: *const VComponent<'static> =
|
|
||||||
unsafe { std::mem::transmute(extended) };
|
|
||||||
cur_scope.borrowed_props.borrow_mut().push(extended);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// add noderefs to current noderef list Noderefs
|
|
||||||
// add effects to current effect list Effects
|
|
||||||
|
|
||||||
let new_component = self.get_scope_mut(&new_idx).unwrap();
|
|
||||||
|
|
||||||
// Run the scope for one iteration to initialize it
|
|
||||||
match new_component.run_scope() {
|
|
||||||
Ok(_) => {
|
|
||||||
// all good, new nodes exist
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
// failed to run. this is the first time the component ran, and it failed
|
|
||||||
// we manually set its head node to an empty fragment
|
|
||||||
panic!("failing components not yet implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take the node that was just generated from running the component
|
|
||||||
let nextnode = new_component.frames.fin_head();
|
|
||||||
|
|
||||||
// Push the new scope onto the stack
|
|
||||||
self.scope_stack.push(new_idx);
|
|
||||||
|
|
||||||
// Run the creation algorithm with this scope on the stack
|
|
||||||
let meta = self.create_vnode(nextnode);
|
|
||||||
|
|
||||||
// pop the scope off the stack
|
|
||||||
self.scope_stack.pop();
|
|
||||||
|
|
||||||
if meta.added_to_stack == 0 {
|
|
||||||
panic!("Components should *always* generate nodes - even if they fail");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, insert this scope as a seen node.
|
|
||||||
self.seen_scopes.insert(new_idx);
|
|
||||||
|
|
||||||
CreateMeta::new(vcomponent.is_static, meta.added_to_stack)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fragments are the only nodes that can contain dynamic content (IE through curlies or iterators).
|
|
||||||
// We can never ignore their contents, so the prescence of a fragment indicates that we need always diff them.
|
|
||||||
// Fragments will just put all their nodes onto the stack after creation
|
|
||||||
VNode::Fragment(frag) => self.create_children(frag.children),
|
|
||||||
|
|
||||||
VNode::Suspended(VSuspended { node: real_node }) => {
|
|
||||||
let id = self.vdom.reserve_node();
|
|
||||||
self.edit_create_placeholder(id);
|
|
||||||
real_node.set(Some(id));
|
|
||||||
CreateMeta::new(false, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_children(&mut self, children: &'bump [VNode<'bump>]) -> CreateMeta {
|
fn create_children(&mut self, children: &'bump [VNode<'bump>]) -> CreateMeta {
|
||||||
let mut is_static = true;
|
let mut is_static = true;
|
||||||
let mut added_to_stack = 0;
|
let mut added_to_stack = 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue