浏览代码

chore: wipe away old src

Jonathan Kelley 2 年之前
父节点
当前提交
d407035931

+ 0 - 237
packages/core/src.old/arbitrary_value.rs

@@ -1,237 +0,0 @@
-use std::{any::Any, fmt::Formatter};
-
-/// Possible values for an attribute
-// trying to keep values at 3 bytes
-#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serialize", serde(untagged))]
-#[derive(Clone, Debug, PartialEq)]
-#[allow(missing_docs)]
-pub enum AttributeValue<'a> {
-    Text(&'a str),
-    Float32(f32),
-    Float64(f64),
-    Int32(i32),
-    Int64(i64),
-    Uint32(u32),
-    Uint64(u64),
-    Bool(bool),
-
-    Vec3Float(f32, f32, f32),
-    Vec3Int(i32, i32, i32),
-    Vec3Uint(u32, u32, u32),
-
-    Vec4Float(f32, f32, f32, f32),
-    Vec4Int(i32, i32, i32, i32),
-    Vec4Uint(u32, u32, u32, u32),
-
-    Bytes(&'a [u8]),
-    // Any(ArbitraryAttributeValue<'a>),
-}
-
-// todo
-#[allow(missing_docs)]
-impl<'a> AttributeValue<'a> {
-    pub fn is_truthy(&self) -> bool {
-        match self {
-            AttributeValue::Text(t) => *t == "true",
-            AttributeValue::Bool(t) => *t,
-            _ => false,
-        }
-    }
-
-    pub fn is_falsy(&self) -> bool {
-        match self {
-            AttributeValue::Text(t) => *t == "false",
-            AttributeValue::Bool(t) => !(*t),
-            _ => false,
-        }
-    }
-}
-
-impl<'a> std::fmt::Display for AttributeValue<'a> {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        match self {
-            AttributeValue::Text(a) => write!(f, "{}", a),
-            AttributeValue::Float32(a) => write!(f, "{}", a),
-            AttributeValue::Float64(a) => write!(f, "{}", a),
-            AttributeValue::Int32(a) => write!(f, "{}", a),
-            AttributeValue::Int64(a) => write!(f, "{}", a),
-            AttributeValue::Uint32(a) => write!(f, "{}", a),
-            AttributeValue::Uint64(a) => write!(f, "{}", a),
-            AttributeValue::Bool(a) => write!(f, "{}", a),
-            AttributeValue::Vec3Float(_, _, _) => todo!(),
-            AttributeValue::Vec3Int(_, _, _) => todo!(),
-            AttributeValue::Vec3Uint(_, _, _) => todo!(),
-            AttributeValue::Vec4Float(_, _, _, _) => todo!(),
-            AttributeValue::Vec4Int(_, _, _, _) => todo!(),
-            AttributeValue::Vec4Uint(_, _, _, _) => todo!(),
-            AttributeValue::Bytes(a) => write!(f, "{:?}", a),
-            // AttributeValue::Any(a) => write!(f, "{:?}", a),
-        }
-    }
-}
-
-#[derive(Clone, Copy)]
-#[allow(missing_docs)]
-pub struct ArbitraryAttributeValue<'a> {
-    pub value: &'a dyn Any,
-    pub cmp: fn(&'a dyn std::any::Any, &'a dyn std::any::Any) -> bool,
-}
-
-// pub trait AnyAttrValue {}
-
-// impl PartialEq for ArbitraryAttributeValue<'_> {
-//     fn eq(&self, other: &Self) -> bool {
-//         (self.cmp)(self.value, other.value)
-//     }
-// }
-
-impl std::fmt::Debug for ArbitraryAttributeValue<'_> {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("ArbitraryAttributeValue").finish()
-    }
-}
-
-#[cfg(feature = "serialize")]
-impl<'a> serde::Serialize for ArbitraryAttributeValue<'a> {
-    fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        panic!("ArbitraryAttributeValue should not be serialized")
-    }
-}
-#[cfg(feature = "serialize")]
-impl<'de, 'a> serde::Deserialize<'de> for &'a ArbitraryAttributeValue<'a> {
-    fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
-    where
-        D: serde::Deserializer<'de>,
-    {
-        panic!("ArbitraryAttributeValue is not deserializable!")
-    }
-}
-#[cfg(feature = "serialize")]
-impl<'de, 'a> serde::Deserialize<'de> for ArbitraryAttributeValue<'a> {
-    fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
-    where
-        D: serde::Deserializer<'de>,
-    {
-        panic!("ArbitraryAttributeValue is not deserializable!")
-    }
-}
-
-// todo
-#[allow(missing_docs)]
-impl<'a> AttributeValue<'a> {
-    pub fn as_text(&self) -> Option<&'a str> {
-        match self {
-            AttributeValue::Text(s) => Some(s),
-            _ => None,
-        }
-    }
-
-    pub fn as_float32(&self) -> Option<f32> {
-        match self {
-            AttributeValue::Float32(f) => Some(*f),
-            _ => None,
-        }
-    }
-
-    pub fn as_float64(&self) -> Option<f64> {
-        match self {
-            AttributeValue::Float64(f) => Some(*f),
-            _ => None,
-        }
-    }
-
-    pub fn as_int32(&self) -> Option<i32> {
-        match self {
-            AttributeValue::Int32(i) => Some(*i),
-            _ => None,
-        }
-    }
-
-    pub fn as_int64(&self) -> Option<i64> {
-        match self {
-            AttributeValue::Int64(i) => Some(*i),
-            _ => None,
-        }
-    }
-
-    pub fn as_uint32(&self) -> Option<u32> {
-        match self {
-            AttributeValue::Uint32(i) => Some(*i),
-            _ => None,
-        }
-    }
-
-    pub fn as_uint64(&self) -> Option<u64> {
-        match self {
-            AttributeValue::Uint64(i) => Some(*i),
-            _ => None,
-        }
-    }
-
-    pub fn as_bool(&self) -> Option<bool> {
-        match self {
-            AttributeValue::Bool(b) => Some(*b),
-            _ => None,
-        }
-    }
-
-    pub fn as_vec3_float(&self) -> Option<(f32, f32, f32)> {
-        match self {
-            AttributeValue::Vec3Float(x, y, z) => Some((*x, *y, *z)),
-            _ => None,
-        }
-    }
-
-    pub fn as_vec3_int(&self) -> Option<(i32, i32, i32)> {
-        match self {
-            AttributeValue::Vec3Int(x, y, z) => Some((*x, *y, *z)),
-            _ => None,
-        }
-    }
-
-    pub fn as_vec3_uint(&self) -> Option<(u32, u32, u32)> {
-        match self {
-            AttributeValue::Vec3Uint(x, y, z) => Some((*x, *y, *z)),
-            _ => None,
-        }
-    }
-
-    pub fn as_vec4_float(&self) -> Option<(f32, f32, f32, f32)> {
-        match self {
-            AttributeValue::Vec4Float(x, y, z, w) => Some((*x, *y, *z, *w)),
-            _ => None,
-        }
-    }
-
-    pub fn as_vec4_int(&self) -> Option<(i32, i32, i32, i32)> {
-        match self {
-            AttributeValue::Vec4Int(x, y, z, w) => Some((*x, *y, *z, *w)),
-            _ => None,
-        }
-    }
-
-    pub fn as_vec4_uint(&self) -> Option<(u32, u32, u32, u32)> {
-        match self {
-            AttributeValue::Vec4Uint(x, y, z, w) => Some((*x, *y, *z, *w)),
-            _ => None,
-        }
-    }
-
-    pub fn as_bytes(&self) -> Option<&[u8]> {
-        match self {
-            AttributeValue::Bytes(b) => Some(b),
-            _ => None,
-        }
-    }
-
-    // pub fn as_any(&self) -> Option<&'a ArbitraryAttributeValue> {
-    //     match self {
-    //         AttributeValue::Any(a) => Some(a),
-    //         _ => None,
-    //     }
-    // }
-}

+ 0 - 1246
packages/core/src.old/diff.rs

@@ -1,1246 +0,0 @@
-#![warn(clippy::pedantic)]
-#![allow(clippy::cast_possible_truncation)]
-
-//! This module contains the stateful [`DiffState`] and all methods to diff [`VNode`]s, their properties, and their children.
-//!
-//! The [`DiffState`] calculates the diffs between the old and new frames, updates the new nodes, and generates a set
-//! of mutations for the renderer to apply.
-//!
-//! ## Notice:
-//!
-//! The inspiration and code for this module was originally taken from Dodrio (@fitzgen) and then modified to support
-//! Components, Fragments, Suspense, `SubTree` memoization, incremental diffing, cancellation, pausing, priority
-//! scheduling, and additional batching operations.
-//!
-//! ## Implementation Details:
-//!
-//! ### IDs for elements
-//! --------------------
-//! All nodes are addressed by their IDs.
-//! We don't necessarily require that DOM changes happen instantly during the diffing process, so the implementor may choose
-//! to batch nodes if it is more performant for their application. The element IDs are indices into the internal element
-//! array. The expectation is that implementors will use the ID as an index into a Vec of real nodes, allowing for passive
-//! garbage collection as the [`crate::VirtualDom`] replaces old nodes.
-//!
-//! When new vnodes are created through `cx.render`, they won't know which real node they correspond to. During diffing,
-//! we always make sure to copy over the ID. If we don't do this properly, the [`ElementId`] will be populated incorrectly
-//! and brick the user's page.
-//!
-//! ### Fragment Support
-//! --------------------
-//! Fragments (nodes without a parent) are supported through a combination of "replace with" and anchor vnodes. Fragments
-//! can be particularly challenging when they are empty, so the anchor node lets us "reserve" a spot for the empty
-//! fragment to be replaced with when it is no longer empty. This is guaranteed by logic in the [`crate::innerlude::NodeFactory`] - it is
-//! impossible to craft a fragment with 0 elements - they must always have at least a single placeholder element. Adding
-//! "dummy" nodes _is_ inefficient, but it makes our diffing algorithm faster and the implementation is completely up to
-//! the platform.
-//!
-//! Other implementations either don't support fragments or use a "child + sibling" pattern to represent them. Our code is
-//! vastly simpler and more performant when we can just create a placeholder element while the fragment has no children.
-//!
-//! ## Subtree Memoization
-//! -----------------------
-//! We also employ "subtree memoization" which saves us from having to check trees which hold no dynamic content. We can
-//! detect if a subtree is "static" by checking if its children are "static". Since we dive into the tree depth-first, the
-//! calls to "create" propagate this information upwards. Structures like the one below are entirely static:
-//! ```rust, ignore
-//! rsx!( div { class: "hello world", "this node is entirely static" } )
-//! ```
-//! Because the subtrees won't be diffed, their "real node" data will be stale (invalid), so it's up to the reconciler to
-//! track nodes created in a scope and clean up all relevant data. Support for this is currently WIP and depends on comp-time
-//! hashing of the subtree from the rsx! macro. We do a very limited form of static analysis via static string pointers as
-//! a way of short-circuiting the most expensive checks.
-//!
-//! ## Bloom Filter and Heuristics
-//! ------------------------------
-//! For all components, we employ some basic heuristics to speed up allocations and pre-size bump arenas. The heuristics are
-//! currently very rough, but will get better as time goes on. The information currently tracked includes the size of a
-//! bump arena after first render, the number of hooks, and the number of nodes in the tree.
-//!
-//! ## Garbage Collection
-//! ---------------------
-//! Dioxus uses a passive garbage collection system to clean up old nodes once the work has been completed. This garbage
-//! collection is done internally once the main diffing work is complete. After the "garbage" is collected, Dioxus will then
-//! start to re-use old keys for new nodes. This results in a passive memory management system that is very efficient.
-//!
-//! The IDs used by the key/map are just an index into a Vec. This means that Dioxus will drive the key allocation strategy
-//! so the client only needs to maintain a simple list of nodes. By default, Dioxus will not manually clean up old nodes
-//! for the client. As new nodes are created, old nodes will be over-written.
-//!
-//! ## Further Reading and Thoughts
-//! ----------------------------
-//! There are more ways of increasing diff performance here that are currently not implemented.
-//! - Strong memoization of subtrees.
-//! - Guided diffing.
-//! - Certain web-dom-specific optimizations.
-//!
-//! More info on how to improve this diffing algorithm:
-//!  - <https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/>
-
-use crate::{
-    innerlude::{
-        AnyProps, ElementId, Renderer, ScopeArena, ScopeId, TemplateNode, VComponent, VElement,
-        VFragment, VNode, VTemplate, VText,
-    },
-    AttributeValue,
-};
-use fxhash::{FxHashMap, FxHashSet};
-use smallvec::{smallvec, SmallVec};
-
-pub(crate) struct DiffState<'a, 'bump, R: Renderer<'bump>> {
-    pub(crate) scopes: &'bump ScopeArena,
-    pub(crate) mutations: &'a mut R,
-    pub(crate) force_diff: bool,
-    pub(crate) element_stack: SmallVec<[ElementId; 10]>,
-    pub(crate) scope_stack: SmallVec<[ScopeId; 5]>,
-}
-
-impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
-    pub fn new(scopes: &'b ScopeArena, renderer: &'a mut R) -> Self {
-        Self {
-            scopes,
-            mutations: renderer,
-            force_diff: false,
-            element_stack: smallvec![],
-            scope_stack: smallvec![],
-        }
-    }
-
-    pub fn diff_scope(&mut self, scopeid: ScopeId) {
-        let (old, new) = (self.scopes.wip_head(scopeid), self.scopes.fin_head(scopeid));
-        let scope = self.scopes.get_scope(scopeid).unwrap();
-
-        self.scope_stack.push(scopeid);
-        self.element_stack.push(scope.container);
-        self.diff_node(old, new);
-        self.element_stack.pop();
-        self.scope_stack.pop();
-
-        self.mutations.mark_dirty_scope(scopeid);
-    }
-
-    pub fn diff_node(&mut self, old_node: &'b VNode<'b>, new_node: &'b VNode<'b>) {
-        use VNode::{Component, Element, Fragment, Template, Text};
-
-        // Same node by ref, no need to diff.
-        if std::ptr::eq(old_node, new_node) {
-            return;
-        }
-
-        match (old_node, new_node) {
-            (Text(old), Text(new)) => self.diff_text(old, new, old_node, new_node),
-            (Element(old), Element(new)) => self.diff_element(old, new, old_node, new_node),
-            (Component(old), Component(new)) => self.diff_component(old_node, new_node, *old, *new),
-            (Fragment(old), Fragment(new)) => self.diff_fragment(old, new),
-            (Template(old), Template(new)) => self.diff_templates(old, new, old_node, new_node),
-
-            (
-                Component(_) | Text(_) | Element(_) | Template(_) | Fragment(_),
-                Component(_) | Text(_) | Element(_) | Template(_) | Fragment(_),
-            ) => self.replace_node(old_node, new_node),
-        }
-    }
-
-    pub fn create_node(&mut self, node: &'b VNode<'b>) -> usize {
-        match node {
-            VNode::Text(vtext) => self.create_text(vtext, node),
-            VNode::Element(element) => self.create_element(element, node),
-            VNode::Fragment(frag) => self.create_fragment(frag),
-            VNode::Component(component) => self.create_component_node(*component),
-            VNode::Template(template) => self.create_template_node(template, node),
-        }
-    }
-
-    fn create_text(&mut self, text: &'b VText<'b>, node: &'b VNode<'b>) -> usize {
-        let real_id = self.scopes.reserve_node(node);
-        text.id.set(Some(real_id));
-        self.mutations.create_text_node(text.text, real_id);
-        1
-    }
-
-    fn create_element(&mut self, element: &'b VElement<'b>, node: &'b VNode<'b>) -> usize {
-        let VElement {
-            tag: tag_name,
-            listeners,
-            attributes,
-            children,
-            namespace,
-            id: dom_id,
-            parent: parent_id,
-            ..
-        } = &element;
-
-        parent_id.set(self.element_stack.last().copied());
-
-        let real_id = self.scopes.reserve_node(node);
-
-        dom_id.set(Some(real_id));
-
-        self.element_stack.push(real_id);
-        {
-            self.mutations.create_element(tag_name, *namespace, real_id);
-
-            let cur_scope_id = self.current_scope();
-
-            for listener in listeners.iter() {
-                listener.mounted_node.set(real_id);
-                self.mutations.new_event_listener(listener, cur_scope_id);
-            }
-
-            for attr in attributes.iter() {
-                self.mutations
-                    .set_attribute(attr.name, attr.value, attr.namespace, real_id);
-            }
-
-            if !children.is_empty() {
-                self.create_and_append_children(children);
-            }
-        }
-        self.element_stack.pop();
-
-        1
-    }
-
-    fn create_fragment(&mut self, frag: &'b VFragment<'b>) -> usize {
-        self.create_children(frag.children)
-    }
-
-    fn create_component_node(&mut self, vcomponent: &'b VComponent<'b>) -> usize {
-        let parent_idx = self.current_scope();
-
-        // the component might already exist - if it does, we need to reuse it
-        // this makes figure out when to drop the component more complicated
-        let new_idx = if let Some(idx) = vcomponent.scope.get() {
-            assert!(self.scopes.get_scope(idx).is_some());
-            idx
-        } else {
-            // Insert a new scope into our component list
-            let props: Box<dyn AnyProps + 'b> = vcomponent.props.borrow_mut().take().unwrap();
-            let props: Box<dyn AnyProps + 'static> = unsafe { std::mem::transmute(props) };
-            self.scopes.new_with_key(
-                vcomponent.user_fc,
-                props,
-                Some(parent_idx),
-                self.element_stack.last().copied().unwrap(),
-                0,
-            )
-        };
-
-        // Actually initialize the caller's slot with the right address
-        vcomponent.scope.set(Some(new_idx));
-
-        log::trace!(
-            "created component \"{}\", id: {:?} parent {:?}",
-            vcomponent.fn_name,
-            new_idx,
-            parent_idx,
-        );
-
-        // if vcomponent.can_memoize {
-        //     // todo: implement promotion logic. save us from boxing props that we don't need
-        // } else {
-        //     // track this component internally so we know the right drop order
-        // }
-
-        self.enter_scope(new_idx);
-
-        let created = {
-            // Run the scope for one iteration to initialize it
-            self.scopes.run_scope(new_idx);
-            self.mutations.mark_dirty_scope(new_idx);
-
-            // Take the node that was just generated from running the component
-            let nextnode = self.scopes.fin_head(new_idx);
-            self.create_node(nextnode)
-        };
-
-        self.leave_scope();
-
-        created
-    }
-
-    pub(crate) fn diff_text(
-        &mut self,
-        old: &'b VText<'b>,
-        new: &'b VText<'b>,
-        _old_node: &'b VNode<'b>,
-        new_node: &'b VNode<'b>,
-    ) {
-        // if the node is comming back not assigned, that means it was borrowed but removed
-        let root = match old.id.get() {
-            Some(id) => id,
-            None => self.scopes.reserve_node(new_node),
-        };
-
-        if old.text != new.text {
-            self.mutations.set_text(new.text, root);
-        }
-
-        self.scopes.update_node(new_node, root);
-
-        new.id.set(Some(root));
-    }
-
-    fn diff_templates(
-        &mut self,
-        old: &'b VTemplate<'b>,
-        new: &'b VTemplate<'b>,
-        old_node: &'b VNode<'b>,
-        new_node: &'b VNode<'b>,
-    ) {
-        if old.template.id != new.template.id {
-            return self.replace_node(old_node, new_node);
-        }
-
-        // if they're the same, just diff the dynamic nodes directly
-        for (left, right) in old.dynamic_nodes.iter().zip(new.dynamic_nodes.iter()) {
-            self.diff_node(&left.node, &right.node);
-        }
-
-        for (left, right) in old.dynamic_attrs.iter().zip(new.dynamic_attrs.iter()) {
-            let id = left.mounted_element.get();
-            right.mounted_element.set(id);
-
-            for (left, right) in right.attrs.iter().zip(left.attrs.iter()) {
-                if right.value != left.value || right.volatile {
-                    self.mutations
-                        .set_attribute(right.name, right.value, right.namespace, id);
-                }
-            }
-
-            // There's not really any diffing that needs to happen for listeners
-            for listener in right.listeners {
-                listener.mounted_node.set(id);
-            }
-        }
-    }
-
-    fn create_static_template_nodes(&mut self, node: &'b TemplateNode, id: ElementId) {
-        match *node {
-            TemplateNode::Element {
-                tag,
-                attrs,
-                children,
-                namespace,
-            } => {
-                self.mutations.create_element(tag, namespace, id);
-                for attr in attrs {
-                    self.mutations.set_attribute(
-                        attr.name,
-                        AttributeValue::Text(attr.value),
-                        attr.namespace,
-                        id,
-                    );
-                }
-                for child in children.iter() {
-                    self.create_static_template_nodes(child, id);
-                }
-                self.mutations.append_children(children.len() as u32);
-            }
-            TemplateNode::Text(text) => self.mutations.create_text_node(text, id),
-            TemplateNode::Dynamic(_) => self.mutations.create_placeholder(id),
-        }
-    }
-
-    /// Create the template from scratch using instructions, cache it, and then use the instructions to build it
-    ///
-    /// This would be way easier if the ID could just be unique *after* cloning
-    ///
-    /// If we traversed the template
-    fn create_template_node(&mut self, template: &'b VTemplate<'b>, node: &'b VNode<'b>) -> usize {
-        // Reserve a single node for all the template nodes to reuse
-        template.node_id.set(self.scopes.reserve_node(node));
-
-        // Save the template if it doesn't exist
-        // todo: use &mut cache instead of borrowed cache
-        let mut templates = self.scopes.template_cache.borrow_mut();
-        if !templates.contains(&template.template) {
-            template
-                .template
-                .roots
-                .into_iter()
-                .for_each(|node| self.create_static_template_nodes(node, template.node_id.get()));
-
-            self.mutations
-                .save(template.template.id, template.template.roots.len() as u32);
-
-            templates.insert(template.template);
-        }
-
-        // Walk the roots backwards, creating nodes and assigning IDs
-        let mut dynamic_attrs = template.dynamic_attrs.iter().peekable();
-        let mut dynamic_nodes = template.dynamic_nodes.iter().peekable();
-
-        let mut on_stack = 0;
-        for (root_idx, root) in template.template.roots.iter().enumerate() {
-            on_stack += match root {
-                TemplateNode::Dynamic(id) => self.create_node(&template.dynamic_nodes[*id].node),
-                TemplateNode::Element { .. } | TemplateNode::Text(_) => 1,
-            };
-
-            // we're on top of a node that has a dynamic attribute for a descndent
-            // Set that attribute now before the stack gets in a weird state
-            // Roots may not be more than 255 nodes long, enforced by the macro
-            while let Some(loc) = dynamic_attrs.next_if(|attr| attr.pathway[0] == root_idx as u8) {
-                // Attach all the elementIDs to the nodes with dynamic content
-                let id = self.scopes.reserve_node(node);
-                self.mutations.assign_id(&loc.pathway[1..], id);
-                loc.mounted_element.set(id);
-
-                for attr in loc.attrs {
-                    self.mutations
-                        .set_attribute(attr.name, attr.value, attr.namespace, id);
-                }
-
-                for listener in loc.listeners {
-                    listener.mounted_node.set(id);
-                }
-            }
-
-            while let Some(dyn_node) = dynamic_nodes.next_if(|f| f.pathway[0] == root_idx as u8) {
-                // we're on top of a node that has a dynamic node for a descndent
-                // Set that node now
-                // Roots may not be more than 255 nodes long, enforced by the macro
-                if dyn_node.pathway[0] == root_idx as u8 {
-                    let created = self.create_node(&dyn_node.node);
-
-                    self.mutations
-                        .replace_descendant(&dyn_node.pathway[1..], created as u32);
-                }
-            }
-        }
-
-        on_stack
-    }
-
-    fn diff_element(
-        &mut self,
-        old: &'b VElement<'b>,
-        new: &'b VElement<'b>,
-        old_node: &'b VNode<'b>,
-        new_node: &'b VNode<'b>,
-    ) {
-        // if the node is comming back not assigned, that means it was borrowed but removed
-        let root = match old.id.get() {
-            Some(id) => id,
-            None => self.scopes.reserve_node(new_node),
-        };
-
-        // If the element type is completely different, the element needs to be re-rendered completely
-        // This is an optimization React makes due to how users structure their code
-        //
-        // This case is rather rare (typically only in non-keyed lists)
-        if new.tag != old.tag || new.namespace != old.namespace {
-            self.replace_node(old_node, new_node);
-            return;
-        }
-
-        self.scopes.update_node(new_node, root);
-
-        new.id.set(Some(root));
-        new.parent.set(old.parent.get());
-
-        // todo: attributes currently rely on the element on top of the stack, but in theory, we only need the id of the
-        // element to modify its attributes.
-        // it would result in fewer instructions if we just set the id directly.
-        // it would also clean up this code some, but that's not very important anyways
-
-        // Diff Attributes
-        //
-        // It's extraordinarily rare to have the number/order of attributes change
-        // In these cases, we just completely erase the old set and make a new set
-        //
-        // TODO: take a more efficient path than this
-        if old.attributes.len() == new.attributes.len() {
-            for (old_attr, new_attr) in old.attributes.iter().zip(new.attributes.iter()) {
-                if old_attr.value != new_attr.value || new_attr.volatile {
-                    self.mutations.set_attribute(
-                        new_attr.name,
-                        new_attr.value,
-                        new_attr.namespace,
-                        root,
-                    );
-                }
-            }
-        } else {
-            for attribute in old.attributes {
-                self.mutations.remove_attribute(attribute, root);
-            }
-            for attribute in new.attributes {
-                self.mutations.set_attribute(
-                    attribute.name,
-                    attribute.value,
-                    attribute.namespace,
-                    root,
-                );
-            }
-        }
-
-        // Diff listeners
-        //
-        // It's extraordinarily rare to have the number/order of listeners change
-        // In the cases where the listeners change, we completely wipe the data attributes and add new ones
-        //
-        // We also need to make sure that all listeners are properly attached to the parent scope (fix_listener)
-        //
-        // TODO: take a more efficient path than this
-        let cur_scope_id = self.current_scope();
-
-        if old.listeners.len() == new.listeners.len() {
-            for (old_l, new_l) in old.listeners.iter().zip(new.listeners.iter()) {
-                new_l.mounted_node.set(old_l.mounted_node.get());
-                if old_l.event != new_l.event {
-                    self.mutations.remove_event_listener(old_l.event, root);
-                    self.mutations.new_event_listener(new_l, cur_scope_id);
-                }
-            }
-        } else {
-            for listener in old.listeners {
-                self.mutations.remove_event_listener(listener.event, root);
-            }
-            for listener in new.listeners {
-                listener.mounted_node.set(root);
-                self.mutations.new_event_listener(listener, cur_scope_id);
-            }
-        }
-
-        match (old.children.len(), new.children.len()) {
-            (0, 0) => {}
-            (0, _) => {
-                self.mutations.push_root(root);
-                let created = self.create_children(new.children);
-                self.mutations.append_children(created as u32);
-                self.mutations.pop_root();
-            }
-            (_, _) => self.diff_children(old.children, new.children),
-        };
-    }
-
-    fn diff_component(
-        &mut self,
-        old_node: &'b VNode<'b>,
-        new_node: &'b VNode<'b>,
-        old: &'b VComponent<'b>,
-        new: &'b VComponent<'b>,
-    ) {
-        let scope_addr = old
-            .scope
-            .get()
-            .expect("existing component nodes should have a scope");
-
-        // Make sure we're dealing with the same component (by function pointer)
-        if old.user_fc == new.user_fc {
-            self.enter_scope(scope_addr);
-            {
-                // Make sure the new component vnode is referencing the right scope id
-                new.scope.set(Some(scope_addr));
-
-                // make sure the component's caller function is up to date
-                let scope = self
-                    .scopes
-                    .get_scope(scope_addr)
-                    .unwrap_or_else(|| panic!("could not find {:?}", scope_addr));
-
-                // take the new props out regardless
-                // when memoizing, push to the existing scope if memoization happens
-                let new_props = new
-                    .props
-                    .borrow_mut()
-                    .take()
-                    .expect("new component props should exist");
-
-                let should_diff = {
-                    if old.can_memoize {
-                        // safety: we trust the implementation of "memoize"
-                        let props_are_the_same = unsafe {
-                            let new_ref = new_props.as_ref();
-                            scope.props.borrow().as_ref().unwrap().memoize(new_ref)
-                        };
-                        !props_are_the_same || self.force_diff
-                    } else {
-                        true
-                    }
-                };
-
-                if should_diff {
-                    let _old_props = scope
-                        .props
-                        .replace(unsafe { std::mem::transmute(Some(new_props)) });
-
-                    // this should auto drop the previous props
-                    self.scopes.run_scope(scope_addr);
-                    self.mutations.mark_dirty_scope(scope_addr);
-
-                    self.diff_node(
-                        self.scopes.wip_head(scope_addr),
-                        self.scopes.fin_head(scope_addr),
-                    );
-                } else {
-                    // memoization has taken place
-                    drop(new_props);
-                };
-            }
-            self.leave_scope();
-        } else {
-            self.replace_node(old_node, new_node);
-        }
-    }
-
-    fn diff_fragment(&mut self, old: &'b VFragment<'b>, new: &'b VFragment<'b>) {
-        todo!()
-        // // This is the case where options or direct vnodes might be used.
-        // // In this case, it's faster to just skip ahead to their diff
-        // if old.children.len() == 1 && new.children.len() == 1 {
-        //     if !std::ptr::eq(old, new) {
-        //         self.diff_node(&old.children[0], &new.children[0]);
-        //     }
-        //     return;
-        // }
-
-        // debug_assert!(!old.children.is_empty());
-        // debug_assert!(!new.children.is_empty());
-
-        // self.diff_children(old.children, new.children);
-    }
-
-    // Diff the given set of old and new children.
-    //
-    // The parent must be on top of the change list stack when this function is
-    // entered:
-    //
-    //     [... parent]
-    //
-    // the change list stack is in the same state when this function returns.
-    //
-    // If old no anchors are provided, then it's assumed that we can freely append to the parent.
-    //
-    // Remember, non-empty lists does not mean that there are real elements, just that there are virtual elements.
-    //
-    // Fragment nodes cannot generate empty children lists, so we can assume that when a list is empty, it belongs only
-    // to an element, and appending makes sense.
-    fn diff_children(&mut self, old: &'b [VNode<'b>], new: &'b [VNode<'b>]) {
-        if std::ptr::eq(old, new) {
-            return;
-        }
-
-        // Remember, fragments can never be empty (they always have a single child)
-        match (old, new) {
-            ([], []) => {}
-            ([], _) => self.create_and_append_children(new),
-            (_, []) => self.remove_nodes(old, true),
-            _ => {
-                let new_is_keyed = new[0].key().is_some();
-                let old_is_keyed = old[0].key().is_some();
-
-                debug_assert!(
-                    new.iter().all(|n| n.key().is_some() == new_is_keyed),
-                    "all siblings must be keyed or all siblings must be non-keyed"
-                );
-                debug_assert!(
-                    old.iter().all(|o| o.key().is_some() == old_is_keyed),
-                    "all siblings must be keyed or all siblings must be non-keyed"
-                );
-
-                if new_is_keyed && old_is_keyed {
-                    self.diff_keyed_children(old, new);
-                } else {
-                    self.diff_non_keyed_children(old, new);
-                }
-            }
-        }
-    }
-
-    // Diff children that are not keyed.
-    //
-    // The parent must be on the top of the change list stack when entering this
-    // function:
-    //
-    //     [... parent]
-    //
-    // the change list stack is in the same state when this function returns.
-    fn diff_non_keyed_children(&mut self, old: &'b [VNode<'b>], new: &'b [VNode<'b>]) {
-        use std::cmp::Ordering;
-
-        // Handled these cases in `diff_children` before calling this function.
-        debug_assert!(!new.is_empty());
-        debug_assert!(!old.is_empty());
-
-        match old.len().cmp(&new.len()) {
-            Ordering::Greater => self.remove_nodes(&old[new.len()..], true),
-            Ordering::Less => self.create_and_insert_after(&new[old.len()..], old.last().unwrap()),
-            Ordering::Equal => {}
-        }
-
-        for (new, old) in new.iter().zip(old.iter()) {
-            self.diff_node(old, new);
-        }
-    }
-
-    // Diffing "keyed" children.
-    //
-    // With keyed children, we care about whether we delete, move, or create nodes
-    // versus mutate existing nodes in place. Presumably there is some sort of CSS
-    // transition animation that makes the virtual DOM diffing algorithm
-    // observable. By specifying keys for nodes, we know which virtual DOM nodes
-    // must reuse (or not reuse) the same physical DOM nodes.
-    //
-    // This is loosely based on Inferno's keyed patching implementation. However, we
-    // have to modify the algorithm since we are compiling the diff down into change
-    // list instructions that will be executed later, rather than applying the
-    // changes to the DOM directly as we compare virtual DOMs.
-    //
-    // https://github.com/infernojs/inferno/blob/36fd96/packages/inferno/src/DOM/patching.ts#L530-L739
-    //
-    // The stack is empty upon entry.
-    fn diff_keyed_children(&mut self, old: &'b [VNode<'b>], new: &'b [VNode<'b>]) {
-        if cfg!(debug_assertions) {
-            let mut keys = fxhash::FxHashSet::default();
-            let mut assert_unique_keys = |children: &'b [VNode<'b>]| {
-                keys.clear();
-                for child in children {
-                    let key = child.key();
-                    debug_assert!(
-                        key.is_some(),
-                        "if any sibling is keyed, all siblings must be keyed"
-                    );
-                    keys.insert(key);
-                }
-                debug_assert_eq!(
-                    children.len(),
-                    keys.len(),
-                    "keyed siblings must each have a unique key"
-                );
-            };
-            assert_unique_keys(old);
-            assert_unique_keys(new);
-        }
-
-        // First up, we diff all the nodes with the same key at the beginning of the
-        // children.
-        //
-        // `shared_prefix_count` is the count of how many nodes at the start of
-        // `new` and `old` share the same keys.
-        let (left_offset, right_offset) = match self.diff_keyed_ends(old, new) {
-            Some(count) => count,
-            None => return,
-        };
-
-        // Ok, we now hopefully have a smaller range of children in the middle
-        // within which to re-order nodes with the same keys, remove old nodes with
-        // now-unused keys, and create new nodes with fresh keys.
-
-        let old_middle = &old[left_offset..(old.len() - right_offset)];
-        let new_middle = &new[left_offset..(new.len() - right_offset)];
-
-        debug_assert!(
-            !((old_middle.len() == new_middle.len()) && old_middle.is_empty()),
-            "keyed children must have the same number of children"
-        );
-
-        if new_middle.is_empty() {
-            // remove the old elements
-            self.remove_nodes(old_middle, true);
-        } else if old_middle.is_empty() {
-            // there were no old elements, so just create the new elements
-            // we need to find the right "foothold" though - we shouldn't use the "append" at all
-            if left_offset == 0 {
-                // insert at the beginning of the old list
-                let foothold = &old[old.len() - right_offset];
-                self.create_and_insert_before(new_middle, foothold);
-            } else if right_offset == 0 {
-                // insert at the end  the old list
-                let foothold = old.last().unwrap();
-                self.create_and_insert_after(new_middle, foothold);
-            } else {
-                // inserting in the middle
-                let foothold = &old[left_offset - 1];
-                self.create_and_insert_after(new_middle, foothold);
-            }
-        } else {
-            self.diff_keyed_middle(old_middle, new_middle);
-        }
-    }
-
-    /// Diff both ends of the children that share keys.
-    ///
-    /// Returns a left offset and right offset of that indicates a smaller section to pass onto the middle diffing.
-    ///
-    /// If there is no offset, then this function returns None and the diffing is complete.
-    fn diff_keyed_ends(
-        &mut self,
-        old: &'b [VNode<'b>],
-        new: &'b [VNode<'b>],
-    ) -> Option<(usize, usize)> {
-        let mut left_offset = 0;
-
-        for (old, new) in old.iter().zip(new.iter()) {
-            // abort early if we finally run into nodes with different keys
-            if old.key() != new.key() {
-                break;
-            }
-            self.diff_node(old, new);
-            left_offset += 1;
-        }
-
-        // If that was all of the old children, then create and append the remaining
-        // new children and we're finished.
-        if left_offset == old.len() {
-            self.create_and_insert_after(&new[left_offset..], old.last().unwrap());
-            return None;
-        }
-
-        // And if that was all of the new children, then remove all of the remaining
-        // old children and we're finished.
-        if left_offset == new.len() {
-            self.remove_nodes(&old[left_offset..], true);
-            return None;
-        }
-
-        // if the shared prefix is less than either length, then we need to walk backwards
-        let mut right_offset = 0;
-        for (old, new) in old.iter().rev().zip(new.iter().rev()) {
-            // abort early if we finally run into nodes with different keys
-            if old.key() != new.key() {
-                break;
-            }
-            self.diff_node(old, new);
-            right_offset += 1;
-        }
-
-        Some((left_offset, right_offset))
-    }
-
-    // The most-general, expensive code path for keyed children diffing.
-    //
-    // We find the longest subsequence within `old` of children that are relatively
-    // ordered the same way in `new` (via finding a longest-increasing-subsequence
-    // of the old child's index within `new`). The children that are elements of
-    // this subsequence will remain in place, minimizing the number of DOM moves we
-    // will have to do.
-    //
-    // Upon entry to this function, the change list stack must be empty.
-    //
-    // This function will load the appropriate nodes onto the stack and do diffing in place.
-    //
-    // Upon exit from this function, it will be restored to that same self.
-    #[allow(clippy::too_many_lines)]
-    fn diff_keyed_middle(&mut self, old: &'b [VNode<'b>], new: &'b [VNode<'b>]) {
-        /*
-        1. Map the old keys into a numerical ordering based on indices.
-        2. Create a map of old key to its index
-        3. Map each new key to the old key, carrying over the old index.
-            - IE if we have ABCD becomes BACD, our sequence would be 1,0,2,3
-            - if we have ABCD to ABDE, our sequence would be 0,1,3,MAX because E doesn't exist
-
-        now, we should have a list of integers that indicates where in the old list the new items map to.
-
-        4. Compute the LIS of this list
-            - this indicates the longest list of new children that won't need to be moved.
-
-        5. Identify which nodes need to be removed
-        6. Identify which nodes will need to be diffed
-
-        7. Going along each item in the new list, create it and insert it before the next closest item in the LIS.
-            - if the item already existed, just move it to the right place.
-
-        8. Finally, generate instructions to remove any old children.
-        9. Generate instructions to finally diff children that are the same between both
-        */
-
-        // 0. Debug sanity checks
-        // Should have already diffed the shared-key prefixes and suffixes.
-        debug_assert_ne!(new.first().map(VNode::key), old.first().map(VNode::key));
-        debug_assert_ne!(new.last().map(VNode::key), old.last().map(VNode::key));
-
-        // 1. Map the old keys into a numerical ordering based on indices.
-        // 2. Create a map of old key to its index
-        // IE if the keys were A B C, then we would have (A, 1) (B, 2) (C, 3).
-        let old_key_to_old_index = old
-            .iter()
-            .enumerate()
-            .map(|(i, o)| (o.key().unwrap(), i))
-            .collect::<FxHashMap<_, _>>();
-
-        let mut shared_keys = FxHashSet::default();
-
-        // 3. Map each new key to the old key, carrying over the old index.
-        let new_index_to_old_index = new
-            .iter()
-            .map(|node| {
-                let key = node.key().unwrap();
-                if let Some(&index) = old_key_to_old_index.get(&key) {
-                    shared_keys.insert(key);
-                    index
-                } else {
-                    u32::MAX as usize
-                }
-            })
-            .collect::<Vec<_>>();
-
-        // If none of the old keys are reused by the new children, then we remove all the remaining old children and
-        // create the new children afresh.
-        if shared_keys.is_empty() {
-            if let Some(first_old) = old.get(0) {
-                self.remove_nodes(&old[1..], true);
-                let nodes_created = self.create_children(new);
-                self.replace_inner(first_old, nodes_created);
-            } else {
-                // I think this is wrong - why are we appending?
-                // only valid of the if there are no trailing elements
-                self.create_and_append_children(new);
-            }
-            return;
-        }
-
-        // remove any old children that are not shared
-        // todo: make this an iterator
-        for child in old {
-            let key = child.key().unwrap();
-            if !shared_keys.contains(&key) {
-                self.remove_nodes([child], true);
-            }
-        }
-
-        // 4. Compute the LIS of this list
-        let mut lis_sequence = Vec::default();
-        lis_sequence.reserve(new_index_to_old_index.len());
-
-        let mut predecessors = vec![0; new_index_to_old_index.len()];
-        let mut starts = vec![0; new_index_to_old_index.len()];
-
-        longest_increasing_subsequence::lis_with(
-            &new_index_to_old_index,
-            &mut lis_sequence,
-            |a, b| a < b,
-            &mut predecessors,
-            &mut starts,
-        );
-
-        // the lis comes out backwards, I think. can't quite tell.
-        lis_sequence.sort_unstable();
-
-        // if a new node gets u32 max and is at the end, then it might be part of our LIS (because u32 max is a valid LIS)
-        if lis_sequence.last().map(|f| new_index_to_old_index[*f]) == Some(u32::MAX as usize) {
-            lis_sequence.pop();
-        }
-
-        for idx in &lis_sequence {
-            self.diff_node(&old[new_index_to_old_index[*idx]], &new[*idx]);
-        }
-
-        let mut nodes_created = 0;
-
-        // add mount instruction for the first items not covered by the lis
-        let last = *lis_sequence.last().unwrap();
-        if last < (new.len() - 1) {
-            for (idx, new_node) in new[(last + 1)..].iter().enumerate() {
-                let new_idx = idx + last + 1;
-                let old_index = new_index_to_old_index[new_idx];
-                if old_index == u32::MAX as usize {
-                    nodes_created += self.create_node(new_node);
-                } else {
-                    self.diff_node(&old[old_index], new_node);
-                    nodes_created += self.push_all_real_nodes(new_node);
-                }
-            }
-
-            self.mutations.insert_after(
-                self.find_last_element(&new[last]).unwrap(),
-                nodes_created as u32,
-            );
-            nodes_created = 0;
-        }
-
-        // for each spacing, generate a mount instruction
-        let mut lis_iter = lis_sequence.iter().rev();
-        let mut last = *lis_iter.next().unwrap();
-        for next in lis_iter {
-            if last - next > 1 {
-                for (idx, new_node) in new[(next + 1)..last].iter().enumerate() {
-                    let new_idx = idx + next + 1;
-                    let old_index = new_index_to_old_index[new_idx];
-                    if old_index == u32::MAX as usize {
-                        nodes_created += self.create_node(new_node);
-                    } else {
-                        self.diff_node(&old[old_index], new_node);
-                        nodes_created += self.push_all_real_nodes(new_node);
-                    }
-                }
-
-                self.mutations.insert_before(
-                    self.find_first_element(&new[last]).unwrap(),
-                    nodes_created as u32,
-                );
-
-                nodes_created = 0;
-            }
-            last = *next;
-        }
-
-        // add mount instruction for the last items not covered by the lis
-        let first_lis = *lis_sequence.first().unwrap();
-        if first_lis > 0 {
-            for (idx, new_node) in new[..first_lis].iter().enumerate() {
-                let old_index = new_index_to_old_index[idx];
-                if old_index == u32::MAX as usize {
-                    nodes_created += self.create_node(new_node);
-                } else {
-                    self.diff_node(&old[old_index], new_node);
-                    nodes_created += self.push_all_real_nodes(new_node);
-                }
-            }
-
-            self.mutations.insert_before(
-                self.find_first_element(&new[first_lis]).unwrap(),
-                nodes_created as u32,
-            );
-        }
-    }
-
-    fn replace_node(&mut self, old: &'b VNode<'b>, new: &'b VNode<'b>) {
-        let nodes_created = self.create_node(new);
-        self.replace_inner(old, nodes_created);
-    }
-
-    fn replace_inner(&mut self, old: &'b VNode<'b>, nodes_created: usize) {
-        match old {
-            VNode::Element(el) => {
-                let id = old
-                    .try_mounted_id()
-                    .unwrap_or_else(|| panic!("broke on {:?}", old));
-
-                self.mutations.replace_with(id, nodes_created as u32);
-                self.remove_nodes(el.children, false);
-                self.scopes.collect_garbage(id);
-            }
-            VNode::Text(_) => {
-                let id = old
-                    .try_mounted_id()
-                    .unwrap_or_else(|| panic!("broke on {:?}", old));
-
-                self.mutations.replace_with(id, nodes_created as u32);
-                self.scopes.collect_garbage(id);
-            }
-            VNode::Fragment(f) => {
-                self.replace_inner(&f.children[0], nodes_created);
-                self.remove_nodes(f.children.iter().skip(1), true);
-            }
-            VNode::Component(c) => {
-                let scope_id = c.scope.get().unwrap();
-                let node = self.scopes.fin_head(scope_id);
-
-                self.enter_scope(scope_id);
-                {
-                    self.replace_inner(node, nodes_created);
-                    let scope = self.scopes.get_scope(scope_id).unwrap();
-                    c.scope.set(None);
-                    let props = scope.props.take().unwrap();
-                    c.props.borrow_mut().replace(props);
-                    self.scopes.try_remove(scope_id);
-                }
-
-                self.leave_scope();
-            }
-            VNode::Template(c) => {
-                todo!()
-                // // let ids = c.root_keys.as_slice_of_cells();
-
-                // self.mutations
-                //     .replace_with(ids[0].get(), nodes_created as u32);
-                // self.scopes.collect_garbage(ids[0].get());
-
-                // for id in ids.iter().skip(1) {
-                //     self.mutations.remove(id.get());
-                //     self.scopes.collect_garbage(id.get());
-                // }
-            }
-        }
-    }
-
-    pub fn remove_nodes(&mut self, nodes: impl IntoIterator<Item = &'b VNode<'b>>, gen_muts: bool) {
-        for node in nodes {
-            match node {
-                VNode::Text(t) => {
-                    // this check exists because our null node will be removed but does not have an ID
-                    if let Some(id) = t.id.get() {
-                        self.scopes.collect_garbage(id);
-                        t.id.set(None);
-
-                        if gen_muts {
-                            self.mutations.remove(id);
-                        }
-                    }
-                }
-                // VNode::Placeholder(a) => {
-                //     let id = a.id.get().unwrap();
-                //     self.scopes.collect_garbage(id);
-                //     a.id.set(None);
-
-                //     if gen_muts {
-                //         self.mutations.remove(id);
-                //     }
-                // }
-                VNode::Element(e) => {
-                    let id = e.id.get().unwrap();
-
-                    if gen_muts {
-                        self.mutations.remove(id);
-                    }
-
-                    self.scopes.collect_garbage(id);
-                    e.id.set(None);
-
-                    self.remove_nodes(e.children, false);
-                }
-
-                VNode::Fragment(f) => {
-                    self.remove_nodes(f.children, gen_muts);
-                }
-                VNode::Component(c) => {
-                    self.enter_scope(c.scope.get().unwrap());
-                    {
-                        let scope_id = c.scope.get().unwrap();
-                        let root = self.scopes.root_node(scope_id);
-                        self.remove_nodes([root], gen_muts);
-
-                        let scope = self.scopes.get_scope(scope_id).unwrap();
-                        c.scope.set(None);
-
-                        let props = scope.props.take().unwrap();
-                        c.props.borrow_mut().replace(props);
-                        self.scopes.try_remove(scope_id);
-                    }
-                    self.leave_scope();
-                }
-
-                VNode::Template(c) => {}
-            }
-        }
-    }
-
-    fn create_children(&mut self, nodes: &'b [VNode<'b>]) -> usize {
-        let mut created = 0;
-        for node in nodes {
-            created += self.create_node(node);
-        }
-        created
-    }
-
-    fn create_and_append_children(&mut self, nodes: &'b [VNode<'b>]) {
-        let created = self.create_children(nodes);
-        self.mutations.append_children(created as u32);
-    }
-
-    fn create_and_insert_after(&mut self, nodes: &'b [VNode<'b>], after: &'b VNode<'b>) {
-        let created = self.create_children(nodes);
-        let last = self.find_last_element(after).unwrap();
-        self.mutations.insert_after(last, created as u32);
-    }
-
-    fn create_and_insert_before(&mut self, nodes: &'b [VNode<'b>], before: &'b VNode<'b>) {
-        let created = self.create_children(nodes);
-        let first = self.find_first_element(before).unwrap();
-        self.mutations.insert_before(first, created as u32);
-    }
-
-    fn current_scope(&self) -> ScopeId {
-        self.scope_stack.last().copied().expect("no current scope")
-    }
-
-    fn enter_scope(&mut self, scope: ScopeId) {
-        self.scope_stack.push(scope);
-    }
-
-    fn leave_scope(&mut self) {
-        self.scope_stack.pop();
-    }
-
-    fn find_last_element(&self, vnode: &'b VNode<'b>) -> Option<ElementId> {
-        let mut search_node = Some(vnode);
-        loop {
-            match &search_node.take().unwrap() {
-                VNode::Text(t) => break t.id.get(),
-                VNode::Element(t) => break t.id.get(),
-                VNode::Fragment(frag) => search_node = frag.children.last(),
-                VNode::Component(el) => {
-                    let scope_id = el.scope.get().unwrap();
-                    search_node = Some(self.scopes.root_node(scope_id));
-                }
-                VNode::Template(template) => match &template.template.roots[0] {
-                    TemplateNode::Text(_) | TemplateNode::Element { .. } => {
-                        break Some(template.root_ids.last().unwrap().get());
-                    }
-                    TemplateNode::Dynamic(el) => {
-                        search_node = Some(&template.dynamic_nodes[*el].node)
-                    }
-                },
-            }
-        }
-    }
-
-    fn find_first_element(&self, vnode: &'b VNode<'b>) -> Option<ElementId> {
-        let mut search_node = Some(vnode);
-        loop {
-            match &search_node.take().expect("search node to have an ID") {
-                VNode::Text(t) => break t.id.get(),
-                VNode::Element(t) => break t.id.get(),
-                VNode::Fragment(frag) => search_node = Some(&frag.children[0]),
-                VNode::Component(el) => {
-                    let scope = el.scope.get().expect("element to have a scope assigned");
-                    search_node = Some(self.scopes.root_node(scope));
-                }
-                VNode::Template(template) => match &template.template.roots[0] {
-                    TemplateNode::Text(_) | TemplateNode::Element { .. } => {
-                        break Some(template.root_ids[0].get());
-                    }
-                    TemplateNode::Dynamic(el) => {
-                        search_node = Some(&template.dynamic_nodes[*el].node)
-                    }
-                },
-            }
-        }
-    }
-
-    // recursively push all the nodes of a tree onto the stack and return how many are there
-    fn push_all_real_nodes(&mut self, node: &'b VNode<'b>) -> usize {
-        match node {
-            VNode::Text(_) | VNode::Element(_) => {
-                self.mutations.push_root(node.mounted_id());
-                1
-            }
-
-            VNode::Fragment(frag) => {
-                let mut added = 0;
-                for child in frag.children {
-                    added += self.push_all_real_nodes(child);
-                }
-                added
-            }
-            VNode::Component(c) => {
-                let scope_id = c.scope.get().unwrap();
-                let root = self.scopes.root_node(scope_id);
-                self.push_all_real_nodes(root)
-            }
-
-            VNode::Template(template) => {
-                let mut added = 0;
-                for (idx, root) in template.template.roots.iter().enumerate() {
-                    match root {
-                        TemplateNode::Text(_) | TemplateNode::Element { .. } => {
-                            self.mutations.push_root(template.root_ids[idx].get());
-                            added += 1;
-                        }
-                        TemplateNode::Dynamic(did) => {
-                            added += self.push_all_real_nodes(&template.dynamic_nodes[*did].node);
-                        }
-                    }
-                }
-                added
-            }
-        }
-    }
-
-    pub(crate) fn diff_placeholder(&self, old_node: &VNode, new_node: &VNode) {
-        todo!()
-    }
-}

+ 0 - 182
packages/core/src.old/events.rs

@@ -1,182 +0,0 @@
-//! Internal and external event system
-//!
-//!
-//! This is all kinda WIP, but the bones are there.
-
-use crate::{ElementId, ScopeId};
-use std::{any::Any, cell::Cell, fmt::Debug, rc::Rc, sync::Arc};
-
-pub(crate) struct BubbleState {
-    pub canceled: Cell<bool>,
-}
-
-impl BubbleState {
-    pub fn new() -> Self {
-        Self {
-            canceled: Cell::new(false),
-        }
-    }
-}
-
-/// User Events are events that are shuttled from the renderer into the [`VirtualDom`] through the scheduler channel.
-///
-/// These events will be passed to the appropriate Element given by `mounted_dom_id` and then bubbled up through the tree
-/// where each listener is checked and fired if the event name matches.
-///
-/// It is the expectation that the event name matches the corresponding event listener, otherwise Dioxus will panic in
-/// attempting to downcast the event data.
-///
-/// Because Event Data is sent across threads, it must be `Send + Sync`. We are hoping to lift the `Sync` restriction but
-/// `Send` will not be lifted. The entire `UserEvent` must also be `Send + Sync` due to its use in the scheduler channel.
-///
-/// # Example
-/// ```rust, ignore
-/// fn App(cx: Scope) -> Element {
-///     render!(div {
-///         onclick: move |_| println!("Clicked!")
-///     })
-/// }
-///
-/// let mut dom = VirtualDom::new(App);
-/// let mut scheduler = dom.get_scheduler_channel();
-/// scheduler.unbounded_send(SchedulerMsg::UiEvent(
-///     UserEvent {
-///         scope_id: None,
-///         priority: EventPriority::Medium,
-///         name: "click",
-///         element: Some(ElementId(0)),
-///         data: Arc::new(ClickEvent { .. })
-///     }
-/// )).unwrap();
-/// ```
-#[derive(Debug, Clone)]
-pub struct UserEvent {
-    /// The originator of the event trigger if available
-    pub scope_id: Option<ScopeId>,
-
-    /// The priority of the event to be scheduled around ongoing work
-    pub priority: EventPriority,
-
-    /// The optional real node associated with the trigger
-    pub element: Option<ElementId>,
-
-    /// The event type IE "onclick" or "onmouseover"
-    pub name: &'static str,
-
-    /// If the event is bubbles up through the vdom
-    pub bubbles: bool,
-
-    /// The event data to be passed onto the event handler
-    pub data: Arc<dyn Any + Send + Sync>,
-}
-
-/// Priority of Event Triggers.
-///
-/// Internally, Dioxus will abort work that's taking too long if new, more important work arrives. Unlike React, Dioxus
-/// won't be afraid to pause work or flush changes to the Real Dom. This is called "cooperative scheduling". Some Renderers
-/// implement this form of scheduling internally, however Dioxus will perform its own scheduling as well.
-///
-/// The ultimate goal of the scheduler is to manage latency of changes, prioritizing "flashier" changes over "subtler" changes.
-///
-/// React has a 5-tier priority system. However, they break things into "Continuous" and "Discrete" priority. For now,
-/// we keep it simple, and just use a 3-tier priority system.
-///
-/// - `NoPriority` = 0
-/// - `LowPriority` = 1
-/// - `NormalPriority` = 2
-/// - `UserBlocking` = 3
-/// - `HighPriority` = 4
-/// - `ImmediatePriority` = 5
-///
-/// We still have a concept of discrete vs continuous though - discrete events won't be batched, but continuous events will.
-/// This means that multiple "scroll" events will be processed in a single frame, but multiple "click" events will be
-/// flushed before proceeding. Multiple discrete events is highly unlikely, though.
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
-pub enum EventPriority {
-    /// Work that must be completed during the EventHandler phase.
-    ///
-    /// Currently this is reserved for controlled inputs.
-    Immediate = 3,
-
-    /// "High Priority" work will not interrupt other high priority work, but will interrupt medium and low priority work.
-    ///
-    /// This is typically reserved for things like user interaction.
-    ///
-    /// React calls these "discrete" events, but with an extra category of "user-blocking" (Immediate).
-    High = 2,
-
-    /// "Medium priority" work is generated by page events not triggered by the user. These types of events are less important
-    /// than "High Priority" events and will take precedence over low priority events.
-    ///
-    /// This is typically reserved for VirtualEvents that are not related to keyboard or mouse input.
-    ///
-    /// React calls these "continuous" events (e.g. mouse move, mouse wheel, touch move, etc).
-    Medium = 1,
-
-    /// "Low Priority" work will always be preempted unless the work is significantly delayed, in which case it will be
-    /// advanced to the front of the work queue until completed.
-    ///
-    /// The primary user of Low Priority work is the asynchronous work system (Suspense).
-    ///
-    /// This is considered "idle" work or "background" work.
-    Low = 0,
-}
-
-/// The internal Dioxus type that carries any event data to the relevant handler.
-
-pub struct AnyEvent {
-    pub(crate) bubble_state: Rc<BubbleState>,
-    pub(crate) data: Arc<dyn Any + Send + Sync>,
-}
-
-impl AnyEvent {
-    /// Convert this [`AnyEvent`] into a specific [`UiEvent`] with [`EventData`].
-    ///
-    /// ```rust, ignore
-    /// let evt: FormEvent = evvt.downcast().unwrap();
-    /// ```
-    #[must_use]
-    pub fn downcast<T: Send + Sync + 'static>(self) -> Option<UiEvent<T>> {
-        let AnyEvent { data, bubble_state } = self;
-
-        data.downcast::<T>()
-            .ok()
-            .map(|data| UiEvent { data, bubble_state })
-    }
-}
-
-/// A [`UiEvent`] is a type that wraps various [`EventData`].
-///
-/// You should prefer to use the name of the event directly, rather than
-/// the [`UiEvent`]<T> generic type.
-///
-/// For the HTML crate, this would include `MouseEvent`, `FormEvent` etc.
-pub struct UiEvent<T> {
-    /// The internal data of the event
-    /// This is wrapped in an Arc so that it can be sent across threads
-    pub data: Arc<T>,
-
-    #[allow(unused)]
-    bubble_state: Rc<BubbleState>,
-}
-
-impl<T: Debug> std::fmt::Debug for UiEvent<T> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("UiEvent").field("data", &self.data).finish()
-    }
-}
-
-impl<T> std::ops::Deref for UiEvent<T> {
-    type Target = T;
-
-    fn deref(&self) -> &Self::Target {
-        self.data.as_ref()
-    }
-}
-
-impl<T> UiEvent<T> {
-    /// Prevent this event from bubbling up the tree.
-    pub fn cancel_bubble(&self) {
-        self.bubble_state.canceled.set(true);
-    }
-}

+ 0 - 322
packages/core/src.old/lazynodes.rs

@@ -1,322 +0,0 @@
-//! Support for storing lazy-nodes on the stack
-//!
-//! This module provides support for a type called `LazyNodes` which is a micro-heap located on the stack to make calls
-//! to `rsx!` more efficient.
-//!
-//! To support returning rsx! from branches in match statements, we need to use dynamic dispatch on [`NodeFactory`] closures.
-//!
-//! This can be done either through boxing directly, or by using dynamic-sized-types and a custom allocator. In our case,
-//! we build a tiny alloactor in the stack and allocate the closure into that.
-//!
-//! The logic for this was borrowed from <https://docs.rs/stack_dst/0.6.1/stack_dst/>. Unfortunately, this crate does not
-//! support non-static closures, so we've implemented the core logic of `ValueA` in this module.
-
-use crate::innerlude::{NodeFactory, VNode};
-use std::mem;
-
-/// A concrete type provider for closures that build [`VNode`] structures.
-///
-/// This struct wraps lazy structs that build [`VNode`] trees Normally, we cannot perform a blanket implementation over
-/// closures, but if we wrap the closure in a concrete type, we can maintain separate implementations of [`IntoVNode`].
-///
-///
-/// ```rust, ignore
-/// LazyNodes::new(|f| f.element("div", [], [], [] None))
-/// ```
-pub struct LazyNodes<'a, 'b> {
-    inner: StackNodeStorage<'a, 'b>,
-}
-
-type StackHeapSize = [usize; 16];
-
-enum StackNodeStorage<'a, 'b> {
-    Stack(LazyStack),
-    Heap(Box<dyn FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>> + 'b>),
-}
-
-impl<'a, 'b> LazyNodes<'a, 'b> {
-    /// Create a new [`LazyNodes`] closure, optimistically placing it onto the stack.
-    ///
-    /// If the closure cannot fit into the stack allocation (16 bytes), then it
-    /// is placed on the heap. Most closures will fit into the stack, and is
-    /// the most optimal way to use the creation function.
-    pub fn new(val: impl FnOnce(NodeFactory<'a>) -> VNode<'a> + 'b) -> Self {
-        // there's no way to call FnOnce without a box, so we need to store it in a slot and use static dispatch
-        let mut slot = Some(val);
-
-        let val = move |fac: Option<NodeFactory<'a>>| {
-            fac.map(
-                slot.take()
-                    .expect("LazyNodes closure to be called only once"),
-            )
-        };
-
-        // miri does not know how to work with mucking directly into bytes
-        // just use a heap allocated type when miri is running
-        if cfg!(miri) {
-            Self {
-                inner: StackNodeStorage::Heap(Box::new(val)),
-            }
-        } else {
-            unsafe { LazyNodes::new_inner(val) }
-        }
-    }
-
-    /// Create a new [`LazyNodes`] closure, but force it onto the heap.
-    pub fn new_boxed<F>(inner: F) -> Self
-    where
-        F: FnOnce(NodeFactory<'a>) -> VNode<'a> + 'b,
-    {
-        // there's no way to call FnOnce without a box, so we need to store it in a slot and use static dispatch
-        let mut slot = Some(inner);
-
-        Self {
-            inner: StackNodeStorage::Heap(Box::new(move |fac: Option<NodeFactory<'a>>| {
-                fac.map(
-                    slot.take()
-                        .expect("LazyNodes closure to be called only once"),
-                )
-            })),
-        }
-    }
-
-    unsafe fn new_inner<F>(val: F) -> Self
-    where
-        F: FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>> + 'b,
-    {
-        let mut ptr: *const _ = &val as &dyn FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>>;
-
-        assert_eq!(
-            ptr as *const u8, &val as *const _ as *const u8,
-            "MISUSE: Closure returned different pointer"
-        );
-        assert_eq!(
-            std::mem::size_of_val(&*ptr),
-            std::mem::size_of::<F>(),
-            "MISUSE: Closure returned a subset pointer"
-        );
-
-        let words = ptr_as_slice(&mut ptr);
-        assert!(
-            words[0] == &val as *const _ as usize,
-            "BUG: Pointer layout is not (data_ptr, info...)"
-        );
-
-        // - Ensure that Self is aligned same as data requires
-        assert!(
-            std::mem::align_of::<F>() <= std::mem::align_of::<Self>(),
-            "TODO: Enforce alignment >{} (requires {})",
-            std::mem::align_of::<Self>(),
-            std::mem::align_of::<F>()
-        );
-
-        let info = &words[1..];
-        let data = words[0] as *mut ();
-        let size = mem::size_of::<F>();
-
-        let stored_size = info.len() * mem::size_of::<usize>() + size;
-        let max_size = mem::size_of::<StackHeapSize>();
-
-        if stored_size > max_size {
-            Self {
-                inner: StackNodeStorage::Heap(Box::new(val)),
-            }
-        } else {
-            let mut buf: StackHeapSize = StackHeapSize::default();
-
-            assert!(info.len() + round_to_words(size) <= buf.as_ref().len());
-
-            // Place pointer information at the end of the region
-            // - Allows the data to be at the start for alignment purposes
-            {
-                let info_ofs = buf.as_ref().len() - info.len();
-                let info_dst = &mut buf.as_mut()[info_ofs..];
-                for (d, v) in Iterator::zip(info_dst.iter_mut(), info.iter()) {
-                    *d = *v;
-                }
-            }
-
-            let src_ptr = data as *const u8;
-            let dataptr = buf.as_mut_ptr().cast::<u8>();
-
-            for i in 0..size {
-                *dataptr.add(i) = *src_ptr.add(i);
-            }
-
-            std::mem::forget(val);
-
-            Self {
-                inner: StackNodeStorage::Stack(LazyStack {
-                    _align: [],
-                    buf,
-                    dropped: false,
-                }),
-            }
-        }
-    }
-
-    /// Call the closure with the given factory to produce real [`VNode`].
-    ///
-    /// ```rust, ignore
-    /// let f = LazyNodes::new(move |f| f.element("div", [], [], [] None));
-    ///
-    /// let fac = NodeFactory::new(&cx);
-    ///
-    /// let node = f.call(cac);
-    /// ```
-    #[must_use]
-    pub fn call(self, f: NodeFactory<'a>) -> VNode<'a> {
-        match self.inner {
-            StackNodeStorage::Heap(mut lazy) => {
-                lazy(Some(f)).expect("Closure should not be called twice")
-            }
-            StackNodeStorage::Stack(mut stack) => stack.call(f),
-        }
-    }
-}
-
-struct LazyStack {
-    _align: [u64; 0],
-    buf: StackHeapSize,
-    dropped: bool,
-}
-
-impl LazyStack {
-    fn call<'a>(&mut self, f: NodeFactory<'a>) -> VNode<'a> {
-        let LazyStack { buf, .. } = self;
-        let data = buf.as_ref();
-
-        let info_size =
-            mem::size_of::<*mut dyn FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>>>()
-                / mem::size_of::<usize>()
-                - 1;
-
-        let info_ofs = data.len() - info_size;
-
-        let g: *mut dyn FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>> =
-            unsafe { make_fat_ptr(data[..].as_ptr() as usize, &data[info_ofs..]) };
-
-        self.dropped = true;
-
-        let clos = unsafe { &mut *g };
-        clos(Some(f)).unwrap()
-    }
-}
-impl Drop for LazyStack {
-    fn drop(&mut self) {
-        if !self.dropped {
-            let LazyStack { buf, .. } = self;
-            let data = buf.as_ref();
-
-            let info_size = mem::size_of::<
-                *mut dyn FnMut(Option<NodeFactory<'_>>) -> Option<VNode<'_>>,
-            >() / mem::size_of::<usize>()
-                - 1;
-
-            let info_ofs = data.len() - info_size;
-
-            let g: *mut dyn FnMut(Option<NodeFactory<'_>>) -> Option<VNode<'_>> =
-                unsafe { make_fat_ptr(data[..].as_ptr() as usize, &data[info_ofs..]) };
-
-            self.dropped = true;
-
-            let clos = unsafe { &mut *g };
-            clos(None);
-        }
-    }
-}
-
-/// Obtain mutable access to a pointer's words
-fn ptr_as_slice<T>(ptr: &mut T) -> &mut [usize] {
-    assert!(mem::size_of::<T>() % mem::size_of::<usize>() == 0);
-    let words = mem::size_of::<T>() / mem::size_of::<usize>();
-    // SAFE: Points to valid memory (a raw pointer)
-    unsafe { core::slice::from_raw_parts_mut(ptr as *mut _ as *mut usize, words) }
-}
-
-/// Re-construct a fat pointer
-unsafe fn make_fat_ptr<T: ?Sized>(data_ptr: usize, meta_vals: &[usize]) -> *mut T {
-    let mut rv = mem::MaybeUninit::<*mut T>::uninit();
-    {
-        let s = ptr_as_slice(&mut rv);
-        s[0] = data_ptr;
-        s[1..].copy_from_slice(meta_vals);
-    }
-    let rv = rv.assume_init();
-    assert_eq!(rv as *const (), data_ptr as *const ());
-    rv
-}
-
-fn round_to_words(len: usize) -> usize {
-    (len + mem::size_of::<usize>() - 1) / mem::size_of::<usize>()
-}
-
-// #[cfg(test)]
-// mod tests {
-//     use super::*;
-//     use crate::innerlude::{Element, Scope, VirtualDom};
-
-//     #[test]
-//     fn it_works() {
-//         fn app(cx: Scope<()>) -> Element {
-//             cx.render(LazyNodes::new(|f| f.text(format_args!("hello world!"))))
-//         }
-
-//         let mut dom = VirtualDom::new(app);
-//         dom.rebuild();
-
-//         let g = dom.base_scope().root_node();
-//         dbg!(g);
-//     }
-
-//     #[test]
-//     fn it_drops() {
-//         use std::rc::Rc;
-
-//         struct AppProps {
-//             inner: Rc<i32>,
-//         }
-
-//         fn app(cx: Scope<AppProps>) -> Element {
-//             struct DropInner {
-//                 id: i32,
-//             }
-//             impl Drop for DropInner {
-//                 fn drop(&mut self) {
-//                     eprintln!("dropping inner");
-//                 }
-//             }
-
-//             let caller = {
-//                 let it = (0..10).map(|i| {
-//                     let val = cx.props.inner.clone();
-//                     LazyNodes::new(move |f| {
-//                         eprintln!("hell closure");
-//                         let inner = DropInner { id: i };
-//                         f.text(format_args!("hello world {:?}, {:?}", inner.id, val))
-//                     })
-//                 });
-
-//                 LazyNodes::new(|f| {
-//                     eprintln!("main closure");
-//                     f.fragment_from_iter(it)
-//                 })
-//             };
-
-//             cx.render(caller)
-//         }
-
-//         let inner = Rc::new(0);
-//         let mut dom = VirtualDom::new_with_props(
-//             app,
-//             AppProps {
-//                 inner: inner.clone(),
-//             },
-//         );
-//         dom.rebuild();
-
-//         drop(dom);
-
-//         assert_eq!(Rc::strong_count(&inner), 1);
-//     }
-// }

+ 0 - 131
packages/core/src.old/lib.rs

@@ -1,131 +0,0 @@
-#![allow(non_snake_case)]
-#![doc = include_str!("../README.md")]
-#![warn(missing_docs)]
-
-pub(crate) mod diff;
-pub(crate) mod events;
-pub(crate) mod lazynodes;
-pub(crate) mod mutations;
-pub(crate) mod nodes;
-pub(crate) mod properties;
-pub(crate) mod scopes;
-pub(crate) mod virtual_dom;
-
-pub(crate) mod innerlude {
-    pub use crate::events::*;
-    pub use crate::lazynodes::*;
-    pub use crate::mutations::*;
-    pub use crate::nodes::*;
-    pub use crate::properties::*;
-    pub use crate::scopes::*;
-    pub use crate::virtual_dom::*;
-
-    /// An [`Element`] is a possibly-none [`VNode`] created by calling `render` on [`Scope`] or [`ScopeState`].
-    ///
-    /// Any [`None`] [`Element`] will automatically be coerced into a placeholder [`VNode`] with the [`VNode::Placeholder`] variant.
-    pub type Element<'a> = Option<VNode<'a>>;
-
-    /// A [`Component`] is a function that takes a [`Scope`] and returns an [`Element`].
-    ///
-    /// Components can be used in other components with two syntax options:
-    /// - lowercase as a function call with named arguments (rust style)
-    /// - uppercase as an element (react style)
-    ///
-    /// ## Rust-Style
-    ///
-    /// ```rust, ignore
-    /// fn example(cx: Scope<Props>) -> Element {
-    ///     // ...
-    /// }
-    ///
-    /// rsx!(
-    ///     example()
-    /// )
-    /// ```
-    /// ## React-Style
-    /// ```rust, ignore
-    /// fn Example(cx: Scope<Props>) -> Element {
-    ///     // ...
-    /// }
-    ///
-    /// rsx!(
-    ///     Example {}
-    /// )
-    /// ```
-    pub type Component<P = ()> = fn(Scope<P>) -> Element;
-
-    /// A list of attributes
-    pub type Attributes<'a> = Option<&'a [Attribute<'a>]>;
-}
-
-pub use crate::innerlude::{
-    AnyAttributeValue, AnyEvent, Attribute, AttributeValue, Component, Element, ElementId,
-    EventHandler, EventPriority, IntoVNode, LazyNodes, Listener, NodeFactory, Properties, Renderer,
-    SchedulerMsg, Scope, ScopeId, ScopeState, TaskId, Template, TemplateAttribute, TemplateNode,
-    UiEvent, UserEvent, VComponent, VElement, VNode, VTemplate, VText, VirtualDom,
-};
-
-/// The purpose of this module is to alleviate imports of many common types
-///
-/// This includes types like [`Scope`], [`Element`], and [`Component`].
-pub mod prelude {
-    pub use crate::innerlude::{
-        fc_to_builder, Attributes, Component, Element, EventHandler, LazyNodes, NodeFactory,
-        Properties, Scope, ScopeId, ScopeState, Template, VNode, VirtualDom,
-    };
-}
-
-pub mod exports {
-    //! Important dependencies that are used by the rest of the library
-    //! Feel free to just add the dependencies in your own Crates.toml
-    pub use bumpalo;
-    pub use futures_channel;
-}
-
-/// Functions that wrap unsafe functionality to prevent us from misusing it at the callsite
-pub(crate) mod unsafe_utils {
-    use crate::VNode;
-
-    pub(crate) unsafe fn extend_vnode<'a, 'b>(node: &'a VNode<'a>) -> &'b VNode<'b> {
-        std::mem::transmute(node)
-    }
-}
-
-#[macro_export]
-/// A helper macro for using hooks in async environements.
-///
-/// # Usage
-///
-///
-/// ```ignore
-/// let (data) = use_ref(&cx, || {});
-///
-/// let handle_thing = move |_| {
-///     to_owned![data]
-///     cx.spawn(async move {
-///         // do stuff
-///     });
-/// }
-/// ```
-macro_rules! to_owned {
-    ($($es:ident),+) => {$(
-        #[allow(unused_mut)]
-        let mut $es = $es.to_owned();
-    )*}
-}
-
-/// get the code location of the code that called this function
-#[macro_export]
-macro_rules! get_line_num {
-    () => {
-        concat!(
-            file!(),
-            ":",
-            line!(),
-            ":",
-            column!(),
-            ":",
-            env!("CARGO_MANIFEST_DIR")
-        )
-    };
-}

+ 0 - 507
packages/core/src.old/mutations.rs

@@ -1,507 +0,0 @@
-//! Instructions returned by the VirtualDOM on how to modify the Real DOM.
-//!
-//! This module contains an internal API to generate these instructions.
-//!
-//! Beware that changing code in this module will break compatibility with
-//! interpreters for these types of DomEdits.
-
-use crate::innerlude::*;
-
-/// A renderer for Dioxus to modify during diffing
-///
-/// The renderer should implement a Stack Machine. IE each call to the below methods are modifications to the renderer's
-/// internal stack for creating and modifying nodes.
-///
-/// Dioxus guarantees that the stack is always in a valid state.
-pub trait Renderer<'a> {
-    /// Load this element onto the stack
-    fn push_root(&mut self, root: ElementId);
-    /// Pop the topmost element from the stack
-    fn pop_root(&mut self);
-    /// Replace the given element with the next m elements on the stack
-    fn replace_with(&mut self, root: ElementId, m: u32);
-
-    /// Insert the next m elements on the stack after the given element
-    fn insert_after(&mut self, root: ElementId, n: u32);
-    /// Insert the next m elements on the stack before the given element
-    fn insert_before(&mut self, root: ElementId, n: u32);
-    /// Append the next n elements on the stack to the n+1 element on the stack
-    fn append_children(&mut self, n: u32);
-
-    /// Create a new element with the given text and ElementId
-    fn create_text_node(&mut self, text: &'a str, root: ElementId);
-    /// Create an element with the given tag name, optional namespace, and ElementId
-    /// Note that namespaces do not cascade down the tree, so the renderer must handle this if it implements namespaces
-    fn create_element(&mut self, tag: &'static str, ns: Option<&'static str>, id: ElementId);
-    /// Create a hidden element to be used later for replacement.
-    /// Used in suspense, lists, and other places where we need to hide a node before it is ready to be shown.
-    /// This is up to the renderer to implement, but it should not be visible to the user.
-    fn create_placeholder(&mut self, id: ElementId);
-
-    /// Remove the targeted node from the DOM
-    fn remove(&mut self, root: ElementId);
-    /// Remove an attribute from an existing element
-    fn remove_attribute(&mut self, attribute: &Attribute, root: ElementId);
-    /// Remove all the children of the given element
-    fn remove_children(&mut self, root: ElementId);
-
-    /// Attach a new listener to the dom
-    fn new_event_listener(&mut self, listener: &Listener, scope: ScopeId);
-    /// Remove an existing listener from the dom
-    fn remove_event_listener(&mut self, event: &'static str, root: ElementId);
-
-    /// Set the text content of a node
-    fn set_text(&mut self, text: &'a str, root: ElementId);
-    /// Set an attribute on an element
-    fn set_attribute(
-        &mut self,
-        name: &'static str,
-        value: AttributeValue<'a>,
-        namespace: Option<&'a str>,
-        root: ElementId,
-    );
-
-    /// General statistics for doing things that extend outside of the renderer
-    fn mark_dirty_scope(&mut self, scope: ScopeId);
-
-    /// Save the current n nodes to the ID to be loaded later
-    fn save(&mut self, id: &'static str, num: u32);
-    /// Loads a set of saved nodes from the ID into a scratch space
-    fn load(&mut self, id: &'static str, index: u32);
-    /// Assign the element on the stack's descendent the given ID
-    fn assign_id(&mut self, descendent: &'static [u8], id: ElementId);
-    /// Replace the given element of the topmost element with the next m elements on the stack
-    /// Is essentially a combination of assign_id and replace_with
-    fn replace_descendant(&mut self, descendent: &'static [u8], m: u32);
-}
-
-/*
-div {
-    div {
-        div {
-            div {}
-        }
-    }
-}
-
-push_child(0)
-push_child(1)
-push_child(3)
-push_child(4)
-pop
-pop
-
-clone_node(0)
-set_node(el, [1,2,3,4])
-set_attribute("class", "foo")
-append_child(1)
-*/
-
-
-//! Instructions returned by the VirtualDOM on how to modify the Real DOM.
-//!
-//! This module contains an internal API to generate these instructions.
-//!
-//! Beware that changing code in this module will break compatibility with
-//! interpreters for these types of DomEdits.
-
-use crate::innerlude::*;
-use std::{any::Any, fmt::Debug};
-
-/// ## Mutations
-///
-/// This method returns "mutations" - IE the necessary changes to get the RealDOM to match the VirtualDOM. It also
-/// includes a list of NodeRefs that need to be applied and effects that need to be triggered after the RealDOM has
-/// applied the edits.
-///
-/// Mutations are the only link between the RealDOM and the VirtualDOM.
-pub struct Mutations<'a> {
-    /// The list of edits that need to be applied for the RealDOM to match the VirtualDOM.
-    pub edits: Vec<DomEdit<'a>>,
-
-    /// The list of Scopes that were diffed, created, and removed during the Diff process.
-    pub dirty_scopes: FxHashSet<ScopeId>,
-
-    /// The list of nodes to connect to the RealDOM.
-    pub refs: Vec<NodeRefMutation<'a>>,
-}
-
-impl Debug for Mutations<'_> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("Mutations")
-            .field("edits", &self.edits)
-            .field("noderefs", &self.refs)
-            .finish()
-    }
-}
-
-/// A `DomEdit` represents a serialized form of the VirtualDom's trait-based API. This allows streaming edits across the
-/// network or through FFI boundaries.
-#[derive(Debug, PartialEq)]
-#[cfg_attr(
-    feature = "serialize",
-    derive(serde::Serialize, serde::Deserialize),
-    serde(tag = "type")
-)]
-pub enum DomEdit<'bump> {
-    /// Pop the topmost node from our stack and append them to the node
-    /// at the top of the stack.
-    AppendChildren {
-        /// The parent to append nodes to.
-        root: Option<u64>,
-
-        /// The ids of the children to append.
-        children: Vec<u64>,
-    },
-
-    /// Replace a given (single) node with a handful of nodes currently on the stack.
-    ReplaceWith {
-        /// The ID of the node to be replaced.
-        root: Option<u64>,
-
-        /// The ids of the nodes to replace the root with.
-        nodes: Vec<u64>,
-    },
-
-    /// Insert a number of nodes after a given node.
-    InsertAfter {
-        /// The ID of the node to insert after.
-        root: Option<u64>,
-
-        /// The ids of the nodes to insert after the target node.
-        nodes: Vec<u64>,
-    },
-
-    /// Insert a number of nodes before a given node.
-    InsertBefore {
-        /// The ID of the node to insert before.
-        root: Option<u64>,
-
-        /// The ids of the nodes to insert before the target node.
-        nodes: Vec<u64>,
-    },
-
-    /// Remove a particular node from the DOM
-    Remove {
-        /// The ID of the node to remove.
-        root: Option<u64>,
-    },
-
-    /// Create a new purely-text node
-    CreateTextNode {
-        /// The ID the new node should have.
-        root: Option<u64>,
-
-        /// The textcontent of the node
-        text: &'bump str,
-    },
-
-    /// Create a new purely-element node
-    CreateElement {
-        /// The ID the new node should have.
-        root: Option<u64>,
-
-        /// The tagname of the node
-        tag: &'bump str,
-
-        /// The number of children nodes that will follow this message.
-        children: u32,
-    },
-
-    /// Create a new purely-comment node with a given namespace
-    CreateElementNs {
-        /// The ID the new node should have.
-        root: Option<u64>,
-
-        /// The namespace of the node
-        tag: &'bump str,
-
-        /// The namespace of the node (like `SVG`)
-        ns: &'static str,
-
-        /// The number of children nodes that will follow this message.
-        children: u32,
-    },
-
-    /// Create a new placeholder node.
-    /// In most implementations, this will either be a hidden div or a comment node.
-    CreatePlaceholder {
-        /// The ID the new node should have.
-        root: Option<u64>,
-    },
-
-    /// Create a new Event Listener.
-    NewEventListener {
-        /// The name of the event to listen for.
-        event_name: &'static str,
-
-        /// The ID of the node to attach the listener to.
-        scope: ScopeId,
-
-        /// The ID of the node to attach the listener to.
-        root: Option<u64>,
-    },
-
-    /// Remove an existing Event Listener.
-    RemoveEventListener {
-        /// The ID of the node to remove.
-        root: Option<u64>,
-
-        /// The name of the event to remove.
-        event: &'static str,
-    },
-
-    /// Set the textcontent of a node.
-    SetText {
-        /// The ID of the node to set the textcontent of.
-        root: Option<u64>,
-
-        /// The textcontent of the node
-        text: &'bump str,
-    },
-
-    /// Set the value of a node's attribute.
-    SetAttribute {
-        /// The ID of the node to set the attribute of.
-        root: Option<u64>,
-
-        /// The name of the attribute to set.
-        field: &'static str,
-
-        /// The value of the attribute.
-        value: AttributeValue<'bump>,
-
-        // value: &'bump str,
-        /// The (optional) namespace of the attribute.
-        /// For instance, "style" is in the "style" namespace.
-        ns: Option<&'bump str>,
-    },
-
-    /// Remove an attribute from a node.
-    RemoveAttribute {
-        /// The ID of the node to remove.
-        root: Option<u64>,
-
-        /// The name of the attribute to remove.
-        name: &'static str,
-
-        /// The namespace of the attribute.
-        ns: Option<&'bump str>,
-    },
-
-    /// Clones a node.
-    CloneNode {
-        /// The ID of the node to clone.
-        id: Option<u64>,
-
-        /// The ID of the new node.
-        new_id: u64,
-    },
-
-    /// Clones the children of a node. (allows cloning fragments)
-    CloneNodeChildren {
-        /// The ID of the node to clone.
-        id: Option<u64>,
-
-        /// The ID of the new node.
-        new_ids: Vec<u64>,
-    },
-
-    /// Navigates to the last node to the first child of the current node.
-    FirstChild {},
-
-    /// Navigates to the last node to the last child of the current node.
-    NextSibling {},
-
-    /// Navigates to the last node to the parent of the current node.
-    ParentNode {},
-
-    /// Stores the last node with a new id.
-    StoreWithId {
-        /// The ID of the node to store.
-        id: u64,
-    },
-
-    /// Manually set the last node.
-    SetLastNode {
-        /// The ID to set the last node to.
-        id: u64,
-    },
-}
-
-use rustc_hash::FxHashSet;
-use DomEdit::*;
-
-#[allow(unused)]
-impl<'a> Mutations<'a> {
-    pub(crate) fn new() -> Self {
-        Self {
-            edits: Vec::new(),
-            refs: Vec::new(),
-            dirty_scopes: Default::default(),
-        }
-    }
-
-    pub(crate) fn replace_with(&mut self, root: Option<u64>, nodes: Vec<u64>) {
-        self.edits.push(ReplaceWith { nodes, root });
-    }
-
-    pub(crate) fn insert_after(&mut self, root: Option<u64>, nodes: Vec<u64>) {
-        self.edits.push(InsertAfter { nodes, root });
-    }
-
-    pub(crate) fn insert_before(&mut self, root: Option<u64>, nodes: Vec<u64>) {
-        self.edits.push(InsertBefore { nodes, root });
-    }
-
-    pub(crate) fn append_children(&mut self, root: Option<u64>, children: Vec<u64>) {
-        self.edits.push(AppendChildren { root, children });
-    }
-
-    // Remove Nodes from the dom
-    pub(crate) fn remove(&mut self, id: Option<u64>) {
-        self.edits.push(Remove { root: id });
-    }
-
-    // Create
-    pub(crate) fn create_text_node(&mut self, text: &'a str, id: Option<u64>) {
-        self.edits.push(CreateTextNode { text, root: id });
-    }
-
-    pub(crate) fn create_element(
-        &mut self,
-        tag: &'static str,
-        ns: Option<&'static str>,
-        id: Option<u64>,
-        children: u32,
-    ) {
-        match ns {
-            Some(ns) => self.edits.push(CreateElementNs {
-                root: id,
-                ns,
-                tag,
-                children,
-            }),
-            None => self.edits.push(CreateElement {
-                root: id,
-                tag,
-                children,
-            }),
-        }
-    }
-
-    // placeholders are nodes that don't get rendered but still exist as an "anchor" in the real dom
-    pub(crate) fn create_placeholder(&mut self, id: Option<u64>) {
-        self.edits.push(CreatePlaceholder { root: id });
-    }
-
-    // events
-    pub(crate) fn new_event_listener(&mut self, listener: &Listener, scope: ScopeId) {
-        let Listener {
-            event,
-            mounted_node,
-            ..
-        } = listener;
-
-        let element_id = Some(mounted_node.get().unwrap().into());
-
-        self.edits.push(NewEventListener {
-            scope,
-            event_name: event,
-            root: element_id,
-        });
-    }
-
-    pub(crate) fn remove_event_listener(&mut self, event: &'static str, root: Option<u64>) {
-        self.edits.push(RemoveEventListener { event, root });
-    }
-
-    // modify
-    pub(crate) fn set_text(&mut self, text: &'a str, root: Option<u64>) {
-        self.edits.push(SetText { text, root });
-    }
-
-    pub(crate) fn set_attribute(&mut self, attribute: &'a Attribute<'a>, root: Option<u64>) {
-        let Attribute {
-            value, attribute, ..
-        } = attribute;
-
-        self.edits.push(SetAttribute {
-            field: attribute.name,
-            value: value.clone(),
-            ns: attribute.namespace,
-            root,
-        });
-    }
-
-    pub(crate) fn remove_attribute(&mut self, attribute: &Attribute, root: Option<u64>) {
-        let Attribute { attribute, .. } = attribute;
-
-        self.edits.push(RemoveAttribute {
-            name: attribute.name,
-            ns: attribute.namespace,
-            root,
-        });
-    }
-
-    pub(crate) fn mark_dirty_scope(&mut self, scope: ScopeId) {
-        self.dirty_scopes.insert(scope);
-    }
-
-    pub(crate) fn clone_node(&mut self, id: Option<u64>, new_id: u64) {
-        self.edits.push(CloneNode { id, new_id });
-    }
-
-    pub(crate) fn clone_node_children(&mut self, id: Option<u64>, new_ids: Vec<u64>) {
-        self.edits.push(CloneNodeChildren { id, new_ids });
-    }
-
-    pub(crate) fn first_child(&mut self) {
-        self.edits.push(FirstChild {});
-    }
-
-    pub(crate) fn next_sibling(&mut self) {
-        self.edits.push(NextSibling {});
-    }
-
-    pub(crate) fn parent_node(&mut self) {
-        self.edits.push(ParentNode {});
-    }
-
-    pub(crate) fn store_with_id(&mut self, id: u64) {
-        self.edits.push(StoreWithId { id });
-    }
-
-    pub(crate) fn set_last_node(&mut self, id: u64) {
-        self.edits.push(SetLastNode { id });
-    }
-}
-
-// refs are only assigned once
-pub struct NodeRefMutation<'a> {
-    pub element: &'a mut Option<once_cell::sync::OnceCell<Box<dyn Any>>>,
-    pub element_id: ElementId,
-}
-
-impl<'a> std::fmt::Debug for NodeRefMutation<'a> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("NodeRefMutation")
-            .field("element_id", &self.element_id)
-            .finish()
-    }
-}
-
-impl<'a> NodeRefMutation<'a> {
-    pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
-        self.element
-            .as_ref()
-            .and_then(|f| f.get())
-            .and_then(|f| f.downcast_ref::<T>())
-    }
-    pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
-        self.element
-            .as_mut()
-            .and_then(|f| f.get_mut())
-            .and_then(|f| f.downcast_mut::<T>())
-    }
-}

+ 0 - 866
packages/core/src.old/nodes.old.rs

@@ -1,866 +0,0 @@
-//! Virtual Node Support
-//!
-//! VNodes represent lazily-constructed VDom trees that support diffing and event handlers. These VNodes should be *very*
-//! cheap and *very* fast to construct - building a full tree should be quick.
-use crate::{
-    innerlude::{AttributeValue, ComponentPtr, Element, Properties, Scope, ScopeId, ScopeState},
-    lazynodes::LazyNodes,
-    AnyEvent, Component,
-};
-use bumpalo::{boxed::Box as BumpBox, Bump};
-use std::{
-    cell::{Cell, RefCell},
-    fmt::{Arguments, Debug, Formatter},
-};
-
-use crate::template::*;
-
-/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
-///
-/// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of:
-///
-/// - the `rsx!` macro
-/// - the [`NodeFactory`] API
-pub enum VNode<'src> {
-    /// Text VNodes are simply bump-allocated (or static) string slices
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// let mut vdom = VirtualDom::new();
-    /// let node = vdom.render_vnode(rsx!( "hello" ));
-    ///
-    /// if let VNode::Text(vtext) = node {
-    ///     assert_eq!(vtext.text, "hello");
-    ///     assert_eq!(vtext.dom_id.get(), None);
-    ///     assert_eq!(vtext.is_static, true);
-    /// }
-    /// ```
-    Text(&'src VText<'src>),
-
-    /// Element VNodes are VNodes that may contain attributes, listeners, a key, a tag, and children.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// let mut vdom = VirtualDom::new();
-    ///
-    /// let node = vdom.render_vnode(rsx!{
-    ///     div {
-    ///         key: "a",
-    ///         onclick: |e| log::info!("clicked"),
-    ///         hidden: "true",
-    ///         style: { background_color: "red" },
-    ///         "hello"
-    ///     }
-    /// });
-    ///
-    /// if let VNode::Element(velement) = node {
-    ///     assert_eq!(velement.tag_name, "div");
-    ///     assert_eq!(velement.namespace, None);
-    ///     assert_eq!(velement.key, Some("a"));
-    /// }
-    /// ```
-    Element(&'src VElement<'src>),
-
-    /// Fragment nodes may contain many VNodes without a single root.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// rsx!{
-    ///     a {}
-    ///     link {}
-    ///     style {}
-    ///     "asd"
-    ///     Example {}
-    /// }
-    /// ```
-    Fragment(&'src VFragment<'src>),
-
-    /// Component nodes represent a mounted component with props, children, and a key.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// fn Example(cx: Scope) -> Element {
-    ///     ...
-    /// }
-    ///
-    /// let mut vdom = VirtualDom::new();
-    ///
-    /// let node = vdom.render_vnode(rsx!( Example {} ));
-    ///
-    /// if let VNode::Component(vcomp) = node {
-    ///     assert_eq!(vcomp.user_fc, Example as *const ());
-    /// }
-    /// ```
-    Component(&'src VComponent<'src>),
-
-    /// Templates are containers for other nodes
-    ///
-    ///
-    Template(&'src VTemplate<'src>),
-}
-
-impl<'src> VNode<'src> {
-    /// Get the VNode's "key" used in the keyed diffing algorithm.
-    pub fn key(&self) -> Option<&'src str> {
-        match &self {
-            VNode::Element(el) => el.key,
-            VNode::Component(c) => c.key,
-            VNode::Text(_t) => None,
-            VNode::Template(_t) => None,
-            VNode::Fragment(_f) => None,
-        }
-    }
-
-    /// Get the ElementID of the mounted VNode.
-    ///
-    /// Panics if the mounted ID is None or if the VNode is not represented by a single Element.
-    pub fn mounted_id(&self) -> ElementId {
-        self.try_mounted_id().unwrap()
-    }
-
-    /// Try to get the ElementID of the mounted VNode.
-    ///
-    /// Returns None if the VNode is not mounted, or if the VNode cannot be presented by a mounted ID (Fragment/Component)
-    pub fn try_mounted_id(&self) -> Option<ElementId> {
-        match &self {
-            VNode::Text(el) => el.id.get(),
-            VNode::Element(el) => el.id.get(),
-            VNode::Fragment(_) => None,
-            VNode::Component(_) => None,
-            VNode::Template(_) => todo!(),
-        }
-    }
-
-    // Create an "owned" version of the vnode.
-    pub(crate) fn decouple(&self) -> VNode<'src> {
-        match *self {
-            VNode::Text(t) => VNode::Text(t),
-            VNode::Element(e) => VNode::Element(e),
-            VNode::Component(c) => VNode::Component(c),
-            VNode::Fragment(f) => VNode::Fragment(f),
-            VNode::Template(_) => todo!(),
-        }
-    }
-}
-
-impl Debug for VNode<'_> {
-    fn fmt(&self, s: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
-        match &self {
-            VNode::Element(el) => s
-                .debug_struct("VNode::Element")
-                .field("name", &el.tag)
-                .field("key", &el.key)
-                .field("attrs", &el.attributes)
-                .field("children", &el.children)
-                .field("id", &el.id)
-                .finish(),
-            VNode::Text(t) => s
-                .debug_struct("VNode::Text")
-                .field("text", &t.text)
-                .field("id", &t.id)
-                .finish(),
-            VNode::Fragment(frag) => s
-                .debug_struct("VNode::Fragment")
-                .field("children", &frag.children)
-                .finish(),
-            VNode::Component(comp) => s
-                .debug_struct("VNode::Component")
-                .field("name", &comp.fn_name)
-                .field("fnptr", &comp.user_fc)
-                .field("key", &comp.key)
-                .field("scope", &comp.scope)
-                .finish(),
-            VNode::Template(_) => todo!(),
-        }
-    }
-}
-
-/// An Element's unique identifier.
-///
-/// `ElementId` is a `usize` that is unique across the entire VirtualDOM - but not unique across time. If a component is
-/// unmounted, then the `ElementId` will be reused for a new component.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub struct ElementId(pub usize);
-impl std::fmt::Display for ElementId {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(f, "{}", self.0)
-    }
-}
-
-impl ElementId {
-    /// Convertt the ElementId to a `u64`.
-    pub fn as_u64(self) -> u64 {
-        self.0 as u64
-    }
-}
-
-fn empty_cell() -> Cell<Option<ElementId>> {
-    Cell::new(None)
-}
-
-/// A placeholder node only generated when Fragments don't have any children.
-pub struct VPlaceholder {
-    /// The [`ElementId`] of the placeholder.
-    pub id: Cell<Option<ElementId>>,
-}
-
-/// A bump-allocated string slice and metadata.
-pub struct VText<'src> {
-    /// The [`ElementId`] of the VText.
-    pub id: Cell<Option<ElementId>>,
-
-    /// The text of the VText.
-    pub text: &'src str,
-
-    /// An indiciation if this VText can be ignored during diffing
-    /// Is usually only when there are no strings to be formatted (so the text is &'static str)
-    pub is_static: bool,
-}
-
-/// A list of VNodes with no single root.
-pub struct VFragment<'src> {
-    /// The key of the fragment to be used during keyed diffing.
-    pub key: Option<&'src str>,
-
-    pub memo: Option<FragmentMemo<'src>>,
-
-    /// Fragments can never have zero children. Enforced by NodeFactory.
-    ///
-    /// You *can* make a fragment with no children, but it's not a valid fragment and your VDom will panic.
-    pub children: &'src [VNode<'src>],
-}
-
-pub struct FragmentMemo<'a> {
-    pub template: TemplateDef<'static>,
-
-    pub dynamic_nodes: &'a Cell<[ElementId]>,
-}
-
-/// An element like a "div" with children, listeners, and attributes.
-pub struct VElement<'a> {
-    /// The [`ElementId`] of the VText.
-    pub id: Cell<Option<ElementId>>,
-
-    /// The key of the element to be used during keyed diffing.
-    pub key: Option<&'a str>,
-
-    /// The tag name of the element.
-    ///
-    /// IE "div"
-    pub tag: &'static str,
-
-    /// The namespace of the VElement
-    ///
-    /// IE "svg"
-    pub namespace: Option<&'static str>,
-
-    /// The parent of the Element (if any).
-    ///
-    /// Used when bubbling events
-    pub parent: Cell<Option<ElementId>>,
-
-    /// The Listeners of the VElement.
-    pub listeners: &'a [Listener<'a>],
-
-    /// The attributes of the VElement.
-    pub attributes: &'a [Attribute<'a>],
-
-    /// The children of the VElement.
-    pub children: &'a [VNode<'a>],
-}
-
-impl Debug for VElement<'_> {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("VElement")
-            .field("tag_name", &self.tag)
-            .field("namespace", &self.namespace)
-            .field("key", &self.key)
-            .field("id", &self.id)
-            .field("parent", &self.parent)
-            .field("listeners", &self.listeners.len())
-            .field("attributes", &self.attributes)
-            .field("children", &self.children)
-            .finish()
-    }
-}
-
-/// A trait for any generic Dioxus Element.
-///
-/// This trait provides the ability to use custom elements in the `rsx!` macro.
-///
-/// ```rust, ignore
-/// struct my_element;
-///
-/// impl DioxusElement for my_element {
-///     const TAG_NAME: "my_element";
-///     const NAME_SPACE: None;
-/// }
-///
-/// let _ = rsx!{
-///     my_element {}
-/// };
-/// ```
-pub trait DioxusElement {
-    /// The tag name of the element.
-    const TAG_NAME: &'static str;
-
-    /// The namespace of the element.
-    const NAME_SPACE: Option<&'static str>;
-
-    /// The tag name of the element.
-    #[inline]
-    fn tag_name(&self) -> &'static str {
-        Self::TAG_NAME
-    }
-
-    /// The namespace of the element.
-    #[inline]
-    fn namespace(&self) -> Option<&'static str> {
-        Self::NAME_SPACE
-    }
-}
-
-/// An attribute on a DOM node, such as `id="my-thing"` or
-/// `href="https://example.com"`.
-#[derive(Clone, Debug)]
-pub struct Attribute<'a> {
-    /// The name of the attribute.
-    pub name: &'static str,
-
-    /// The value of the attribute.
-    pub value: AttributeValue<'a>,
-
-    /// An indication if this attribute can be ignored during diffing
-    ///
-    /// Usually only when there are no strings to be formatted (so the value is &'static str)
-    pub is_static: bool,
-
-    /// An indication of we should always try and set the attribute.
-    /// Used in controlled components to ensure changes are propagated.
-    pub is_volatile: bool,
-
-    /// The namespace of the attribute.
-    ///
-    /// Doesn't exist in the html spec.
-    /// Used in Dioxus to denote "style" tags and other attribute groups.
-    pub namespace: Option<&'static str>,
-}
-
-/// An event listener.
-/// IE onclick, onkeydown, etc
-pub struct Listener<'bump> {
-    /// The ID of the node that this listener is mounted to
-    /// Used to generate the event listener's ID on the DOM
-    pub mounted_node: Cell<Option<ElementId>>,
-
-    /// The type of event to listen for.
-    ///
-    /// IE "click" - whatever the renderer needs to attach the listener by name.
-    pub event: &'static str,
-
-    /// The actual callback that the user specified
-    pub(crate) callback: InternalHandler<'bump>,
-}
-
-pub type InternalHandler<'bump> = &'bump RefCell<Option<InternalListenerCallback<'bump>>>;
-type InternalListenerCallback<'bump> = BumpBox<'bump, dyn FnMut(AnyEvent) + 'bump>;
-type ExternalListenerCallback<'bump, T> = BumpBox<'bump, dyn FnMut(T) + 'bump>;
-
-/// The callback type generated by the `rsx!` macro when an `on` field is specified for components.
-///
-/// This makes it possible to pass `move |evt| {}` style closures into components as property fields.
-///
-///
-/// # Example
-///
-/// ```rust, ignore
-///
-/// rsx!{
-///     MyComponent { onclick: move |evt| log::info!("clicked"), }
-/// }
-///
-/// #[derive(Props)]
-/// struct MyProps<'a> {
-///     onclick: EventHandler<'a, MouseEvent>,
-/// }
-///
-/// fn MyComponent(cx: Scope<'a, MyProps<'a>>) -> Element {
-///     cx.render(rsx!{
-///         button {
-///             onclick: move |evt| cx.props.onclick.call(evt),
-///         }
-///     })
-/// }
-///
-/// ```
-pub struct EventHandler<'bump, T = ()> {
-    /// The (optional) callback that the user specified
-    /// Uses a `RefCell` to allow for interior mutability, and FnMut closures.
-    pub callback: RefCell<Option<ExternalListenerCallback<'bump, T>>>,
-}
-
-impl<'a, T> Default for EventHandler<'a, T> {
-    fn default() -> Self {
-        Self {
-            callback: RefCell::new(None),
-        }
-    }
-}
-
-impl<T> EventHandler<'_, T> {
-    /// Call this event handler with the appropriate event type
-    pub fn call(&self, event: T) {
-        if let Some(callback) = self.callback.borrow_mut().as_mut() {
-            callback(event);
-        }
-    }
-
-    /// Forcibly drop the internal handler callback, releasing memory
-    pub fn release(&self) {
-        self.callback.replace(None);
-    }
-}
-
-/// Virtual Components for custom user-defined components
-/// Only supports the functional syntax
-pub struct VComponent<'src> {
-    /// The key of the component to be used during keyed diffing.
-    pub key: Option<&'src str>,
-
-    /// The ID of the component.
-    /// Will not be assigned until after the component has been initialized.
-    pub scope: Cell<Option<ScopeId>>,
-
-    /// An indication if the component is static (can be memozied)
-    pub can_memoize: bool,
-
-    /// The function pointer to the component's render function.
-    pub user_fc: ComponentPtr,
-
-    /// The actual name of the component.
-    pub fn_name: &'static str,
-
-    /// The props of the component.
-    pub props: RefCell<Option<Box<dyn AnyProps + 'src>>>,
-}
-
-pub(crate) struct VComponentProps<P> {
-    pub render_fn: Component<P>,
-    pub memo: unsafe fn(&P, &P) -> bool,
-    pub props: P,
-}
-
-pub trait AnyProps {
-    fn as_ptr(&self) -> *const ();
-    fn render<'a>(&'a self, bump: &'a ScopeState) -> Element<'a>;
-    unsafe fn memoize(&self, other: &dyn AnyProps) -> bool;
-}
-
-impl<P> AnyProps for VComponentProps<P> {
-    fn as_ptr(&self) -> *const () {
-        &self.props as *const _ as *const ()
-    }
-
-    // Safety:
-    // this will downcast the other ptr as our swallowed type!
-    // you *must* make this check *before* calling this method
-    // if your functions are not the same, then you will downcast a pointer into a different type (UB)
-    unsafe fn memoize(&self, other: &dyn AnyProps) -> bool {
-        let real_other: &P = &*(other.as_ptr() as *const _ as *const P);
-        let real_us: &P = &*(self.as_ptr() as *const _ as *const P);
-        (self.memo)(real_us, real_other)
-    }
-
-    fn render<'a>(&'a self, scope: &'a ScopeState) -> Element<'a> {
-        let props = unsafe { std::mem::transmute::<&P, &P>(&self.props) };
-        (self.render_fn)(Scope { scope, props })
-    }
-}
-
-/// This struct provides an ergonomic API to quickly build VNodes.
-///
-/// NodeFactory is used to build VNodes in the component's memory space.
-/// This struct adds metadata to the final VNode about listeners, attributes, and children
-#[derive(Copy, Clone)]
-pub struct NodeFactory<'a> {
-    pub(crate) scope: &'a ScopeState,
-    pub(crate) bump: &'a Bump,
-}
-
-impl<'a> NodeFactory<'a> {
-    /// Create a new [`NodeFactory`] from a [`Scope`] or [`ScopeState`]
-    pub fn new(scope: &'a ScopeState) -> NodeFactory<'a> {
-        NodeFactory {
-            scope,
-            bump: &scope.wip_frame().bump,
-        }
-    }
-
-    /// Get the custom allocator for this component
-    #[inline]
-    pub fn bump(&self) -> &'a bumpalo::Bump {
-        self.bump
-    }
-
-    /// Directly pass in text blocks without the need to use the format_args macro.
-    pub fn static_text(&self, text: &'static str) -> VNode<'a> {
-        VNode::Text(self.bump.alloc(VText {
-            id: empty_cell(),
-            text,
-            is_static: true,
-        }))
-    }
-
-    /// Parses a lazy text Arguments and returns a string and a flag indicating if the text is 'static
-    ///
-    /// Text that's static may be pointer compared, making it cheaper to diff
-    pub fn raw_text(&self, args: Arguments) -> (&'a str, bool) {
-        match args.as_str() {
-            Some(static_str) => (static_str, true),
-            None => {
-                use bumpalo::core_alloc::fmt::Write;
-                let mut str_buf = bumpalo::collections::String::new_in(self.bump);
-                str_buf.write_fmt(args).unwrap();
-                (str_buf.into_bump_str(), false)
-            }
-        }
-    }
-
-    /// Create some text that's allocated along with the other vnodes
-    ///
-    pub fn text(&self, args: Arguments) -> VNode<'a> {
-        let (text, is_static) = self.raw_text(args);
-
-        VNode::Text(self.bump.alloc(VText {
-            text,
-            is_static,
-            id: empty_cell(),
-        }))
-    }
-
-    /// Create a new [`VNode::Element`]
-    pub fn element(
-        &self,
-        el: impl DioxusElement,
-        listeners: &'a [Listener<'a>],
-        attributes: &'a [Attribute<'a>],
-        children: &'a [VNode<'a>],
-        key: Option<Arguments>,
-    ) -> VNode<'a> {
-        self.raw_element(
-            el.tag_name(),
-            el.namespace(),
-            listeners,
-            attributes,
-            children,
-            key,
-        )
-    }
-
-    /// Create a new [`VNode::Element`] without the trait bound
-    ///
-    /// IE pass in "div" instead of `div`
-    pub fn raw_element(
-        &self,
-        tag_name: &'static str,
-        namespace: Option<&'static str>,
-        listeners: &'a [Listener<'a>],
-        attributes: &'a [Attribute<'a>],
-        children: &'a [VNode<'a>],
-        key: Option<Arguments>,
-    ) -> VNode<'a> {
-        let key = key.map(|f| self.raw_text(f).0);
-
-        let mut items = self.scope.items.borrow_mut();
-        for listener in listeners {
-            let long_listener = unsafe { std::mem::transmute(listener) };
-            items.listeners.push(long_listener);
-        }
-
-        VNode::Element(self.bump.alloc(VElement {
-            tag: tag_name,
-            key,
-            namespace,
-            listeners,
-            attributes,
-            children,
-            id: empty_cell(),
-            parent: empty_cell(),
-        }))
-    }
-
-    /// Create a new [`Attribute`]
-    pub fn attr(
-        &self,
-        name: &'static str,
-        val: Arguments,
-        namespace: Option<&'static str>,
-        is_volatile: bool,
-    ) -> Attribute<'a> {
-        let (value, is_static) = self.raw_text(val);
-        Attribute {
-            name,
-            value: AttributeValue::Text(value),
-            is_static,
-            namespace,
-            is_volatile,
-        }
-    }
-
-    /// Create a new [`Attribute`] using non-arguments
-    pub fn custom_attr(
-        &self,
-        name: &'static str,
-        value: AttributeValue<'a>,
-        namespace: Option<&'static str>,
-        is_volatile: bool,
-        is_static: bool,
-    ) -> Attribute<'a> {
-        Attribute {
-            name,
-            value,
-            is_static,
-            namespace,
-            is_volatile,
-        }
-    }
-
-    /// Create a new [`VNode::Component`]
-    pub fn component<P>(
-        &self,
-        component: fn(Scope<'a, P>) -> Element,
-        props: P,
-        key: Option<Arguments>,
-        fn_name: &'static str,
-    ) -> VNode<'a>
-    where
-        P: Properties + 'a,
-    {
-        let vcomp = self.bump.alloc(VComponent {
-            key: key.map(|f| self.raw_text(f).0),
-            scope: Default::default(),
-            can_memoize: P::IS_STATIC,
-            user_fc: component as ComponentPtr,
-            fn_name,
-            props: RefCell::new(Some(Box::new(VComponentProps {
-                props,
-                memo: P::memoize, // smuggle the memoization function across borders
-
-                // i'm sorry but I just need to bludgeon the lifetimes into place here
-                // this is safe because we're managing all lifetimes to originate from previous calls
-                // the intricacies of Rust's lifetime system make it difficult to properly express
-                // the transformation from this specific lifetime to the for<'a> lifetime
-                render_fn: unsafe { std::mem::transmute(component) },
-            }))),
-        });
-
-        if !P::IS_STATIC {
-            let vcomp = &*vcomp;
-            let vcomp = unsafe { std::mem::transmute(vcomp) };
-            self.scope.items.borrow_mut().borrowed_props.push(vcomp);
-        }
-
-        VNode::Component(vcomp)
-    }
-
-    /// Create a new [`Listener`]
-    pub fn listener(self, event: &'static str, callback: InternalHandler<'a>) -> Listener<'a> {
-        Listener {
-            event,
-            mounted_node: Cell::new(None),
-            callback,
-        }
-    }
-
-    pub fn template(&self, def: &'static TemplateDef, dynamic_nodes: &'a [VNode<'a>]) -> VNode<'a> {
-        VNode::Template(self.bump.alloc(VTemplate {
-            def,
-            dynamic_nodes,
-            rendered_nodes: &[],
-        }))
-    }
-
-    // /// Create a new [`VNode::Fragment`] from a root of the rsx! call
-    // pub fn fragment_root<'b, 'c>(
-    //     self,
-    //     node_iter: impl IntoIterator<Item = impl IntoVNode<'a> + 'c> + 'b,
-    // ) -> VNode<'a> {
-    //     let mut nodes = bumpalo::collections::Vec::new_in(self.bump);
-
-    //     for node in node_iter {
-    //         nodes.push(node.into_vnode(self));
-    //     }
-
-    //     if nodes.is_empty() {
-    //         VNode::Placeholder(self.bump.alloc(VPlaceholder { id: empty_cell() }))
-    //     } else {
-    //         VNode::Fragment(self.bump.alloc(VFragment {
-    //             children: nodes.into_bump_slice(),
-    //             key: None,
-    //         }))
-    //     }
-    // }
-
-    // /// Create a new [`VNode::Fragment`] from any iterator
-    // pub fn fragment_from_iter<'c, I, J>(
-    //     self,
-    //     node_iter: impl IntoVNode<'a, I, J> + 'c,
-    // ) -> VNode<'a> {
-    //     node_iter.into_vnode(self)
-    // }
-
-    // /// Create a new [`VNode`] from any iterator of children
-    // pub fn create_children(
-    //     self,
-    //     node_iter: impl IntoIterator<Item = impl IntoVNode<'a>>,
-    // ) -> Element<'a> {
-    //     let mut nodes = bumpalo::collections::Vec::new_in(self.bump);
-
-    //     for node in node_iter {
-    //         nodes.push(node.into_vnode(self));
-    //     }
-
-    //     if nodes.is_empty() {
-    //         Some(VNode::Placeholder(
-    //             self.bump.alloc(VPlaceholder { id: empty_cell() }),
-    //         ))
-    //     } else {
-    //         let children = nodes.into_bump_slice();
-
-    //         Some(VNode::Fragment(self.bump.alloc(VFragment {
-    //             children,
-    //             key: None,
-    //         })))
-    //     }
-    // }
-
-    /// Create a new [`EventHandler`] from an [`FnMut`]
-    pub fn event_handler<T>(self, f: impl FnMut(T) + 'a) -> EventHandler<'a, T> {
-        let handler: &mut dyn FnMut(T) = self.bump.alloc(f);
-        let caller = unsafe { BumpBox::from_raw(handler as *mut dyn FnMut(T)) };
-        let callback = RefCell::new(Some(caller));
-        EventHandler { callback }
-    }
-}
-
-impl Debug for NodeFactory<'_> {
-    fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        Ok(())
-    }
-}
-
-/// Trait implementations for use in the rsx! and html! macros.
-///
-/// ## Details
-///
-/// This section provides convenience methods and trait implementations for converting common structs into a format accepted
-/// by the macros.
-///
-/// All dynamic content in the macros must flow in through `fragment_from_iter`. Everything else must be statically layed out.
-/// We pipe basically everything through `fragment_from_iter`, so we expect a very specific type:
-/// ```rust, ignore
-/// impl IntoIterator<Item = impl IntoVNode<'a>>
-/// ```
-///
-/// As such, all node creation must go through the factory, which is only available in the component context.
-/// These strict requirements make it possible to manage lifetimes and state.
-pub trait IntoVNode<'a, I = (), J = ()> {
-    /// Convert this into a [`VNode`], using the [`NodeFactory`] as a source of allocation
-    fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>;
-}
-
-// TODO: do we even need this? It almost seems better not to
-// // For the case where a rendered VNode is passed into the rsx! macro through curly braces
-impl<'a> IntoVNode<'a> for VNode<'a> {
-    fn into_vnode(self, _: NodeFactory<'a>) -> VNode<'a> {
-        self
-    }
-}
-
-// Conveniently, we also support "null" (nothing) passed in
-impl IntoVNode<'_> for () {
-    fn into_vnode(self, cx: NodeFactory) -> VNode {
-        todo!()
-        // VNode::Placeholder(cx.bump.alloc(VPlaceholder { id: empty_cell() }))
-    }
-}
-
-impl<'a, 'b> IntoVNode<'a> for LazyNodes<'a, 'b> {
-    fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
-        self.call(cx)
-    }
-}
-
-impl<'b> IntoVNode<'_> for &'b str {
-    fn into_vnode(self, cx: NodeFactory) -> VNode {
-        cx.text(format_args!("{}", self))
-    }
-}
-
-impl IntoVNode<'_> for String {
-    fn into_vnode(self, cx: NodeFactory) -> VNode {
-        cx.text(format_args!("{}", self))
-    }
-}
-
-impl IntoVNode<'_> for Arguments<'_> {
-    fn into_vnode(self, cx: NodeFactory) -> VNode {
-        cx.text(self)
-    }
-}
-
-impl<'a> IntoVNode<'a> for &VNode<'a> {
-    fn into_vnode(self, _cx: NodeFactory<'a>) -> VNode<'a> {
-        // borrowed nodes are strange
-        self.decouple()
-    }
-}
-
-// Note that we're using the E as a generic but this is never crafted anyways.
-pub struct FromNodeIterator;
-impl<'a, T, I, E> IntoVNode<'a, FromNodeIterator, E> for T
-where
-    T: IntoIterator<Item = I>,
-    I: IntoVNode<'a, E>,
-{
-    fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
-        let mut nodes = bumpalo::collections::Vec::new_in(cx.bump);
-
-        for node in self {
-            nodes.push(node.into_vnode(cx));
-        }
-
-        todo!()
-        // if nodes.is_empty() {
-        //     VNode::Placeholder(cx.bump.alloc(VPlaceholder { id: empty_cell() }))
-        // } else {
-        //     let children = nodes.into_bump_slice();
-
-        //     if cfg!(debug_assertions)
-        //         && children.len() > 1
-        //         && children.last().unwrap().key().is_none()
-        //     {
-        //         // todo: make the backtrace prettier or remove it altogether
-        //         log::error!(
-        //             r#"
-        //         Warning: Each child in an array or iterator should have a unique "key" prop.
-        //         Not providing a key will lead to poor performance with lists.
-        //         See docs.rs/dioxus for more information.
-        //         -------------
-        //         {:?}
-        //         "#,
-        //             backtrace::Backtrace::new()
-        //         );
-        //     }
-
-        //     VNode::Fragment(cx.bump.alloc(VFragment {
-        //         children,
-        //         key: None,
-        //     }))
-        // }
-    }
-}

+ 0 - 163
packages/core/src.old/nodes/arbitrary_value.rs

@@ -1,163 +0,0 @@
-use std::{
-    any::Any,
-    fmt::{Arguments, Formatter},
-};
-
-use bumpalo::Bump;
-
-/// Possible values for an attribute
-#[derive(Clone, Copy)]
-pub enum AttributeValue<'a> {
-    /// Reference strs, most common
-    Text(&'a str),
-    /// Basic float values
-    Float(f32),
-    /// Basic Int values
-    Int(i32),
-    /// Basic bool values
-    Bool(bool),
-    /// Everything else
-    Any(&'a dyn AnyAttributeValue),
-}
-
-impl<'a> PartialEq for AttributeValue<'a> {
-    fn eq(&self, other: &Self) -> bool {
-        match (self, other) {
-            (Self::Text(l0), Self::Text(r0)) => l0 == r0,
-            (Self::Float(l0), Self::Float(r0)) => l0 == r0,
-            (Self::Int(l0), Self::Int(r0)) => l0 == r0,
-            (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
-            (Self::Any(l0), Self::Any(r0)) => (*l0).cmp_any(*r0),
-            _ => false,
-        }
-    }
-}
-
-impl std::fmt::Debug for AttributeValue<'_> {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        match self {
-            AttributeValue::Text(s) => write!(f, "AttributeValue::Text({:?})", s),
-            AttributeValue::Float(v) => write!(f, "AttributeValue::Float({:?})", v),
-            AttributeValue::Int(v) => write!(f, "AttributeValue::Int({:?})", v),
-            AttributeValue::Bool(b) => write!(f, "AttributeValue::Bool({:?})", b),
-            AttributeValue::Any(_) => write!(f, "AttributeValue::Any()"),
-        }
-    }
-}
-
-/// A value that can be converted into an attribute value
-pub trait IntoAttributeValue<'a> {
-    /// Convert into an attribute value
-    fn into_value(self, bump: &'a Bump) -> AttributeValue<'a>;
-}
-
-impl<'a> IntoAttributeValue<'a> for &'a str {
-    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
-        AttributeValue::Text(self)
-    }
-}
-impl<'a> IntoAttributeValue<'a> for f32 {
-    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
-        AttributeValue::Float(self)
-    }
-}
-impl<'a> IntoAttributeValue<'a> for i32 {
-    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
-        AttributeValue::Int(self)
-    }
-}
-impl<'a> IntoAttributeValue<'a> for bool {
-    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
-        AttributeValue::Bool(self)
-    }
-}
-impl<'a> IntoAttributeValue<'a> for Arguments<'_> {
-    fn into_value(self, bump: &'a Bump) -> AttributeValue<'a> {
-        use bumpalo::core_alloc::fmt::Write;
-        let mut str_buf = bumpalo::collections::String::new_in(bump);
-        str_buf.write_fmt(self).unwrap();
-        AttributeValue::Text(str_buf.into_bump_str())
-    }
-}
-
-// todo
-#[allow(missing_docs)]
-impl<'a> AttributeValue<'a> {
-    pub fn is_truthy(&self) -> bool {
-        match self {
-            AttributeValue::Text(t) => *t == "true",
-            AttributeValue::Bool(t) => *t,
-            _ => false,
-        }
-    }
-
-    pub fn is_falsy(&self) -> bool {
-        match self {
-            AttributeValue::Text(t) => *t == "false",
-            AttributeValue::Bool(t) => !(*t),
-            _ => false,
-        }
-    }
-}
-
-/// A trait that allows for comparing two values of the same type through the Any trait
-///
-/// Defaults to false if the types are not the same
-///
-/// This is an implicit trait, so any value that is 'static and PartialEq can be used directly
-///
-/// If you want to override the default behavior, you should implement PartialEq through a wrapper type
-pub trait AnyAttributeValue: Any {
-    /// Perform a comparison between two values
-    fn cmp_any<'a>(&'a self, _other: &'a dyn AnyAttributeValue) -> bool {
-        false
-    }
-}
-
-impl<T: Any + PartialEq> AnyAttributeValue for T {
-    fn cmp_any(&self, other: &dyn AnyAttributeValue) -> bool {
-        // we can't, for whatever reason use other as &dyn Any
-        let right: &dyn Any = unsafe { std::mem::transmute(other) };
-
-        match right.downcast_ref::<T>() {
-            Some(right) => self == right,
-            None => false,
-        }
-    }
-}
-
-#[test]
-fn cmp_any_works_even_though_it_transmutes() {
-    // same type, same value
-    let a = 2;
-    let b = 2;
-    assert!(a.cmp_any(&b as &dyn AnyAttributeValue));
-
-    // same type, different value
-    let a = "asds";
-    let b = "asdsasd";
-    assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
-
-    // different type, different values
-    let a = 123;
-    let b = "asdsasd";
-    assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
-
-    // Custom structs
-    #[derive(PartialEq)]
-    struct CustomStruct {
-        a: i32,
-    }
-
-    let a = CustomStruct { a: 1 };
-    let b = CustomStruct { a: 1 };
-    assert!(a.cmp_any(&b as &dyn AnyAttributeValue));
-
-    let a = CustomStruct { a: 1 };
-    let b = CustomStruct { a: 123 };
-    assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
-
-    let a = CustomStruct { a: 1 };
-    let b = "asdasd";
-    assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
-}

+ 0 - 61
packages/core/src.old/nodes/component.rs

@@ -1,61 +0,0 @@
-use crate::{
-    innerlude::{ComponentPtr, Element, Scope, ScopeId, ScopeState},
-    Component,
-};
-use std::cell::{Cell, RefCell};
-
-/// Virtual Components for custom user-defined components
-/// Only supports the functional syntax
-pub struct VComponent<'src> {
-    /// The key of the component to be used during keyed diffing.
-    pub key: Option<&'src str>,
-
-    /// The ID of the component.
-    /// Will not be assigned until after the component has been initialized.
-    pub scope: Cell<Option<ScopeId>>,
-
-    /// An indication if the component is static (can be memozied)
-    pub can_memoize: bool,
-
-    /// The function pointer to the component's render function.
-    pub user_fc: ComponentPtr,
-
-    /// The actual name of the component.
-    pub fn_name: &'static str,
-
-    /// The props of the component.
-    pub props: RefCell<Option<Box<dyn AnyProps + 'src>>>,
-}
-
-pub(crate) struct VComponentProps<P> {
-    pub render_fn: Component<P>,
-    pub memo: unsafe fn(&P, &P) -> bool,
-    pub props: P,
-}
-
-pub trait AnyProps {
-    fn as_ptr(&self) -> *const ();
-    fn render<'a>(&'a self, bump: &'a ScopeState) -> Element<'a>;
-    unsafe fn memoize(&self, other: &dyn AnyProps) -> bool;
-}
-
-impl<P> AnyProps for VComponentProps<P> {
-    fn as_ptr(&self) -> *const () {
-        &self.props as *const _ as *const ()
-    }
-
-    // Safety:
-    // this will downcast the other ptr as our swallowed type!
-    // you *must* make this check *before* calling this method
-    // if your functions are not the same, then you will downcast a pointer into a different type (UB)
-    unsafe fn memoize(&self, other: &dyn AnyProps) -> bool {
-        let real_other: &P = &*(other.as_ptr() as *const _ as *const P);
-        let real_us: &P = &*(self.as_ptr() as *const _ as *const P);
-        (self.memo)(real_us, real_other)
-    }
-
-    fn render<'a>(&'a self, scope: &'a ScopeState) -> Element<'a> {
-        let props = unsafe { std::mem::transmute::<&P, &P>(&self.props) };
-        (self.render_fn)(Scope { scope, props })
-    }
-}

+ 0 - 150
packages/core/src.old/nodes/element.rs

@@ -1,150 +0,0 @@
-use crate::{innerlude::AttributeValue, AnyEvent, ElementId, VNode};
-use bumpalo::boxed::Box as BumpBox;
-use std::{
-    cell::{Cell, RefCell},
-    fmt::{Debug, Formatter},
-};
-
-/// An element like a "div" with children, listeners, and attributes.
-pub struct VElement<'a> {
-    /// The [`ElementId`] of the VText.
-    pub id: Cell<Option<ElementId>>,
-
-    /// The key of the element to be used during keyed diffing.
-    pub key: Option<&'a str>,
-
-    /// The tag name of the element.
-    ///
-    /// IE "div"
-    pub tag: &'static str,
-
-    /// The namespace of the VElement
-    ///
-    /// IE "svg"
-    pub namespace: Option<&'static str>,
-
-    /// The parent of the Element (if any).
-    ///
-    /// Used when bubbling events
-    pub parent: Cell<Option<ElementId>>,
-
-    /// The Listeners of the VElement.
-    pub listeners: &'a [Listener<'a>],
-
-    /// The attributes of the VElement.
-    pub attributes: &'a [Attribute<'a>],
-
-    /// The children of the VElement.
-    pub children: &'a [VNode<'a>],
-}
-
-impl Debug for VElement<'_> {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("VElement")
-            .field("tag_name", &self.tag)
-            .field("namespace", &self.namespace)
-            .field("key", &self.key)
-            .field("id", &self.id)
-            .field("parent", &self.parent)
-            .field("listeners", &self.listeners.len())
-            .field("attributes", &self.attributes)
-            .field("children", &self.children)
-            .finish()
-    }
-}
-
-/// An attribute on a DOM node, such as `id="my-thing"` or
-/// `href="https://example.com"`.
-#[derive(Clone, Debug)]
-pub struct Attribute<'a> {
-    /// The name of the attribute.
-    pub name: &'static str,
-
-    /// The namespace of the attribute.
-    ///
-    /// Doesn't exist in the html spec.
-    /// Used in Dioxus to denote "style" tags and other attribute groups.
-    pub namespace: Option<&'static str>,
-
-    /// An indication of we should always try and set the attribute.
-    /// Used in controlled components to ensure changes are propagated.
-    pub volatile: bool,
-
-    /// The value of the attribute.
-    pub value: AttributeValue<'a>,
-}
-
-/// An event listener.
-/// IE onclick, onkeydown, etc
-pub struct Listener<'bump> {
-    /// The ID of the node that this listener is mounted to
-    /// Used to generate the event listener's ID on the DOM
-    pub mounted_node: Cell<ElementId>,
-
-    /// The type of event to listen for.
-    ///
-    /// IE "click" - whatever the renderer needs to attach the listener by name.
-    pub event: &'static str,
-
-    /// The actual callback that the user specified
-    pub(crate) callback: InternalHandler<'bump>,
-}
-
-pub type InternalHandler<'bump> = &'bump RefCell<Option<InternalListenerCallback<'bump>>>;
-type InternalListenerCallback<'bump> = BumpBox<'bump, dyn FnMut(AnyEvent) + 'bump>;
-type ExternalListenerCallback<'bump, T> = BumpBox<'bump, dyn FnMut(T) + 'bump>;
-
-/// The callback type generated by the `rsx!` macro when an `on` field is specified for components.
-///
-/// This makes it possible to pass `move |evt| {}` style closures into components as property fields.
-///
-///
-/// # Example
-///
-/// ```rust, ignore
-///
-/// rsx!{
-///     MyComponent { onclick: move |evt| log::info!("clicked"), }
-/// }
-///
-/// #[derive(Props)]
-/// struct MyProps<'a> {
-///     onclick: EventHandler<'a, MouseEvent>,
-/// }
-///
-/// fn MyComponent(cx: Scope<'a, MyProps<'a>>) -> Element {
-///     cx.render(rsx!{
-///         button {
-///             onclick: move |evt| cx.props.onclick.call(evt),
-///         }
-///     })
-/// }
-///
-/// ```
-pub struct EventHandler<'bump, T = ()> {
-    /// The (optional) callback that the user specified
-    /// Uses a `RefCell` to allow for interior mutability, and FnMut closures.
-    pub callback: RefCell<Option<ExternalListenerCallback<'bump, T>>>,
-}
-
-impl<'a, T> Default for EventHandler<'a, T> {
-    fn default() -> Self {
-        Self {
-            callback: RefCell::new(None),
-        }
-    }
-}
-
-impl<T> EventHandler<'_, T> {
-    /// Call this event handler with the appropriate event type
-    pub fn call(&self, event: T) {
-        if let Some(callback) = self.callback.borrow_mut().as_mut() {
-            callback(event);
-        }
-    }
-
-    /// Forcibly drop the internal handler callback, releasing memory
-    pub fn release(&self) {
-        self.callback.replace(None);
-    }
-}

+ 0 - 362
packages/core/src.old/nodes/factory.rs

@@ -1,362 +0,0 @@
-use crate::{innerlude::*, Attribute, Listener, VElement, VNode, VText};
-use bumpalo::{boxed::Box as BumpBox, Bump};
-use std::{
-    cell::{Cell, RefCell},
-    fmt::{Arguments, Debug},
-};
-
-/// This struct provides an ergonomic API to quickly build VNodes.
-///
-/// NodeFactory is used to build VNodes in the component's memory space.
-/// This struct adds metadata to the final VNode about listeners, attributes, and children
-#[derive(Copy, Clone)]
-pub struct NodeFactory<'a> {
-    pub(crate) scope: &'a ScopeState,
-    pub(crate) bump: &'a Bump,
-}
-
-impl<'a> NodeFactory<'a> {
-    /// Create a new [`NodeFactory`] from a [`Scope`] or [`ScopeState`]
-    pub fn new(scope: &'a ScopeState) -> NodeFactory<'a> {
-        NodeFactory {
-            scope,
-            bump: &scope.wip_frame().bump,
-        }
-    }
-
-    /// Get the custom allocator for this component
-    #[inline]
-    pub fn bump(&self) -> &'a bumpalo::Bump {
-        self.bump
-    }
-
-    /// Directly pass in text blocks without the need to use the format_args macro.
-    pub fn static_text(&self, text: &'static str) -> VNode<'a> {
-        VNode::Text(self.bump.alloc(VText {
-            id: Default::default(),
-            text,
-        }))
-    }
-
-    /// Parses a lazy text Arguments and returns a string and a flag indicating if the text is 'static
-    ///
-    /// Text that's static may be pointer compared, making it cheaper to diff
-    pub fn raw_text(&self, args: Arguments) -> (&'a str, bool) {
-        match args.as_str() {
-            Some(static_str) => (static_str, true),
-            None => {
-                use bumpalo::core_alloc::fmt::Write;
-                let mut str_buf = bumpalo::collections::String::new_in(self.bump);
-                str_buf.write_fmt(args).unwrap();
-                (str_buf.into_bump_str(), false)
-            }
-        }
-    }
-
-    /// Create some text that's allocated along with the other vnodes
-    ///
-    pub fn text(&self, args: Arguments) -> VNode<'a> {
-        let (text, _is_static) = self.raw_text(args);
-
-        VNode::Text(self.bump.alloc(VText {
-            text,
-            id: Default::default(),
-        }))
-    }
-
-    /// Create a new [`VNode::Element`] without the trait bound
-    ///
-    /// IE pass in "div" instead of `div`
-    pub fn raw_element(
-        &self,
-        tag_name: &'static str,
-        namespace: Option<&'static str>,
-        listeners: &'a [Listener<'a>],
-        attributes: &'a [Attribute<'a>],
-        children: &'a [VNode<'a>],
-        key: Option<Arguments>,
-    ) -> VNode<'a> {
-        let key = key.map(|f| self.raw_text(f).0);
-
-        let mut items = self.scope.items.borrow_mut();
-        for listener in listeners {
-            let long_listener = unsafe { std::mem::transmute(listener) };
-            items.listeners.push(long_listener);
-        }
-
-        VNode::Element(self.bump.alloc(VElement {
-            tag: tag_name,
-            key,
-            namespace,
-            listeners,
-            attributes,
-            children,
-            id: Default::default(),
-            parent: Default::default(),
-        }))
-    }
-
-    /// Create a new [`Attribute`]
-    pub fn attr(
-        &self,
-        name: &'static str,
-        val: impl IntoAttributeValue<'a>,
-        namespace: Option<&'static str>,
-        is_volatile: bool,
-    ) -> Attribute<'a> {
-        Attribute {
-            name,
-            namespace,
-            volatile: is_volatile,
-            value: val.into_value(self.bump),
-        }
-    }
-
-    /// Create a new [`Attribute`] using non-arguments
-    pub fn custom_attr(
-        &self,
-        name: &'static str,
-        value: AttributeValue<'a>,
-        namespace: Option<&'static str>,
-        is_volatile: bool,
-    ) -> Attribute<'a> {
-        Attribute {
-            name,
-            namespace,
-            volatile: is_volatile,
-            value,
-        }
-    }
-
-    /// Create a new [`VNode::Component`]
-    pub fn component<P>(
-        &self,
-        component: fn(Scope<'a, P>) -> Element,
-        props: P,
-        key: Option<Arguments>,
-        fn_name: &'static str,
-    ) -> VNode<'a>
-    where
-        P: Properties + 'a,
-    {
-        let vcomp = self.bump.alloc(VComponent {
-            key: key.map(|f| self.raw_text(f).0),
-            scope: Default::default(),
-            can_memoize: P::IS_STATIC,
-            user_fc: component as ComponentPtr,
-            fn_name,
-            props: RefCell::new(Some(Box::new(VComponentProps {
-                props,
-                memo: P::memoize, // smuggle the memoization function across borders
-
-                // i'm sorry but I just need to bludgeon the lifetimes into place here
-                // this is safe because we're managing all lifetimes to originate from previous calls
-                // the intricacies of Rust's lifetime system make it difficult to properly express
-                // the transformation from this specific lifetime to the for<'a> lifetime
-                render_fn: unsafe { std::mem::transmute(component) },
-            }))),
-        });
-
-        if !P::IS_STATIC {
-            let vcomp = &*vcomp;
-            let vcomp = unsafe { std::mem::transmute(vcomp) };
-            self.scope.items.borrow_mut().borrowed_props.push(vcomp);
-        }
-
-        VNode::Component(vcomp)
-    }
-
-    /// Create a new [`Listener`]
-    pub fn listener(self, event: &'static str, callback: InternalHandler<'a>) -> Listener<'a> {
-        Listener {
-            event,
-            mounted_node: Cell::new(ElementId(0)),
-            callback,
-        }
-    }
-
-    /// Create a new [`VNode::Fragment`] from a root of the rsx! call
-    pub fn fragment_root<'b, 'c>(
-        self,
-        node_iter: impl IntoIterator<Item = impl IntoVNode<'a> + 'c> + 'b,
-    ) -> VNode<'a> {
-        let mut nodes = bumpalo::collections::Vec::new_in(self.bump);
-
-        for node in node_iter {
-            nodes.push(node.into_vnode(self));
-        }
-
-        VNode::Fragment(self.bump.alloc(VFragment {
-            children: nodes.into_bump_slice(),
-            placeholder: Default::default(),
-            key: None,
-        }))
-    }
-
-    /// Create a new [`VNode::Fragment`] from any iterator
-    pub fn fragment_from_iter<'c, I, J>(
-        self,
-        node_iter: impl IntoVNode<'a, I, J> + 'c,
-    ) -> VNode<'a> {
-        node_iter.into_vnode(self)
-    }
-
-    /// Create a new [`VNode`] from any iterator of children
-    pub fn create_children(
-        self,
-        node_iter: impl IntoIterator<Item = impl IntoVNode<'a>>,
-    ) -> Element<'a> {
-        let mut nodes = bumpalo::collections::Vec::new_in(self.bump);
-
-        for node in node_iter {
-            nodes.push(node.into_vnode(self));
-        }
-
-        let children = nodes.into_bump_slice();
-
-        Some(VNode::Fragment(self.bump.alloc(VFragment {
-            children,
-            key: None,
-            placeholder: Default::default(),
-        })))
-    }
-
-    /// Create a new [`EventHandler`] from an [`FnMut`]
-    pub fn event_handler<T>(self, f: impl FnMut(T) + 'a) -> EventHandler<'a, T> {
-        let handler: &mut dyn FnMut(T) = self.bump.alloc(f);
-        let caller = unsafe { BumpBox::from_raw(handler as *mut dyn FnMut(T)) };
-        let callback = RefCell::new(Some(caller));
-        EventHandler { callback }
-    }
-
-    /// Create a refrence to a template
-    pub fn template_ref(
-        &self,
-        template: Template<'static>,
-        nodes: &'a [VNode<'a>],
-        attributes: &'a [Attribute<'a>],
-        listeners: &'a [Listener<'a>],
-        key: Option<Arguments>,
-    ) -> VNode<'a> {
-        VNode::Template(
-            self.bump.alloc(VTemplate {
-                key: None,
-                node_id: Cell::new(ElementId(0)),
-                template,
-                dynamic_nodes: self.bump.alloc([]),
-                dynamic_attrs: self.bump.alloc([]),
-                listeners,
-                root_ids:
-                    bumpalo::vec![in self.bump; Cell::new(ElementId(0)); template.roots.len()]
-                        .into_bump_slice(),
-            }),
-        )
-    }
-}
-
-impl Debug for NodeFactory<'_> {
-    fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        Ok(())
-    }
-}
-
-/// Trait implementations for use in the rsx! and html! macros.
-///
-/// ## Details
-///
-/// This section provides convenience methods and trait implementations for converting common structs into a format accepted
-/// by the macros.
-///
-/// All dynamic content in the macros must flow in through `fragment_from_iter`. Everything else must be statically layed out.
-/// We pipe basically everything through `fragment_from_iter`, so we expect a very specific type:
-/// ```rust, ignore
-/// impl IntoIterator<Item = impl IntoVNode<'a>>
-/// ```
-///
-/// As such, all node creation must go through the factory, which is only available in the component context.
-/// These strict requirements make it possible to manage lifetimes and state.
-pub trait IntoVNode<'a, I = (), J = ()> {
-    /// Convert this into a [`VNode`], using the [`NodeFactory`] as a source of allocation
-    fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>;
-}
-
-// TODO: do we even need this? It almost seems better not to
-// // For the case where a rendered VNode is passed into the rsx! macro through curly braces
-impl<'a> IntoVNode<'a> for VNode<'a> {
-    fn into_vnode(self, _: NodeFactory<'a>) -> VNode<'a> {
-        self
-    }
-}
-
-impl<'a, 'b> IntoVNode<'a> for LazyNodes<'a, '_> {
-    fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
-        self.call(cx)
-    }
-}
-
-impl<'b> IntoVNode<'_> for &'b str {
-    fn into_vnode(self, cx: NodeFactory) -> VNode {
-        cx.text(format_args!("{}", self))
-    }
-}
-
-impl IntoVNode<'_> for String {
-    fn into_vnode(self, cx: NodeFactory) -> VNode {
-        cx.text(format_args!("{}", self))
-    }
-}
-
-impl IntoVNode<'_> for Arguments<'_> {
-    fn into_vnode(self, cx: NodeFactory) -> VNode {
-        cx.text(self)
-    }
-}
-
-impl<'a> IntoVNode<'a> for &VNode<'a> {
-    fn into_vnode(self, _cx: NodeFactory<'a>) -> VNode<'a> {
-        // borrowed nodes are strange
-        self.decouple()
-    }
-}
-
-// Note that we're using the E as a generic but this is never crafted anyways.
-pub struct FromNodeIterator;
-impl<'a, T, I, E> IntoVNode<'a, FromNodeIterator, E> for T
-where
-    T: IntoIterator<Item = I>,
-    I: IntoVNode<'a, E>,
-{
-    fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
-        let mut nodes = bumpalo::collections::Vec::new_in(cx.bump);
-
-        for node in self {
-            nodes.push(node.into_vnode(cx));
-        }
-
-        let children = nodes.into_bump_slice();
-
-        if cfg!(debug_assertions) && children.len() > 1 && children.last().unwrap().key().is_none()
-        {
-            // let bt = backtrace::Backtrace::new();
-            let bt = "no backtrace available";
-
-            // todo: make the backtrace prettier or remove it altogether
-            log::error!(
-                r#"
-                Warning: Each child in an array or iterator should have a unique "key" prop.
-                Not providing a key will lead to poor performance with lists.
-                See docs.rs/dioxus for more information.
-                -------------
-                {:?}
-                "#,
-                bt
-            );
-        }
-
-        VNode::Fragment(cx.bump.alloc(VFragment {
-            children,
-            placeholder: Default::default(),
-            key: None,
-        }))
-    }
-}

+ 0 - 16
packages/core/src.old/nodes/fragment.rs

@@ -1,16 +0,0 @@
-use crate::{ElementId, VNode};
-use std::cell::Cell;
-
-/// A list of VNodes with no single root.
-pub struct VFragment<'src> {
-    /// The key of the fragment to be used during keyed diffing.
-    pub key: Option<&'src str>,
-
-    /// The [`ElementId`] of the placeholder if it exists
-    pub placeholder: Cell<Option<ElementId>>,
-
-    /// Fragments can never have zero children. Enforced by NodeFactory.
-    ///
-    /// You *can* make a fragment with no children, but it's not a valid fragment and your VDom will panic.
-    pub children: &'src [VNode<'src>],
-}

+ 0 - 207
packages/core/src.old/nodes/mod.old.rs

@@ -1,207 +0,0 @@
-//! Virtual Node Support
-//!
-//! VNodes represent lazily-constructed VDom trees that support diffing and event handlers. These VNodes should be *very*
-//! cheap and *very* fast to construct - building a full tree should be quick.
-
-use std::fmt::{Debug, Formatter};
-
-mod arbitrary_value;
-mod component;
-mod element;
-mod factory;
-mod fragment;
-mod placeholder;
-mod suspense;
-mod template;
-mod text;
-
-pub use arbitrary_value::*;
-pub use component::*;
-pub use element::*;
-pub use factory::*;
-pub use fragment::*;
-pub use suspense::*;
-pub use template::*;
-pub use text::*;
-
-use self::placeholder::VPlaceholder;
-
-/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
-///
-/// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of:
-///
-/// - the `rsx!` macro
-/// - the [`NodeFactory`] API
-pub enum VNode<'src> {
-    /// Text VNodes are simply bump-allocated (or static) string slices
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// let mut vdom = VirtualDom::new();
-    /// let node = vdom.render_vnode(rsx!( "hello" ));
-    ///
-    /// if let VNode::Text(vtext) = node {
-    ///     assert_eq!(vtext.text, "hello");
-    ///     assert_eq!(vtext.dom_id.get(), None);
-    ///     assert_eq!(vtext.is_static, true);
-    /// }
-    /// ```
-    Text(&'src VText<'src>),
-
-    /// Element VNodes are VNodes that may contain attributes, listeners, a key, a tag, and children.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// let mut vdom = VirtualDom::new();
-    ///
-    /// let node = vdom.render_vnode(rsx!{
-    ///     div {
-    ///         key: "a",
-    ///         onclick: |e| log::info!("clicked"),
-    ///         hidden: "true",
-    ///         style: { background_color: "red" },
-    ///         "hello"
-    ///     }
-    /// });
-    ///
-    /// if let VNode::Element(velement) = node {
-    ///     assert_eq!(velement.tag_name, "div");
-    ///     assert_eq!(velement.namespace, None);
-    ///     assert_eq!(velement.key, Some("a"));
-    /// }
-    /// ```
-    Element(&'src VElement<'src>),
-
-    /// Fragment nodes may contain many VNodes without a single root.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// rsx!{
-    ///     a {}
-    ///     link {}
-    ///     style {}
-    ///     "asd"
-    ///     Example {}
-    /// }
-    /// ```
-    Fragment(&'src VFragment<'src>),
-
-    /// Component nodes represent a mounted component with props, children, and a key.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// fn Example(cx: Scope) -> Element {
-    ///     ...
-    /// }
-    ///
-    /// let mut vdom = VirtualDom::new();
-    ///
-    /// let node = vdom.render_vnode(rsx!( Example {} ));
-    ///
-    /// if let VNode::Component(vcomp) = node {
-    ///     assert_eq!(vcomp.user_fc, Example as *const ());
-    /// }
-    /// ```
-    Component(&'src VComponent<'src>),
-
-    /// Templetes ase generated by the rsx macro to eleminate diffing static nodes.
-    ///
-    ///
-    ///
-    ///
-    ///
-    ///
-    Template(&'src VTemplate<'src>),
-}
-
-/// An Element's unique identifier.
-///
-/// `ElementId` is a `usize` that is unique across the entire VirtualDOM - but not unique across time. If a component is
-/// unmounted, then the `ElementId` will be reused for a new component.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serialize", serde(transparent))]
-pub struct ElementId(pub usize);
-
-impl<'src> VNode<'src> {
-    /// Get the VNode's "key" used in the keyed diffing algorithm.
-    pub fn key(&self) -> Option<&'src str> {
-        match &self {
-            VNode::Element(el) => el.key,
-            VNode::Component(c) => c.key,
-            VNode::Fragment(f) => f.key,
-            VNode::Template(t) => t.key,
-            VNode::Text(_t) => None,
-        }
-    }
-
-    /// Get the ElementID of the mounted VNode.
-    ///
-    /// Panics if the mounted ID is None or if the VNode is not represented by a single Element.
-    pub fn mounted_id(&self) -> ElementId {
-        self.try_mounted_id().unwrap()
-    }
-
-    /// Try to get the ElementID of the mounted VNode.
-    ///
-    /// Returns None if the VNode is not mounted, or if the VNode cannot be presented by a mounted ID (Fragment/Component)
-    pub fn try_mounted_id(&self) -> Option<ElementId> {
-        match &self {
-            VNode::Text(el) => el.id.get(),
-            VNode::Element(el) => el.id.get(),
-            VNode::Fragment(_) => None,
-            VNode::Component(_) => None,
-            VNode::Template(_) => None,
-        }
-    }
-
-    // Create an "owned" version of the vnode.
-    pub(crate) fn decouple(&self) -> VNode<'src> {
-        match *self {
-            VNode::Text(t) => VNode::Text(t),
-            VNode::Element(e) => VNode::Element(e),
-            VNode::Component(c) => VNode::Component(c),
-            VNode::Fragment(f) => VNode::Fragment(f),
-            VNode::Template(t) => VNode::Template(t),
-        }
-    }
-}
-
-impl Debug for VNode<'_> {
-    fn fmt(&self, s: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
-        match &self {
-            VNode::Element(el) => s
-                .debug_struct("VNode::Element")
-                .field("name", &el.tag)
-                .field("key", &el.key)
-                .field("attrs", &el.attributes)
-                .field("children", &el.children)
-                .field("id", &el.id)
-                .finish(),
-            VNode::Text(t) => s
-                .debug_struct("VNode::Text")
-                .field("text", &t.text)
-                .field("id", &t.id)
-                .finish(),
-            VNode::Fragment(frag) => s
-                .debug_struct("VNode::Fragment")
-                .field("children", &frag.children)
-                .finish(),
-            VNode::Component(comp) => s
-                .debug_struct("VNode::Component")
-                .field("name", &comp.fn_name)
-                .field("fnptr", &comp.user_fc)
-                .field("key", &comp.key)
-                .field("scope", &comp.scope)
-                .finish(),
-            VNode::Template(temp) => s
-                .debug_struct("VNode::Templates")
-                .field("template_id", &temp.template.id)
-                .finish(),
-        }
-    }
-}

+ 0 - 88
packages/core/src.old/nodes/mod.rs

@@ -1,88 +0,0 @@
-use std::{cell::Cell, num::NonZeroUsize};
-
-/// A reference to a template along with any context needed to hydrate it
-pub struct VTemplate<'a> {
-    // The ID assigned for the root of this template
-    pub node_id: Cell<ElementId>,
-
-    pub template: &'static Template,
-
-    /// All the dynamic nodes for a template
-    pub dynamic_nodes: &'a [DynamicNode<'a>],
-
-    pub dynamic_attrs: &'a [AttributeLocation<'a>],
-}
-
-#[derive(Debug, Clone, Copy)]
-pub struct Template {
-    pub id: &'static str,
-
-    pub root: TemplateNode<'static>,
-
-    // todo: locations of dynamic nodes
-    pub node_pathways: &'static [&'static [u8]],
-
-    // todo: locations of dynamic nodes
-    pub attr_pathways: &'static [&'static [u8]],
-}
-
-/// A weird-ish variant of VNodes with way more limited types
-#[derive(Debug, Clone, Copy)]
-pub enum TemplateNode<'a> {
-    /// A simple element
-    Element {
-        tag: &'a str,
-        namespace: Option<&'a str>,
-        attrs: &'a [TemplateAttribute<'a>],
-        children: &'a [TemplateNode<'a>],
-    },
-    Text(&'a str),
-    Dynamic(usize),
-    DynamicText(usize),
-}
-
-pub enum DynamicNode<'a> {
-    // Anything declared in component form
-    // IE in caps or with underscores
-    Component {
-        name: &'static str,
-    },
-
-    // Comes in with string interpolation or from format_args, include_str, etc
-    Text {
-        id: Cell<ElementId>,
-        value: &'static str,
-    },
-
-    // Anything that's coming in as an iterator
-    Fragment {
-        children: &'a [VTemplate<'a>],
-    },
-}
-
-#[derive(Debug)]
-pub struct TemplateAttribute<'a> {
-    pub name: &'static str,
-    pub value: &'a str,
-    pub namespace: Option<&'static str>,
-    pub volatile: bool,
-}
-
-pub struct AttributeLocation<'a> {
-    pub mounted_element: Cell<ElementId>,
-    pub attrs: &'a [Attribute<'a>],
-}
-
-#[derive(Debug)]
-pub struct Attribute<'a> {
-    pub name: &'static str,
-    pub value: &'a str,
-    pub namespace: Option<&'static str>,
-}
-
-#[test]
-fn what_are_the_sizes() {
-    dbg!(std::mem::size_of::<VTemplate>());
-    dbg!(std::mem::size_of::<Template>());
-    dbg!(std::mem::size_of::<TemplateNode>());
-}

+ 0 - 8
packages/core/src.old/nodes/placeholder.rs

@@ -1,8 +0,0 @@
-use crate::ElementId;
-use std::cell::Cell;
-
-/// A placeholder node
-pub struct VPlaceholder {
-    pub id: Cell<Option<ElementId>>,
-    pub dynamic_index: Option<usize>,
-}

+ 0 - 0
packages/core/src.old/nodes/suspense.rs


+ 0 - 78
packages/core/src.old/nodes/template.rs

@@ -1,78 +0,0 @@
-use std::{cell::Cell, hash::Hash};
-
-use crate::{Attribute, ElementId, Listener, VNode};
-
-/// A reference to a template along with any context needed to hydrate it
-pub struct VTemplate<'a> {
-    pub key: Option<&'a str>,
-
-    // The ID assigned for all nodes in this template
-    pub node_id: Cell<ElementId>,
-
-    // All the IDs for the roots of this template
-    // Non-assigned IDs are set to 0
-    pub root_ids: &'a [Cell<ElementId>],
-
-    pub template: Template<'static>,
-
-    /// All the non-root dynamic nodes
-    pub dynamic_nodes: &'a [NodeLocation<'a>],
-
-    pub dynamic_attrs: &'a [AttributeLocation<'a>],
-
-    pub listeners: &'a [Listener<'a>],
-}
-
-/// A template that is created at compile time
-#[derive(Clone, Copy)]
-pub struct Template<'a> {
-    /// name, line, col, or some sort of identifier
-    pub id: &'static str,
-
-    /// All the roots of the template. ie rsx! { div {} div{} } would have two roots
-    pub roots: &'a [TemplateNode<'a>],
-}
-
-impl<'a> Eq for Template<'a> {}
-impl<'a> PartialEq for Template<'a> {
-    fn eq(&self, other: &Self) -> bool {
-        self.id == other.id
-    }
-}
-impl<'a> Hash for Template<'a> {
-    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
-        self.id.hash(state);
-    }
-}
-
-/// A weird-ish variant of VNodes with way more limited types
-pub enum TemplateNode<'a> {
-    /// A simple element
-    Element {
-        tag: &'static str,
-        namespace: Option<&'static str>,
-        attrs: &'a [TemplateAttribute<'a>],
-        children: &'a [TemplateNode<'a>],
-    },
-    Text(&'static str),
-    Dynamic(usize),
-}
-
-pub struct TemplateAttribute<'a> {
-    pub name: &'static str,
-    pub value: &'a str,
-    pub namespace: Option<&'static str>,
-    pub volatile: bool,
-}
-
-pub struct AttributeLocation<'a> {
-    pub pathway: &'static [u8],
-    pub mounted_element: Cell<ElementId>,
-    pub attrs: &'a [Attribute<'a>],
-    pub listeners: &'a [Listener<'a>],
-}
-
-pub struct NodeLocation<'a> {
-    pub pathway: &'static [u8],
-    pub node: VNode<'a>,
-}

+ 0 - 11
packages/core/src.old/nodes/text.rs

@@ -1,11 +0,0 @@
-use crate::ElementId;
-use std::cell::Cell;
-
-/// A bump-allocated string slice and metadata.
-pub struct VText<'src> {
-    /// The [`ElementId`] of the VText.
-    pub id: Cell<Option<ElementId>>,
-
-    /// The text of the VText.
-    pub text: &'src str,
-}

+ 0 - 170
packages/core/src.old/properties.rs

@@ -1,170 +0,0 @@
-use crate::innerlude::*;
-
-pub struct FragmentProps<'a>(Element<'a>);
-pub struct FragmentBuilder<'a, const BUILT: bool>(Element<'a>);
-impl<'a> FragmentBuilder<'a, false> {
-    pub fn children(self, children: Element<'a>) -> FragmentBuilder<'a, true> {
-        FragmentBuilder(children)
-    }
-}
-impl<'a, const A: bool> FragmentBuilder<'a, A> {
-    pub fn build(self) -> FragmentProps<'a> {
-        FragmentProps(self.0)
-    }
-}
-
-/// Access the children elements passed into the component
-///
-/// This enables patterns where a component is passed children from its parent.
-///
-/// ## Details
-///
-/// Unlike React, Dioxus allows *only* lists of children to be passed from parent to child - not arbitrary functions
-/// or classes. If you want to generate nodes instead of accepting them as a list, consider declaring a closure
-/// on the props that takes Context.
-///
-/// If a parent passes children into a component, the child will always re-render when the parent re-renders. In other
-/// words, a component cannot be automatically memoized if it borrows nodes from its parent, even if the component's
-/// props are valid for the static lifetime.
-///
-/// ## Example
-///
-/// ```rust, ignore
-/// fn App(cx: Scope) -> Element {
-///     cx.render(rsx!{
-///         CustomCard {
-///             h1 {}
-///             p {}
-///         }
-///     })
-/// }
-///
-/// #[derive(PartialEq, Props)]
-/// struct CardProps {
-///     children: Element
-/// }
-///
-/// fn CustomCard(cx: Scope<CardProps>) -> Element {
-///     cx.render(rsx!{
-///         div {
-///             h1 {"Title card"}
-///             {cx.props.children}
-///         }
-///     })
-/// }
-/// ```
-impl<'a> Properties for FragmentProps<'a> {
-    type Builder = FragmentBuilder<'a, false>;
-    const IS_STATIC: bool = false;
-    fn builder() -> Self::Builder {
-        FragmentBuilder(None)
-    }
-    unsafe fn memoize(&self, _other: &Self) -> bool {
-        false
-    }
-}
-
-// /// Create inline fragments using Component syntax.
-// ///
-// /// ## Details
-// ///
-// /// Fragments capture a series of children without rendering extra nodes.
-// ///
-// /// Creating fragments explicitly with the Fragment component is particularly useful when rendering lists or tables and
-// /// a key is needed to identify each item.
-// ///
-// /// ## Example
-// ///
-// /// ```rust, ignore
-// /// rsx!{
-// ///     Fragment { key: "abc" }
-// /// }
-// /// ```
-// ///
-// /// ## Usage
-// ///
-// /// Fragments are incredibly useful when necessary, but *do* add cost in the diffing phase.
-// /// Try to avoid highly nested fragments if you can. Unlike React, there is no protection against infinitely nested fragments.
-// ///
-// /// This function defines a dedicated `Fragment` component that can be used to create inline fragments in the RSX macro.
-// ///
-// /// You want to use this free-function when your fragment needs a key and simply returning multiple nodes from rsx! won't cut it.
-// #[allow(non_upper_case_globals, non_snake_case)]
-// pub fn Fragment<'a>(cx: Scope<'a, FragmentProps<'a>>) -> Element {
-//     let i = cx.props.0.as_ref().map(|f| f.decouple());
-//     cx.render(LazyNodes::new(|f| f.fragment_from_iter(i)))
-// }
-
-/// Every "Props" used for a component must implement the `Properties` trait. This trait gives some hints to Dioxus
-/// on how to memoize the props and some additional optimizations that can be made. We strongly encourage using the
-/// derive macro to implement the `Properties` trait automatically as guarantee that your memoization strategy is safe.
-///
-/// If your props are 'static, then Dioxus will require that they also be PartialEq for the derived memoize strategy. However,
-/// if your props borrow data, then the memoization strategy will simply default to "false" and the PartialEq will be ignored.
-/// This tends to be useful when props borrow something that simply cannot be compared (IE a reference to a closure);
-///
-/// By default, the memoization strategy is very conservative, but can be tuned to be more aggressive manually. However,
-/// this is only safe if the props are 'static - otherwise you might borrow references after-free.
-///
-/// We strongly suggest that any changes to memoization be done at the "PartialEq" level for 'static props. Additionally,
-/// we advise the use of smart pointers in cases where memoization is important.
-///
-/// ## Example
-///
-/// For props that are 'static:
-/// ```rust, ignore
-/// #[derive(Props, PartialEq)]
-/// struct MyProps {
-///     data: String
-/// }
-/// ```
-///
-/// For props that borrow:
-///
-/// ```rust, ignore
-/// #[derive(Props)]
-/// struct MyProps<'a >{
-///     data: &'a str
-/// }
-/// ```
-pub trait Properties: Sized {
-    /// The type of the builder for this component.
-    /// Used to create "in-progress" versions of the props.
-    type Builder;
-
-    /// An indication if these props are can be memoized automatically.
-    const IS_STATIC: bool;
-
-    /// Create a builder for this component.
-    fn builder() -> Self::Builder;
-
-    /// Memoization can only happen if the props are valid for the 'static lifetime
-    ///
-    /// # Safety
-    /// The user must know if their props are static, but if they make a mistake, UB happens
-    /// Therefore it's unsafe to memoize.
-    unsafe fn memoize(&self, other: &Self) -> bool;
-}
-
-impl Properties for () {
-    type Builder = EmptyBuilder;
-    const IS_STATIC: bool = true;
-    fn builder() -> Self::Builder {
-        EmptyBuilder {}
-    }
-    unsafe fn memoize(&self, _other: &Self) -> bool {
-        true
-    }
-}
-// We allow components to use the () generic parameter if they have no props. This impl enables the "build" method
-// that the macros use to anonymously complete prop construction.
-pub struct EmptyBuilder;
-impl EmptyBuilder {
-    pub fn build(self) {}
-}
-
-/// This utility function launches the builder method so rsx! and html! macros can use the typed-builder pattern
-/// to initialize a component's props.
-pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Scope<'a, T>) -> Element) -> T::Builder {
-    T::builder()
-}

+ 0 - 1008
packages/core/src.old/scopes.rs

@@ -1,1008 +0,0 @@
-use crate::{innerlude::*, unsafe_utils::extend_vnode};
-use bumpalo::Bump;
-use futures_channel::mpsc::UnboundedSender;
-use fxhash::FxHashMap;
-use slab::Slab;
-use std::{
-    any::{Any, TypeId},
-    borrow::Borrow,
-    cell::{Cell, RefCell},
-    collections::{HashMap, HashSet},
-    future::Future,
-    pin::Pin,
-    rc::Rc,
-    sync::Arc,
-};
-
-/// for traceability, we use the raw fn pointer to identify the function
-/// we also get the component name, but that's not necessarily unique in the app
-pub(crate) type ComponentPtr = *mut std::os::raw::c_void;
-
-pub(crate) struct Heuristic {
-    hook_arena_size: usize,
-    node_arena_size: usize,
-}
-
-// a slab-like arena with stable references even when new scopes are allocated
-// uses a bump arena as a backing
-//
-// has an internal heuristics engine to pre-allocate arenas to the right size
-pub(crate) struct ScopeArena {
-    pub scope_gen: Cell<usize>,
-    pub bump: Bump,
-    pub scopes: RefCell<FxHashMap<ScopeId, *mut ScopeState>>,
-    pub heuristics: RefCell<FxHashMap<ComponentPtr, Heuristic>>,
-    pub free_scopes: RefCell<Vec<*mut ScopeState>>,
-    pub nodes: RefCell<Slab<*const VNode<'static>>>,
-    pub tasks: Rc<TaskQueue>,
-    pub template_cache: RefCell<HashSet<Template<'static>>>,
-}
-
-impl ScopeArena {
-    pub(crate) fn new(sender: UnboundedSender<SchedulerMsg>) -> Self {
-        let bump = Bump::new();
-
-        // allocate a container for the root element
-        // this will *never* show up in the diffing process
-        // todo: figure out why this is necessary. i forgot. whoops.
-        let el = bump.alloc(VElement {
-            tag: "root",
-            namespace: None,
-            key: None,
-            id: Cell::new(Some(ElementId(0))),
-            parent: Default::default(),
-            listeners: &[],
-            attributes: &[],
-            children: &[],
-        });
-
-        let node = bump.alloc(VNode::Element(el));
-        let mut nodes = Slab::new();
-        let root_id = nodes.insert(unsafe { std::mem::transmute(node as *const _) });
-
-        debug_assert_eq!(root_id, 0);
-
-        Self {
-            scope_gen: Cell::new(0),
-            bump,
-            scopes: RefCell::new(FxHashMap::default()),
-            heuristics: RefCell::new(FxHashMap::default()),
-            free_scopes: RefCell::new(Vec::new()),
-            nodes: RefCell::new(nodes),
-            tasks: Rc::new(TaskQueue {
-                tasks: RefCell::new(FxHashMap::default()),
-                task_map: RefCell::new(FxHashMap::default()),
-                gen: Cell::new(0),
-                sender,
-            }),
-            template_cache: RefCell::new(HashSet::new()),
-        }
-    }
-
-    /// Safety:
-    /// - Obtaining a mutable reference to any Scope is unsafe
-    /// - Scopes use interior mutability when sharing data into components
-    pub(crate) fn get_scope(&self, id: ScopeId) -> Option<&ScopeState> {
-        unsafe { self.scopes.borrow().get(&id).map(|f| &**f) }
-    }
-
-    pub(crate) fn get_scope_raw(&self, id: ScopeId) -> Option<*mut ScopeState> {
-        self.scopes.borrow().get(&id).copied()
-    }
-
-    pub(crate) fn new_with_key(
-        &self,
-        fc_ptr: ComponentPtr,
-        vcomp: Box<dyn AnyProps>,
-        parent_scope: Option<ScopeId>,
-        container: ElementId,
-        subtree: u32,
-    ) -> ScopeId {
-        // Increment the ScopeId system. ScopeIDs are never reused
-        let new_scope_id = ScopeId(self.scope_gen.get());
-        self.scope_gen.set(self.scope_gen.get() + 1);
-
-        // Get the height of the scope
-        let height = parent_scope
-            .and_then(|id| self.get_scope(id).map(|scope| scope.height + 1))
-            .unwrap_or_default();
-
-        let parent_scope = parent_scope.and_then(|f| self.get_scope_raw(f));
-
-        /*
-        This scopearena aggressively reuses old scopes when possible.
-        We try to minimize the new allocations for props/arenas.
-
-        However, this will probably lead to some sort of fragmentation.
-        I'm not exactly sure how to improve this today.
-        */
-        if let Some(old_scope) = self.free_scopes.borrow_mut().pop() {
-            // reuse the old scope
-            let scope = unsafe { &mut *old_scope };
-
-            scope.container = container;
-            scope.our_arena_idx = new_scope_id;
-            scope.parent_scope = parent_scope;
-            scope.height = height;
-            scope.fnptr = fc_ptr;
-            scope.props.get_mut().replace(vcomp);
-            scope.subtree.set(subtree);
-            scope.frames[0].reset();
-            scope.frames[1].reset();
-            scope.shared_contexts.get_mut().clear();
-            scope.items.get_mut().listeners.clear();
-            scope.items.get_mut().borrowed_props.clear();
-            scope.hook_idx.set(0);
-            scope.hook_vals.get_mut().clear();
-
-            let any_item = self.scopes.borrow_mut().insert(new_scope_id, scope);
-            debug_assert!(any_item.is_none());
-        } else {
-            // else create a new scope
-            let (node_capacity, hook_capacity) = self
-                .heuristics
-                .borrow()
-                .get(&fc_ptr)
-                .map(|h| (h.node_arena_size, h.hook_arena_size))
-                .unwrap_or_default();
-
-            self.scopes.borrow_mut().insert(
-                new_scope_id,
-                self.bump.alloc(ScopeState {
-                    container,
-                    our_arena_idx: new_scope_id,
-                    parent_scope,
-                    height,
-                    fnptr: fc_ptr,
-                    props: RefCell::new(Some(vcomp)),
-                    frames: [BumpFrame::new(node_capacity), BumpFrame::new(node_capacity)],
-
-                    // todo: subtrees
-                    subtree: Cell::new(0),
-                    is_subtree_root: Cell::default(),
-
-                    generation: 0.into(),
-
-                    tasks: self.tasks.clone(),
-                    shared_contexts: RefCell::default(),
-
-                    items: RefCell::new(SelfReferentialItems {
-                        listeners: Vec::default(),
-                        borrowed_props: Vec::default(),
-                    }),
-
-                    hook_arena: Bump::new(),
-                    hook_vals: RefCell::new(Vec::with_capacity(hook_capacity)),
-                    hook_idx: Cell::default(),
-                }),
-            );
-        }
-
-        new_scope_id
-    }
-
-    // Removes a scope and its descendents from the arena
-    pub fn try_remove(&self, id: ScopeId) {
-        self.ensure_drop_safety(id);
-
-        // Dispose of any ongoing tasks
-        let mut tasks = self.tasks.tasks.borrow_mut();
-        let mut task_map = self.tasks.task_map.borrow_mut();
-        if let Some(cur_tasks) = task_map.remove(&id) {
-            for task in cur_tasks {
-                tasks.remove(&task);
-            }
-        }
-
-        // Safety:
-        // - ensure_drop_safety ensures that no references to this scope are in use
-        // - this raw pointer is removed from the map
-        let scope = unsafe { &mut *self.scopes.borrow_mut().remove(&id).unwrap() };
-        scope.reset();
-
-        self.free_scopes.borrow_mut().push(scope);
-    }
-
-    pub fn reserve_node<'a>(&self, node: &'a VNode<'a>) -> ElementId {
-        let mut els = self.nodes.borrow_mut();
-        let entry = els.vacant_entry();
-        let key = entry.key();
-        let id = ElementId(key);
-        let node = unsafe { extend_vnode(node) };
-        entry.insert(node as *const _);
-        id
-    }
-
-    pub fn update_node<'a>(&self, node: &'a VNode<'a>, id: ElementId) {
-        let node = unsafe { extend_vnode(node) };
-        *self.nodes.borrow_mut().get_mut(id.0).unwrap() = node;
-    }
-
-    pub fn collect_garbage(&self, id: ElementId) {
-        self.nodes.borrow_mut().remove(id.0);
-    }
-
-    /// This method cleans up any references to data held within our hook list. This prevents mutable aliasing from
-    /// causing UB in our tree.
-    ///
-    /// This works by cleaning up our references from the bottom of the tree to the top. The directed graph of components
-    /// essentially forms a dependency tree that we can traverse from the bottom to the top. As we traverse, we remove
-    /// any possible references to the data in the hook list.
-    ///
-    /// References to hook data can only be stored in listeners and component props. During diffing, we make sure to log
-    /// all listeners and borrowed props so we can clear them here.
-    ///
-    /// This also makes sure that drop order is consistent and predictable. All resources that rely on being dropped will
-    /// be dropped.
-    pub(crate) fn ensure_drop_safety(&self, scope_id: ScopeId) {
-        if let Some(scope) = self.get_scope(scope_id) {
-            let mut items = scope.items.borrow_mut();
-
-            // make sure we drop all borrowed props manually to guarantee that their drop implementation is called before we
-            // run the hooks (which hold an &mut Reference)
-            // recursively call ensure_drop_safety on all children
-            items.borrowed_props.drain(..).for_each(|comp| {
-                if let Some(scope_id) = comp.scope.get() {
-                    self.ensure_drop_safety(scope_id);
-                }
-                drop(comp.props.take());
-            });
-
-            // Now that all the references are gone, we can safely drop our own references in our listeners.
-            items
-                .listeners
-                .drain(..)
-                .for_each(|listener| drop(listener.callback.borrow_mut().take()));
-        }
-    }
-
-    pub(crate) fn run_scope(&self, id: ScopeId) {
-        // Cycle to the next frame and then reset it
-        // This breaks any latent references, invalidating every pointer referencing into it.
-        // Remove all the outdated listeners
-        self.ensure_drop_safety(id);
-
-        // todo: we *know* that this is aliased by the contents of the scope itself
-        let scope = unsafe { &mut *self.get_scope_raw(id).expect("could not find scope") };
-
-        log::trace!("running scope {:?} symbol: {:?}", id, scope.fnptr);
-
-        // Safety:
-        // - We dropped the listeners, so no more &mut T can be used while these are held
-        // - All children nodes that rely on &mut T are replaced with a new reference
-        scope.hook_idx.set(0);
-
-        {
-            // Safety:
-            // - We've dropped all references to the wip bump frame with "ensure_drop_safety"
-            unsafe { scope.reset_wip_frame() };
-
-            let items = scope.items.borrow();
-
-            // guarantee that we haven't screwed up - there should be no latent references anywhere
-            debug_assert!(items.listeners.is_empty());
-            debug_assert!(items.borrowed_props.is_empty());
-        }
-
-        /*
-        If the component returns None, then we fill in a placeholder node. This will wipe what was there.
-        An alternate approach is to leave the Real Dom the same, but that can lead to safety issues and a lot more checks.
-
-        Instead, we just treat the `None` as a shortcut to placeholder.
-        If the developer wants to prevent a scope from updating, they should control its memoization instead.
-
-        Also, the way we implement hooks allows us to cut rendering short before the next hook is recalled.
-        I'm not sure if React lets you abort the component early, but we let you do that.
-        */
-
-        let props = scope.props.borrow();
-        let render = props.as_ref().unwrap();
-        if let Some(node) = render.render(scope) {
-            let frame = scope.wip_frame();
-            let node = frame.bump.alloc(node);
-            frame.node.set(unsafe { extend_vnode(node) });
-        } else {
-            let frame = scope.wip_frame();
-            let node = frame.bump.alloc(VNode::Text(frame.bump.alloc(VText {
-                id: Cell::default(),
-                text: "asd",
-            })));
-            frame.node.set(unsafe { extend_vnode(node) });
-        }
-
-        // make the "wip frame" contents the "finished frame"
-        // any future dipping into completed nodes after "render" will go through "fin head"
-        scope.cycle_frame();
-    }
-
-    pub fn call_listener_with_bubbling(&self, event: &UserEvent, element: ElementId) {
-        let nodes = self.nodes.borrow();
-        let mut cur_el = Some(element);
-
-        let state = Rc::new(BubbleState::new());
-
-        while let Some(id) = cur_el.take() {
-            if let Some(el) = nodes.get(id.0) {
-                let real_el = unsafe { &**el };
-
-                if let VNode::Element(real_el) = real_el {
-                    for listener in real_el.listeners.borrow().iter() {
-                        if listener.event == event.name {
-                            if state.canceled.get() {
-                                // stop bubbling if canceled
-                                return;
-                            }
-
-                            let mut cb = listener.callback.borrow_mut();
-                            if let Some(cb) = cb.as_mut() {
-                                // todo: arcs are pretty heavy to clone
-                                // we really want to convert arc to rc
-                                // unfortunately, the SchedulerMsg must be send/sync to be sent across threads
-                                // we could convert arc to rc internally or something
-                                (cb)(AnyEvent {
-                                    bubble_state: state.clone(),
-                                    data: event.data.clone(),
-                                });
-                            }
-
-                            if !event.bubbles {
-                                return;
-                            }
-                        }
-                    }
-
-                    cur_el = real_el.parent.get();
-                }
-            }
-        }
-    }
-
-    // The head of the bumpframe is the first linked NodeLink
-    pub fn wip_head(&self, id: ScopeId) -> &VNode {
-        let scope = self.get_scope(id).unwrap();
-        let frame = scope.wip_frame();
-        let node = unsafe { &*frame.node.get() };
-        unsafe { extend_vnode(node) }
-    }
-
-    // The head of the bumpframe is the first linked NodeLink
-    pub fn fin_head(&self, id: ScopeId) -> &VNode {
-        let scope = self.get_scope(id).unwrap();
-        let frame = scope.fin_frame();
-        let node = unsafe { &*frame.node.get() };
-        unsafe { extend_vnode(node) }
-    }
-
-    pub fn root_node(&self, id: ScopeId) -> &VNode {
-        self.fin_head(id)
-    }
-
-    // this is totally okay since all our nodes are always in a valid state
-    pub fn get_element(&self, id: ElementId) -> Option<&VNode> {
-        self.nodes
-            .borrow()
-            .get(id.0)
-            .copied()
-            .map(|ptr| unsafe { extend_vnode(&*ptr) })
-    }
-}
-
-/// Components in Dioxus use the "Context" object to interact with their lifecycle.
-///
-/// This lets components access props, schedule updates, integrate hooks, and expose shared state.
-///
-/// For the most part, the only method you should be using regularly is `render`.
-///
-/// ## Example
-///
-/// ```ignore
-/// #[derive(Props)]
-/// struct ExampleProps {
-///     name: String
-/// }
-///
-/// fn Example(cx: Scope<ExampleProps>) -> Element {
-///     cx.render(rsx!{ div {"Hello, {cx.props.name}"} })
-/// }
-/// ```
-pub struct Scope<'a, P = ()> {
-    /// The internal ScopeState for this component
-    pub scope: &'a ScopeState,
-
-    /// The props for this component
-    pub props: &'a P,
-}
-
-impl<P> Copy for Scope<'_, P> {}
-impl<P> Clone for Scope<'_, P> {
-    fn clone(&self) -> Self {
-        Self {
-            scope: self.scope,
-            props: self.props,
-        }
-    }
-}
-
-impl<'a, P> std::ops::Deref for Scope<'a, P> {
-    type Target = &'a ScopeState;
-    fn deref(&self) -> &Self::Target {
-        &self.scope
-    }
-}
-
-/// A component's unique identifier.
-///
-/// `ScopeId` is a `usize` that is unique across the entire [`VirtualDom`] and across time. [`ScopeID`]s will never be reused
-/// once a component has been unmounted.
-#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
-pub struct ScopeId(pub usize);
-
-/// A task's unique identifier.
-///
-/// `TaskId` is a `usize` that is unique across the entire [`VirtualDom`] and across time. [`TaskID`]s will never be reused
-/// once a Task has been completed.
-#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub struct TaskId {
-    /// The global ID of the task
-    pub id: usize,
-
-    /// The original scope that this task was scheduled in
-    pub scope: ScopeId,
-}
-
-/// Every component in Dioxus is represented by a `ScopeState`.
-///
-/// Scopes contain the state for hooks, the component's props, and other lifecycle information.
-///
-/// Scopes are allocated in a generational arena. As components are mounted/unmounted, they will replace slots of dead components.
-/// The actual contents of the hooks, though, will be allocated with the standard allocator. These should not allocate as frequently.
-///
-/// We expose the `Scope` type so downstream users can traverse the Dioxus [`VirtualDom`] for whatever
-/// use case they might have.
-pub struct ScopeState {
-    pub(crate) parent_scope: Option<*mut ScopeState>,
-    pub(crate) container: ElementId,
-    pub(crate) our_arena_idx: ScopeId,
-    pub(crate) height: u32,
-    pub(crate) fnptr: ComponentPtr,
-
-    // todo: subtrees
-    pub(crate) is_subtree_root: Cell<bool>,
-    pub(crate) subtree: Cell<u32>,
-    pub(crate) props: RefCell<Option<Box<dyn AnyProps>>>,
-
-    // nodes, items
-    pub(crate) frames: [BumpFrame; 2],
-    pub(crate) generation: Cell<u32>,
-    pub(crate) items: RefCell<SelfReferentialItems<'static>>,
-
-    // hooks
-    pub(crate) hook_arena: Bump,
-    pub(crate) hook_vals: RefCell<Vec<*mut dyn Any>>,
-    pub(crate) hook_idx: Cell<usize>,
-
-    // shared state -> todo: move this out of scopestate
-    pub(crate) shared_contexts: RefCell<HashMap<TypeId, Box<dyn Any>>>,
-    pub(crate) tasks: Rc<TaskQueue>,
-}
-
-pub struct SelfReferentialItems<'a> {
-    pub(crate) listeners: Vec<&'a Listener<'a>>,
-    pub(crate) borrowed_props: Vec<&'a VComponent<'a>>,
-}
-
-// Public methods exposed to libraries and components
-impl ScopeState {
-    /// Get the subtree ID that this scope belongs to.
-    ///
-    /// Each component has its own subtree ID - the root subtree has an ID of 0. This ID is used by the renderer to route
-    /// the mutations to the correct window/portal/subtree.
-    ///
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// let mut dom = VirtualDom::new(|cx| cx.render(rsx!{ div {} }));
-    /// dom.rebuild();
-    ///
-    /// let base = dom.base_scope();
-    ///
-    /// assert_eq!(base.subtree(), 0);
-    /// ```
-    ///
-    /// todo: enable
-    pub(crate) fn _subtree(&self) -> u32 {
-        self.subtree.get()
-    }
-
-    /// Create a new subtree with this scope as the root of the subtree.
-    ///
-    /// Each component has its own subtree ID - the root subtree has an ID of 0. This ID is used by the renderer to route
-    /// the mutations to the correct window/portal/subtree.
-    ///
-    /// This method
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// fn App(cx: Scope) -> Element {
-    ///     render!(div { "Subtree {id}"})
-    /// };
-    /// ```
-    ///
-    /// todo: enable subtree
-    pub(crate) fn _create_subtree(&self) -> Option<u32> {
-        if self.is_subtree_root.get() {
-            None
-        } else {
-            todo!()
-        }
-    }
-
-    /// Get the height of this Scope - IE the number of scopes above it.
-    ///
-    /// A Scope with a height of `0` is the root scope - there are no other scopes above it.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// let mut dom = VirtualDom::new(|cx|  cx.render(rsx!{ div {} }));
-    /// dom.rebuild();
-    ///
-    /// let base = dom.base_scope();
-    ///
-    /// assert_eq!(base.height(), 0);
-    /// ```
-    pub fn height(&self) -> u32 {
-        self.height
-    }
-
-    /// Get the Parent of this [`Scope`] within this Dioxus [`VirtualDom`].
-    ///
-    /// This ID is not unique across Dioxus [`VirtualDom`]s or across time. IDs will be reused when components are unmounted.
-    ///
-    /// The base component will not have a parent, and will return `None`.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// let mut dom = VirtualDom::new(|cx|  cx.render(rsx!{ div {} }));
-    /// dom.rebuild();
-    ///
-    /// let base = dom.base_scope();
-    ///
-    /// assert_eq!(base.parent(), None);
-    /// ```
-    pub fn parent(&self) -> Option<ScopeId> {
-        // safety: the pointer to our parent is *always* valid thanks to the bump arena
-        self.parent_scope.map(|p| unsafe { &*p }.our_arena_idx)
-    }
-
-    /// Get the ID of this Scope within this Dioxus [`VirtualDom`].
-    ///
-    /// This ID is not unique across Dioxus [`VirtualDom`]s or across time. IDs will be reused when components are unmounted.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// let mut dom = VirtualDom::new(|cx|  cx.render(rsx!{ div {} }));
-    /// dom.rebuild();
-    /// let base = dom.base_scope();
-    ///
-    /// assert_eq!(base.scope_id(), 0);
-    /// ```
-    pub fn scope_id(&self) -> ScopeId {
-        self.our_arena_idx
-    }
-
-    /// Get a handle to the raw update scheduler channel
-    pub fn scheduler_channel(&self) -> UnboundedSender<SchedulerMsg> {
-        self.tasks.sender.clone()
-    }
-
-    /// Create a subscription that schedules a future render for the reference component
-    ///
-    /// ## Notice: you should prefer using [`schedule_update_any`] and [`scope_id`]
-    pub fn schedule_update(&self) -> Arc<dyn Fn() + Send + Sync + 'static> {
-        let (chan, id) = (self.tasks.sender.clone(), self.scope_id());
-        Arc::new(move || drop(chan.unbounded_send(SchedulerMsg::Immediate(id))))
-    }
-
-    /// Schedule an update for any component given its [`ScopeId`].
-    ///
-    /// A component's [`ScopeId`] can be obtained from `use_hook` or the [`ScopeState::scope_id`] method.
-    ///
-    /// This method should be used when you want to schedule an update for a component
-    pub fn schedule_update_any(&self) -> Arc<dyn Fn(ScopeId) + Send + Sync> {
-        let chan = self.tasks.sender.clone();
-        Arc::new(move |id| drop(chan.unbounded_send(SchedulerMsg::Immediate(id))))
-    }
-
-    pub fn needs_update(&self) {
-        self.needs_update_any(self.scope_id());
-    }
-
-    /// Get the [`ScopeId`] of a mounted component.
-    ///
-    /// `ScopeId` is not unique for the lifetime of the [`VirtualDom`] - a [`ScopeId`] will be reused if a component is unmounted.
-    pub fn needs_update_any(&self, id: ScopeId) {
-        self.tasks
-            .sender
-            .unbounded_send(SchedulerMsg::Immediate(id))
-            .expect("Scheduler to exist if scope exists");
-    }
-
-    /// Get the Root Node of this scope
-    pub fn root_node(&self) -> &VNode {
-        let node = unsafe { &*self.fin_frame().node.get() };
-        unsafe { std::mem::transmute(node) }
-    }
-
-    /// This method enables the ability to expose state to children further down the [`VirtualDom`] Tree.
-    ///
-    /// This is a "fundamental" operation and should only be called during initialization of a hook.
-    ///
-    /// For a hook that provides the same functionality, use `use_provide_context` and `use_consume_context` instead.
-    ///
-    /// When the component is dropped, so is the context. Be aware of this behavior when consuming
-    /// the context via Rc/Weak.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// struct SharedState(&'static str);
-    ///
-    /// static App: Component = |cx| {
-    ///     cx.use_hook(|| cx.provide_context(SharedState("world")));
-    ///     render!(Child {})
-    /// }
-    ///
-    /// static Child: Component = |cx| {
-    ///     let state = cx.consume_state::<SharedState>();
-    ///     render!(div { "hello {state.0}" })
-    /// }
-    /// ```
-    pub fn provide_context<T: 'static + Clone>(&self, value: T) -> T {
-        self.shared_contexts
-            .borrow_mut()
-            .insert(TypeId::of::<T>(), Box::new(value.clone()))
-            .and_then(|f| f.downcast::<T>().ok());
-        value
-    }
-
-    /// Provide a context for the root component from anywhere in your app.
-    ///
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// struct SharedState(&'static str);
-    ///
-    /// static App: Component = |cx| {
-    ///     cx.use_hook(|| cx.provide_root_context(SharedState("world")));
-    ///     render!(Child {})
-    /// }
-    ///
-    /// static Child: Component = |cx| {
-    ///     let state = cx.consume_state::<SharedState>();
-    ///     render!(div { "hello {state.0}" })
-    /// }
-    /// ```
-    pub fn provide_root_context<T: 'static + Clone>(&self, value: T) -> T {
-        // if we *are* the root component, then we can just provide the context directly
-        if self.scope_id() == ScopeId(0) {
-            self.shared_contexts
-                .borrow_mut()
-                .insert(TypeId::of::<T>(), Box::new(value.clone()))
-                .and_then(|f| f.downcast::<T>().ok());
-            return value;
-        }
-
-        let mut search_parent = self.parent_scope;
-
-        while let Some(parent) = search_parent.take() {
-            let parent = unsafe { &*parent };
-
-            if parent.scope_id() == ScopeId(0) {
-                let exists = parent
-                    .shared_contexts
-                    .borrow_mut()
-                    .insert(TypeId::of::<T>(), Box::new(value.clone()));
-
-                if exists.is_some() {
-                    log::warn!("Context already provided to parent scope - replacing it");
-                }
-                return value;
-            }
-
-            search_parent = parent.parent_scope;
-        }
-
-        unreachable!("all apps have a root scope")
-    }
-
-    /// Try to retrieve a shared state with type T from the any parent Scope.
-    pub fn consume_context<T: 'static + Clone>(&self) -> Option<T> {
-        if let Some(shared) = self.shared_contexts.borrow().get(&TypeId::of::<T>()) {
-            Some(
-                (*shared
-                    .downcast_ref::<T>()
-                    .expect("Context of type T should exist"))
-                .clone(),
-            )
-        } else {
-            let mut search_parent = self.parent_scope;
-
-            while let Some(parent_ptr) = search_parent {
-                // safety: all parent pointers are valid thanks to the bump arena
-                let parent = unsafe { &*parent_ptr };
-                if let Some(shared) = parent.shared_contexts.borrow().get(&TypeId::of::<T>()) {
-                    return Some(
-                        shared
-                            .downcast_ref::<T>()
-                            .expect("Context of type T should exist")
-                            .clone(),
-                    );
-                }
-                search_parent = parent.parent_scope;
-            }
-            None
-        }
-    }
-
-    /// Pushes the future onto the poll queue to be polled after the component renders.
-    pub fn push_future(&self, fut: impl Future<Output = ()> + 'static) -> TaskId {
-        // wake up the scheduler if it is sleeping
-        self.tasks
-            .sender
-            .unbounded_send(SchedulerMsg::NewTask(self.our_arena_idx))
-            .expect("Scheduler should exist");
-
-        self.tasks.spawn(self.our_arena_idx, fut)
-    }
-
-    /// Spawns the future but does not return the [`TaskId`]
-    pub fn spawn(&self, fut: impl Future<Output = ()> + 'static) {
-        self.push_future(fut);
-    }
-
-    /// Spawn a future that Dioxus will never clean up
-    ///
-    /// This is good for tasks that need to be run after the component has been dropped.
-    pub fn spawn_forever(&self, fut: impl Future<Output = ()> + 'static) -> TaskId {
-        // wake up the scheduler if it is sleeping
-        self.tasks
-            .sender
-            .unbounded_send(SchedulerMsg::NewTask(self.our_arena_idx))
-            .expect("Scheduler should exist");
-
-        // The root scope will never be unmounted so we can just add the task at the top of the app
-        self.tasks.spawn(ScopeId(0), fut)
-    }
-
-    /// Informs the scheduler that this task is no longer needed and should be removed
-    /// on next poll.
-    pub fn remove_future(&self, id: TaskId) {
-        self.tasks.remove(id);
-    }
-
-    /// Take a lazy [`VNode`] structure and actually build it with the context of the Vdoms efficient [`VNode`] allocator.
-    ///
-    /// ## Example
-    ///
-    /// ```ignore
-    /// fn Component(cx: Scope<Props>) -> Element {
-    ///     // Lazy assemble the VNode tree
-    ///     let lazy_nodes = rsx!("hello world");
-    ///
-    ///     // Actually build the tree and allocate it
-    ///     cx.render(lazy_tree)
-    /// }
-    ///```
-    pub fn render<'src>(&'src self, rsx: LazyNodes<'src, '_>) -> Option<VNode<'src>> {
-        Some(rsx.call(NodeFactory {
-            scope: self,
-            bump: &self.wip_frame().bump,
-        }))
-    }
-
-    /// Store a value between renders. The foundational hook for all other hooks.
-    ///
-    /// Accepts an `initializer` closure, which is run on the first use of the hook (typically the initial render). The return value of this closure is stored for the lifetime of the component, and a mutable reference to it is provided on every render as the return value of `use_hook`.
-    ///
-    /// When the component is unmounted (removed from the UI), the value is dropped. This means you can return a custom type and provide cleanup code by implementing the [`Drop`] trait
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use dioxus_core::ScopeState;
-    ///
-    /// // prints a greeting on the initial render
-    /// pub fn use_hello_world(cx: &ScopeState) {
-    ///     cx.use_hook(|| println!("Hello, world!"));
-    /// }
-    /// ```
-    #[allow(clippy::mut_from_ref)]
-    pub fn use_hook<State: 'static>(&self, initializer: impl FnOnce() -> State) -> &mut State {
-        let mut vals = self.hook_vals.borrow_mut();
-
-        let hook_len = vals.len();
-        let cur_idx = self.hook_idx.get();
-
-        if cur_idx >= hook_len {
-            vals.push(self.hook_arena.alloc(initializer()));
-        }
-
-        vals
-            .get(cur_idx)
-            .and_then(|inn| {
-                self.hook_idx.set(cur_idx + 1);
-                let raw_box = unsafe { &mut **inn };
-                raw_box.downcast_mut::<State>()
-            })
-            .expect(
-                r###"
-                Unable to retrieve the hook that was initialized at this index.
-                Consult the `rules of hooks` to understand how to use hooks properly.
-
-                You likely used the hook in a conditional. Hooks rely on consistent ordering between renders.
-                Functions prefixed with "use" should never be called conditionally.
-                "###,
-            )
-    }
-
-    /// The "work in progress frame" represents the frame that is currently being worked on.
-    pub(crate) fn wip_frame(&self) -> &BumpFrame {
-        match self.generation.get() & 1 {
-            0 => &self.frames[0],
-            _ => &self.frames[1],
-        }
-    }
-
-    /// Mutable access to the "work in progress frame" - used to clear it
-    pub(crate) fn wip_frame_mut(&mut self) -> &mut BumpFrame {
-        match self.generation.get() & 1 {
-            0 => &mut self.frames[0],
-            _ => &mut self.frames[1],
-        }
-    }
-
-    /// Access to the frame where finalized nodes existed
-    pub(crate) fn fin_frame(&self) -> &BumpFrame {
-        match self.generation.get() & 1 {
-            1 => &self.frames[0],
-            _ => &self.frames[1],
-        }
-    }
-
-    /// Reset this component's frame
-    ///
-    /// # Safety:
-    ///
-    /// This method breaks every reference of every [`VNode`] in the current frame.
-    ///
-    /// Calling reset itself is not usually a big deal, but we consider it important
-    /// due to the complex safety guarantees we need to uphold.
-    pub(crate) unsafe fn reset_wip_frame(&mut self) {
-        self.wip_frame_mut().bump.reset();
-    }
-
-    /// Cycle to the next generation
-    pub(crate) fn cycle_frame(&self) {
-        self.generation.set(self.generation.get() + 1);
-    }
-
-    // todo: disable bookkeeping on drop (unncessary)
-    pub(crate) fn reset(&mut self) {
-        // first: book keaping
-        self.hook_idx.set(0);
-        self.parent_scope = None;
-        self.generation.set(0);
-        self.is_subtree_root.set(false);
-        self.subtree.set(0);
-
-        // next: shared context data
-        self.shared_contexts.get_mut().clear();
-
-        // next: reset the node data
-        let SelfReferentialItems {
-            borrowed_props,
-            listeners,
-        } = self.items.get_mut();
-        borrowed_props.clear();
-        listeners.clear();
-        self.frames[0].reset();
-        self.frames[1].reset();
-
-        // Free up the hook values
-        self.hook_vals.get_mut().drain(..).for_each(|state| {
-            let as_mut = unsafe { &mut *state };
-            let boxed = unsafe { bumpalo::boxed::Box::from_raw(as_mut) };
-            drop(boxed);
-        });
-
-        // Finally, clear the hook arena
-        self.hook_arena.reset();
-    }
-}
-
-pub(crate) struct BumpFrame {
-    pub bump: Bump,
-    pub node: Cell<*const VNode<'static>>,
-}
-impl BumpFrame {
-    pub(crate) fn new(capacity: usize) -> Self {
-        let bump = Bump::with_capacity(capacity);
-        let node = bump.alloc(VText {
-            text: "placeholdertext",
-            id: Cell::default(),
-        });
-        let node = bump.alloc(VNode::Text(unsafe {
-            &*(node as *mut VText as *const VText)
-        }));
-        let nodes = Cell::new(node as *const _);
-        Self { bump, node: nodes }
-    }
-
-    pub(crate) fn reset(&mut self) {
-        self.bump.reset();
-        let node = self.bump.alloc(VText {
-            text: "placeholdertext",
-            id: Cell::default(),
-        });
-        let node = self.bump.alloc(VNode::Text(unsafe {
-            &*(node as *mut VText as *const VText)
-        }));
-        self.node.set(node as *const _);
-    }
-}
-
-pub(crate) struct TaskQueue {
-    pub(crate) tasks: RefCell<FxHashMap<TaskId, InnerTask>>,
-    pub(crate) task_map: RefCell<FxHashMap<ScopeId, HashSet<TaskId>>>,
-    gen: Cell<usize>,
-    sender: UnboundedSender<SchedulerMsg>,
-}
-
-pub(crate) type InnerTask = Pin<Box<dyn Future<Output = ()>>>;
-impl TaskQueue {
-    fn spawn(&self, scope: ScopeId, task: impl Future<Output = ()> + 'static) -> TaskId {
-        let pinned = Box::pin(task);
-        let id = self.gen.get();
-        self.gen.set(id + 1);
-        let tid = TaskId { id, scope };
-
-        self.tasks.borrow_mut().insert(tid, pinned);
-
-        // also add to the task map
-        // when the component is unmounted we know to remove it from the map
-        self.task_map
-            .borrow_mut()
-            .entry(scope)
-            .or_default()
-            .insert(tid);
-
-        tid
-    }
-
-    fn remove(&self, id: TaskId) {
-        if let Ok(mut tasks) = self.tasks.try_borrow_mut() {
-            tasks.remove(&id);
-            if let Some(task_map) = self.task_map.borrow_mut().get_mut(&id.scope) {
-                task_map.remove(&id);
-            }
-        }
-        // the task map is still around, but it'll be removed when the scope is unmounted
-    }
-
-    pub(crate) fn has_tasks(&self) -> bool {
-        !self.tasks.borrow().is_empty()
-    }
-}
-
-#[test]
-fn sizeof() {
-    dbg!(std::mem::size_of::<ScopeState>());
-}

+ 0 - 84
packages/core/src.old/util.rs

@@ -1,84 +0,0 @@
-use crate::innerlude::{VNode, VirtualDom};
-
-/// An iterator that only yields "real" [`Element`]s. IE only Elements that are
-/// not [`VNode::Component`] or [`VNode::Fragment`], .
-pub struct ElementIdIterator<'a> {
-    vdom: &'a VirtualDom,
-
-    // Heuristically we should never bleed into 5 completely nested fragments/components
-    // Smallvec lets us stack allocate our little stack machine so the vast majority of cases are sane
-    stack: smallvec::SmallVec<[(u16, &'a VNode<'a>); 5]>,
-}
-
-impl<'a> ElementIdIterator<'a> {
-    /// Create a new iterator from the given [`VirtualDom`] and [`VNode`]
-    ///
-    /// This will allow you to iterate through all the real childrne of the [`VNode`].
-    pub fn new(vdom: &'a VirtualDom, node: &'a VNode<'a>) -> Self {
-        Self {
-            vdom,
-            stack: smallvec::smallvec![(0, node)],
-        }
-    }
-}
-
-impl<'a> Iterator for ElementIdIterator<'a> {
-    type Item = &'a VNode<'a>;
-
-    fn next(&mut self) -> Option<&'a VNode<'a>> {
-        let mut should_pop = false;
-        let mut returned_node = None;
-        let mut should_push = None;
-
-        while returned_node.is_none() {
-            if let Some((count, node)) = self.stack.last_mut() {
-                match node {
-                    // We can only exit our looping when we get "real" nodes
-                    VNode::Element(_) | VNode::Text(_) | VNode::Placeholder(_) => {
-                        // We've recursed INTO an element/text
-                        // We need to recurse *out* of it and move forward to the next
-                        should_pop = true;
-                        returned_node = Some(&**node);
-                    }
-
-                    // If we get a fragment we push the next child
-                    VNode::Fragment(frag) => {
-                        let count = *count as usize;
-                        if count >= frag.children.len() {
-                            should_pop = true;
-                        } else {
-                            should_push = Some(&frag.children[count]);
-                        }
-                    }
-
-                    // For components, we load their root and push them onto the stack
-                    VNode::Component(sc) => {
-                        let scope = self.vdom.get_scope(sc.scope.get().unwrap()).unwrap();
-                        // Simply swap the current node on the stack with the root of the component
-                        *node = scope.root_node();
-                    }
-
-                    VNode::Template(_) => todo!(),
-                }
-            } else {
-                // If there's no more items on the stack, we're done!
-                return None;
-            }
-
-            if should_pop {
-                self.stack.pop();
-                if let Some((id, _)) = self.stack.last_mut() {
-                    *id += 1;
-                }
-                should_pop = false;
-            }
-
-            if let Some(push) = should_push {
-                self.stack.push((0, push));
-                should_push = None;
-            }
-        }
-
-        returned_node
-    }
-}

+ 0 - 752
packages/core/src.old/virtual_dom.rs

@@ -1,752 +0,0 @@
-//! # Virtual DOM Implementation for Rust
-//!
-//! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
-
-use crate::diff::DiffState;
-use crate::innerlude::*;
-use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
-use futures_util::{future::poll_fn, StreamExt};
-use fxhash::FxHashSet;
-use indexmap::IndexSet;
-use std::{collections::VecDeque, iter::FromIterator, task::Poll};
-
-/// A virtual node system that progresses user events and diffs UI trees.
-///
-/// ## Guide
-///
-/// Components are defined as simple functions that take [`Scope`] and return an [`Element`].
-///
-/// ```rust, ignore
-/// #[derive(Props, PartialEq)]
-/// struct AppProps {
-///     title: String
-/// }
-///
-/// fn App(cx: Scope<AppProps>) -> Element {
-///     cx.render(rsx!(
-///         div {"hello, {cx.props.title}"}
-///     ))
-/// }
-/// ```
-///
-/// Components may be composed to make complex apps.
-///
-/// ```rust, ignore
-/// fn App(cx: Scope<AppProps>) -> Element {
-///     cx.render(rsx!(
-///         NavBar { routes: ROUTES }
-///         Title { "{cx.props.title}" }
-///         Footer {}
-///     ))
-/// }
-/// ```
-///
-/// To start an app, create a [`VirtualDom`] and call [`VirtualDom::rebuild`] to get the list of edits required to
-/// draw the UI.
-///
-/// ```rust, ignore
-/// let mut vdom = VirtualDom::new(App);
-/// let edits = vdom.rebuild();
-/// ```
-///
-/// To inject UserEvents into the VirtualDom, call [`VirtualDom::get_scheduler_channel`] to get access to the scheduler.
-///
-/// ```rust, ignore
-/// let channel = vdom.get_scheduler_channel();
-/// channel.send_unbounded(SchedulerMsg::UserEvent(UserEvent {
-///     // ...
-/// }))
-/// ```
-///
-/// While waiting for UserEvents to occur, call [`VirtualDom::wait_for_work`] to poll any futures inside the VirtualDom.
-///
-/// ```rust, ignore
-/// vdom.wait_for_work().await;
-/// ```
-///
-/// Once work is ready, call [`VirtualDom::work_with_deadline`] to compute the differences between the previous and
-/// current UI trees. This will return a [`Mutations`] object that contains Edits, Effects, and NodeRefs that need to be
-/// handled by the renderer.
-///
-/// ```rust, ignore
-/// let mutations = vdom.work_with_deadline(|| false);
-/// for edit in mutations {
-///     apply(edit);
-/// }
-/// ```
-///
-/// ## Building an event loop around Dioxus:
-///
-/// Putting everything together, you can build an event loop around Dioxus by using the methods outlined above.
-///
-/// ```rust, ignore
-/// fn App(cx: Scope) -> Element {
-///     cx.render(rsx!{
-///         div { "Hello World" }
-///     })
-/// }
-///
-/// async fn main() {
-///     let mut dom = VirtualDom::new(App);
-///
-///     let mut inital_edits = dom.rebuild();
-///     apply_edits(inital_edits);
-///
-///     loop {
-///         dom.wait_for_work().await;
-///         let frame_timeout = TimeoutFuture::new(Duration::from_millis(16));
-///         let deadline = || (&mut frame_timeout).now_or_never();
-///         let edits = dom.run_with_deadline(deadline).await;
-///         apply_edits(edits);
-///     }
-/// }
-/// ```
-pub struct VirtualDom {
-    scopes: ScopeArena,
-
-    pending_messages: VecDeque<SchedulerMsg>,
-    dirty_scopes: IndexSet<ScopeId>,
-
-    channel: (
-        UnboundedSender<SchedulerMsg>,
-        UnboundedReceiver<SchedulerMsg>,
-    ),
-}
-
-/// The type of message that can be sent to the scheduler.
-///
-/// These messages control how the scheduler will process updates to the UI.
-#[derive(Debug)]
-pub enum SchedulerMsg {
-    /// Events from the Renderer
-    Event(UserEvent),
-
-    /// Immediate updates from Components that mark them as dirty
-    Immediate(ScopeId),
-
-    /// Mark all components as dirty and update them
-    DirtyAll,
-
-    /// New tasks from components that should be polled when the next poll is ready
-    NewTask(ScopeId),
-}
-
-// Methods to create the VirtualDom
-impl VirtualDom {
-    /// Create a new VirtualDom with a component that does not have special props.
-    ///
-    /// # Description
-    ///
-    /// Later, the props can be updated by calling "update" with a new set of props, causing a set of re-renders.
-    ///
-    /// This is useful when a component tree can be driven by external state (IE SSR) but it would be too expensive
-    /// to toss out the entire tree.
-    ///
-    ///
-    /// # Example
-    /// ```rust, ignore
-    /// fn Example(cx: Scope) -> Element  {
-    ///     cx.render(rsx!( div { "hello world" } ))
-    /// }
-    ///
-    /// let dom = VirtualDom::new(Example);
-    /// ```
-    ///
-    /// Note: the VirtualDom is not progressed, you must either "run_with_deadline" or use "rebuild" to progress it.
-    pub fn new(root: Component) -> Self {
-        Self::new_with_props(root, ())
-    }
-
-    /// Create a new VirtualDom with the given properties for the root component.
-    ///
-    /// # Description
-    ///
-    /// Later, the props can be updated by calling "update" with a new set of props, causing a set of re-renders.
-    ///
-    /// This is useful when a component tree can be driven by external state (IE SSR) but it would be too expensive
-    /// to toss out the entire tree.
-    ///
-    ///
-    /// # Example
-    /// ```rust, ignore
-    /// #[derive(PartialEq, Props)]
-    /// struct SomeProps {
-    ///     name: &'static str
-    /// }
-    ///
-    /// fn Example(cx: Scope<SomeProps>) -> Element  {
-    ///     cx.render(rsx!{ div{ "hello {cx.props.name}" } })
-    /// }
-    ///
-    /// let dom = VirtualDom::new(Example);
-    /// ```
-    ///
-    /// Note: the VirtualDom is not progressed on creation. You must either "run_with_deadline" or use "rebuild" to progress it.
-    ///
-    /// ```rust, ignore
-    /// let mut dom = VirtualDom::new_with_props(Example, SomeProps { name: "jane" });
-    /// let mutations = dom.rebuild();
-    /// ```
-    pub fn new_with_props<P>(root: Component<P>, root_props: P) -> Self
-    where
-        P: 'static,
-    {
-        Self::new_with_props_and_scheduler(
-            root,
-            root_props,
-            futures_channel::mpsc::unbounded::<SchedulerMsg>(),
-        )
-    }
-
-    /// Launch the VirtualDom, but provide your own channel for receiving and sending messages into the scheduler
-    ///
-    /// This is useful when the VirtualDom must be driven from outside a thread and it doesn't make sense to wait for the
-    /// VirtualDom to be created just to retrieve its channel receiver.
-    ///
-    /// ```rust, ignore
-    /// let channel = futures_channel::mpsc::unbounded();
-    /// let dom = VirtualDom::new_with_scheduler(Example, (), channel);
-    /// ```
-    pub fn new_with_props_and_scheduler<P: 'static>(
-        root: Component<P>,
-        root_props: P,
-        channel: (
-            UnboundedSender<SchedulerMsg>,
-            UnboundedReceiver<SchedulerMsg>,
-        ),
-    ) -> Self {
-        let scopes = ScopeArena::new(channel.0.clone());
-
-        scopes.new_with_key(
-            root as ComponentPtr,
-            Box::new(VComponentProps {
-                props: root_props,
-                memo: |_a, _b| unreachable!("memo on root will neve be run"),
-                render_fn: root,
-            }),
-            None,
-            ElementId(0),
-            0,
-        );
-
-        Self {
-            scopes,
-            channel,
-            dirty_scopes: IndexSet::from_iter([ScopeId(0)]),
-            pending_messages: VecDeque::new(),
-        }
-    }
-
-    /// Get the [`Scope`] for the root component.
-    ///
-    /// This is useful for traversing the tree from the root for heuristics or alternative renderers that use Dioxus
-    /// directly.
-    ///
-    /// This method is equivalent to calling `get_scope(ScopeId(0))`
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// let mut dom = VirtualDom::new(example);
-    /// dom.rebuild();
-    ///
-    ///
-    /// ```
-    pub fn base_scope(&self) -> &ScopeState {
-        self.get_scope(ScopeId(0)).unwrap()
-    }
-
-    /// Get the [`ScopeState`] for a component given its [`ScopeId`]
-    ///
-    /// # Example
-    ///
-    ///
-    ///
-    pub fn get_scope(&self, id: ScopeId) -> Option<&ScopeState> {
-        self.scopes.get_scope(id)
-    }
-
-    /// Get an [`UnboundedSender`] handle to the channel used by the scheduler.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// let dom = VirtualDom::new(App);
-    /// let sender = dom.get_scheduler_channel();
-    /// ```
-    pub fn get_scheduler_channel(&self) -> UnboundedSender<SchedulerMsg> {
-        self.channel.0.clone()
-    }
-
-    /// Try to get an element from its ElementId
-    pub fn get_element(&self, id: ElementId) -> Option<&VNode> {
-        self.scopes.get_element(id)
-    }
-
-    /// Add a new message to the scheduler queue directly.
-    ///
-    ///
-    /// This method makes it possible to send messages to the scheduler from outside the VirtualDom without having to
-    /// call `get_schedule_channel` and then `send`.
-    ///
-    /// # Example
-    /// ```rust, ignore
-    /// let dom = VirtualDom::new(App);
-    /// dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
-    /// ```
-    pub fn handle_message(&mut self, msg: SchedulerMsg) {
-        if self.channel.0.unbounded_send(msg).is_ok() {
-            self.process_all_messages();
-        }
-    }
-
-    /// Check if the [`VirtualDom`] has any pending updates or work to be done.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// let dom = VirtualDom::new(App);
-    ///
-    /// // the dom is "dirty" when it is started and must be rebuilt to get the first render
-    /// assert!(dom.has_any_work());
-    /// ```
-    pub fn has_work(&self) -> bool {
-        !(self.dirty_scopes.is_empty() && self.pending_messages.is_empty())
-    }
-
-    /// Wait for the scheduler to have any work.
-    ///
-    /// This method polls the internal future queue *and* the scheduler channel.
-    /// To add work to the VirtualDom, insert a message via the scheduler channel.
-    ///
-    /// This lets us poll async tasks during idle periods without blocking the main thread.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// let dom = VirtualDom::new(App);
-    /// let sender = dom.get_scheduler_channel();
-    /// ```
-    pub async fn wait_for_work(&mut self) {
-        loop {
-            if !self.dirty_scopes.is_empty() && self.pending_messages.is_empty() {
-                break;
-            }
-
-            if self.pending_messages.is_empty() {
-                if self.scopes.tasks.has_tasks() {
-                    use futures_util::future::{select, Either};
-
-                    let scopes = &mut self.scopes;
-                    let task_poll = poll_fn(|cx| {
-                        let mut tasks = scopes.tasks.tasks.borrow_mut();
-                        tasks.retain(|_, task| task.as_mut().poll(cx).is_pending());
-
-                        match tasks.is_empty() {
-                            true => Poll::Ready(()),
-                            false => Poll::Pending,
-                        }
-                    });
-
-                    match select(task_poll, self.channel.1.next()).await {
-                        Either::Left((_, _)) => {}
-                        Either::Right((msg, _)) => self.pending_messages.push_front(msg.unwrap()),
-                    }
-                } else {
-                    self.pending_messages
-                        .push_front(self.channel.1.next().await.unwrap());
-                }
-            }
-
-            // Move all the messages into the queue
-            self.process_all_messages();
-        }
-    }
-
-    /// Manually kick the VirtualDom to process any
-    pub fn process_all_messages(&mut self) {
-        // clear out the scheduler queue
-        while let Ok(Some(msg)) = self.channel.1.try_next() {
-            self.pending_messages.push_front(msg);
-        }
-
-        // process all the messages pulled from the queue
-        while let Some(msg) = self.pending_messages.pop_back() {
-            self.process_message(msg);
-        }
-    }
-
-    /// Handle an individual message for the scheduler.
-    ///
-    /// This will either call an event listener or mark a component as dirty.
-    pub fn process_message(&mut self, msg: SchedulerMsg) {
-        match msg {
-            SchedulerMsg::NewTask(_id) => {
-                // uh, not sure? I think end up re-polling it anyways
-            }
-            SchedulerMsg::Event(event) => {
-                if let Some(element) = event.element {
-                    self.scopes.call_listener_with_bubbling(&event, element);
-                }
-            }
-            SchedulerMsg::Immediate(s) => {
-                self.dirty_scopes.insert(s);
-            }
-            SchedulerMsg::DirtyAll => {
-                for id in self.scopes.scopes.borrow().keys() {
-                    self.dirty_scopes.insert(*id);
-                }
-            }
-        }
-    }
-
-    /// Run the virtualdom with a deadline.
-    ///
-    /// This method will perform any outstanding diffing work and try to return as many mutations as possible before the
-    /// deadline is reached. This method accepts a closure that returns `true` if the deadline has been reached. To wrap
-    /// your future into a deadline, consider the `now_or_never` method from `future_utils`.
-    ///
-    /// ```rust, ignore
-    /// let mut vdom = VirtualDom::new(App);
-    ///
-    /// let timeout = TimeoutFuture::from_ms(16);
-    /// let deadline = || (&mut timeout).now_or_never();
-    ///
-    /// let mutations = vdom.work_with_deadline(deadline);
-    /// ```
-    ///
-    /// This method is useful when needing to schedule the virtualdom around other tasks on the main thread to prevent
-    /// "jank". It will try to finish whatever work it has by the deadline to free up time for other work.
-    ///
-    /// If the work is not finished by the deadline, Dioxus will store it for later and return when work_with_deadline
-    /// is called again. This means you can ensure some level of free time on the VirtualDom's thread during the work phase.
-    ///
-    /// For use in the web, it is expected that this method will be called to be executed during "idle times" and the
-    /// mutations to be applied during the "paint times" IE "animation frames". With this strategy, it is possible to craft
-    /// entirely jank-free applications that perform a ton of work.
-    ///
-    /// In general use, Dioxus is plenty fast enough to not need to worry about this.
-    ///
-    /// # Example
-    ///
-    /// ```rust, ignore
-    /// fn App(cx: Scope) -> Element {
-    ///     cx.render(rsx!( div {"hello"} ))
-    /// }
-    ///
-    /// let mut dom = VirtualDom::new(App);
-    ///
-    /// loop {
-    ///     let mut timeout = TimeoutFuture::from_ms(16);
-    ///     let deadline = move || (&mut timeout).now_or_never();
-    ///
-    ///     let mutations = dom.run_with_deadline(deadline).await;
-    ///
-    ///     apply_mutations(mutations);
-    /// }
-    /// ```
-    pub fn work_with_deadline<'a>(
-        &'a mut self,
-        renderer: &mut impl Renderer<'a>,
-        mut deadline: impl FnMut() -> bool,
-    ) {
-        while !self.dirty_scopes.is_empty() {
-            let scopes = &self.scopes;
-            let mut diff_state = DiffState::new(scopes, renderer);
-
-            let mut ran_scopes = FxHashSet::default();
-
-            // Sort the scopes by height. Theoretically, we'll de-duplicate scopes by height
-            self.dirty_scopes
-                .retain(|id| scopes.get_scope(*id).is_some());
-
-            self.dirty_scopes.sort_by(|a, b| {
-                let h1 = scopes.get_scope(*a).unwrap().height;
-                let h2 = scopes.get_scope(*b).unwrap().height;
-                h1.cmp(&h2).reverse()
-            });
-
-            if let Some(scopeid) = self.dirty_scopes.pop() {
-                if !ran_scopes.contains(&scopeid) {
-                    ran_scopes.insert(scopeid);
-
-                    self.scopes.run_scope(scopeid);
-
-                    diff_state.diff_scope(scopeid);
-
-                    let DiffState { mutations, .. } = diff_state;
-
-                    todo!()
-                    // for scope in &mutations.dirty_scopes {
-                    //     self.dirty_scopes.remove(scope);
-                    // }
-
-                    // if !mutations.edits.is_empty() {
-                    //     committed_mutations.push(mutations);
-                    // }
-
-                    // todo: pause the diff machine
-                    // if diff_state.work(&mut deadline) {
-                    //     let DiffState { mutations, .. } = diff_state;
-                    //     for scope in &mutations.dirty_scopes {
-                    //         self.dirty_scopes.remove(scope);
-                    //     }
-                    //     committed_mutations.push(mutations);
-                    // } else {
-                    //     // leave the work in an incomplete state
-                    //     //
-                    //     // todo: we should store the edits and re-apply them later
-                    //     // for now, we just dump the work completely (threadsafe)
-                    //     return committed_mutations;
-                    // }
-                }
-            }
-        }
-    }
-
-    /// Run the virtualdom, waiting for all async components to finish rendering
-    ///
-    /// As they finish rendering, the virtualdom will apply the mutations to the renderer.
-    pub async fn render(&mut self, renderer: &mut impl Renderer<'_>) {
-        //
-    }
-
-    /// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom from scratch.
-    ///
-    /// The diff machine expects the RealDom's stack to be the root of the application.
-    ///
-    /// Tasks will not be polled with this method, nor will any events be processed from the event queue. Instead, the
-    /// root component will be ran once and then diffed. All updates will flow out as mutations.
-    ///
-    /// All state stored in components will be completely wiped away.
-    ///
-    /// # Example
-    /// ```rust, ignore
-    /// static App: Component = |cx|  cx.render(rsx!{ "hello world" });
-    /// let mut dom = VirtualDom::new();
-    /// let edits = dom.rebuild();
-    ///
-    /// apply_edits(edits);
-    /// ```
-    pub fn rebuild<'a>(&'a mut self, dom: &mut impl Renderer<'a>) {
-        let scope_id = ScopeId(0);
-        let mut diff_state = DiffState::new(&self.scopes, dom);
-
-        self.scopes.run_scope(scope_id);
-
-        diff_state.element_stack.push(ElementId(0));
-        diff_state.scope_stack.push(scope_id);
-
-        let node = self.scopes.fin_head(scope_id);
-        let created = diff_state.create_node(node);
-
-        diff_state.mutations.append_children(created as u32);
-
-        self.dirty_scopes.clear();
-        assert!(self.dirty_scopes.is_empty());
-    }
-
-    /// Compute a manual diff of the VirtualDom between states.
-    ///
-    /// This can be useful when state inside the DOM is remotely changed from the outside, but not propagated as an event.
-    ///
-    /// In this case, every component will be diffed, even if their props are memoized. This method is intended to be used
-    /// to force an update of the DOM when the state of the app is changed outside of the app.
-    ///
-    /// To force a reflow of the entire VirtualDom, use `ScopeId(0)` as the scope_id.
-    ///
-    /// # Example
-    /// ```rust, ignore
-    /// #[derive(PartialEq, Props)]
-    /// struct AppProps {
-    ///     value: Shared<&'static str>,
-    /// }
-    ///
-    /// static App: Component<AppProps> = |cx| {
-    ///     let val = cx.value.borrow();
-    ///     cx.render(rsx! { div { "{val}" } })
-    /// };
-    ///
-    /// let value = Rc::new(RefCell::new("Hello"));
-    /// let mut dom = VirtualDom::new_with_props(App, AppProps { value: value.clone(), });
-    ///
-    /// let _ = dom.rebuild();
-    ///
-    /// *value.borrow_mut() = "goodbye";
-    ///
-    /// let edits = dom.hard_diff(ScopeId(0));
-    /// ```
-    pub fn hard_diff<'a>(&'a mut self, scope_id: ScopeId, dom: &mut impl Renderer<'a>) {
-        let mut diff_machine = DiffState::new(&self.scopes, dom);
-        self.scopes.run_scope(scope_id);
-
-        let (old, new) = (
-            diff_machine.scopes.wip_head(scope_id),
-            diff_machine.scopes.fin_head(scope_id),
-        );
-
-        diff_machine.force_diff = true;
-        diff_machine.scope_stack.push(scope_id);
-        let scope = diff_machine.scopes.get_scope(scope_id).unwrap();
-        diff_machine.element_stack.push(scope.container);
-
-        diff_machine.diff_node(old, new);
-    }
-
-    // /// Renders an `rsx` call into the Base Scope's allocator.
-    // ///
-    // /// Useful when needing to render nodes from outside the VirtualDom, such as in a test.
-    // ///
-    // /// ```rust, ignore
-    // /// fn Base(cx: Scope) -> Element {
-    // ///     render!(div {})
-    // /// }
-    // ///
-    // /// let dom = VirtualDom::new(Base);
-    // /// let nodes = dom.render_nodes(rsx!("div"));
-    // /// ```
-    // pub fn render_vnodes<'a>(&'a self, lazy_nodes: LazyNodes<'a, '_>) -> &'a VNode<'a> {
-    //     let scope = self.scopes.get_scope(ScopeId(0)).unwrap();
-    //     let frame = scope.wip_frame();
-    //     let factory = NodeFactory::new(scope);
-    //     let node = lazy_nodes.call(factory);
-    //     frame.bump.alloc(node)
-    // }
-
-    // /// Renders an `rsx` call into the Base Scope's allocator.
-    // ///
-    // /// Useful when needing to render nodes from outside the VirtualDom, such as in a test.
-    // ///
-    // /// ```rust, ignore
-    // /// fn Base(cx: Scope) -> Element {
-    // ///     render!(div {})
-    // /// }
-    // ///
-    // /// let dom = VirtualDom::new(Base);
-    // /// let nodes = dom.render_nodes(rsx!("div"));
-    // /// ```
-    // pub fn diff_vnodes<'a>(&'a self, old: &'a VNode<'a>, new: &'a VNode<'a>) -> Mutations<'a> {
-    //     let mut machine = DiffState::new(&self.scopes);
-    //     machine.element_stack.push(ElementId(0));
-    //     machine.scope_stack.push(ScopeId(0));
-    //     machine.diff_node(old, new);
-
-    //     machine.mutations
-    // }
-
-    // /// Renders an `rsx` call into the Base Scope's allocator.
-    // ///
-    // /// Useful when needing to render nodes from outside the VirtualDom, such as in a test.
-    // ///
-    // ///
-    // /// ```rust, ignore
-    // /// fn Base(cx: Scope) -> Element {
-    // ///     render!(div {})
-    // /// }
-    // ///
-    // /// let dom = VirtualDom::new(Base);
-    // /// let nodes = dom.render_nodes(rsx!("div"));
-    // /// ```
-    // pub fn create_vnodes<'a>(&'a self, nodes: LazyNodes<'a, '_>) -> Mutations<'a> {
-    //     let mut machine = DiffState::new(&self.scopes);
-    //     machine.scope_stack.push(ScopeId(0));
-    //     machine.element_stack.push(ElementId(0));
-    //     let node = self.render_vnodes(nodes);
-    //     let created = machine.create_node(node);
-    //     machine.mutations.append_children(created as u32);
-    //     machine.mutations
-    // }
-
-    // /// Renders an `rsx` call into the Base Scopes's arena.
-    // ///
-    // /// Useful when needing to diff two rsx! calls from outside the VirtualDom, such as in a test.
-    // ///
-    // ///
-    // /// ```rust, ignore
-    // /// fn Base(cx: Scope) -> Element {
-    // ///     render!(div {})
-    // /// }
-    // ///
-    // /// let dom = VirtualDom::new(Base);
-    // /// let nodes = dom.render_nodes(rsx!("div"));
-    // /// ```
-    // pub fn diff_lazynodes<'a>(
-    //     &'a self,
-    //     left: LazyNodes<'a, '_>,
-    //     right: LazyNodes<'a, '_>,
-    // ) -> (Mutations<'a>, Mutations<'a>) {
-    //     let (old, new) = (self.render_vnodes(left), self.render_vnodes(right));
-
-    //     let mut create = DiffState::new(&self.scopes);
-    //     create.scope_stack.push(ScopeId(0));
-    //     create.element_stack.push(ElementId(0));
-    //     let created = create.create_node(old);
-    //     create.mutations.append_children(created as u32);
-
-    //     let mut edit = DiffState::new(&self.scopes);
-    //     edit.scope_stack.push(ScopeId(0));
-    //     edit.element_stack.push(ElementId(0));
-    //     edit.diff_node(old, new);
-
-    //     (create.mutations, edit.mutations)
-    // }
-}
-
-/*
-Scopes and ScopeArenas are never dropped internally.
-An app will always occupy as much memory as its biggest form.
-
-This means we need to handle all specifics of drop *here*. It's easier
-to reason about centralizing all the drop logic in one spot rather than scattered in each module.
-
-Broadly speaking, we want to use the remove_nodes method to clean up *everything*
-This will drop listeners, borrowed props, and hooks for all components.
-We need to do this in the correct order - nodes at the very bottom must be dropped first to release
-the borrow chain.
-
-Once the contents of the tree have been cleaned up, we can finally clean up the
-memory used by ScopeState itself.
-
-questions:
-should we build a vcomponent for the root?
-- probably - yes?
-- store the vcomponent in the root dom
-
-- 1: Use remove_nodes to use the ensure_drop_safety pathway to safely drop the tree
-- 2: Drop the ScopeState itself
-*/
-impl Drop for VirtualDom {
-    fn drop(&mut self) {
-        // the best way to drop the dom is to replace the root scope with a dud
-        // the diff infrastructure will then finish the rest
-        let scope = self.scopes.get_scope(ScopeId(0)).unwrap();
-
-        // todo: move the remove nodes method onto scopearena
-        // this will clear *all* scopes *except* the root scope
-        // let mut machine = DiffState::new(&self.scopes);
-        // machine.remove_nodes([scope.root_node()], false);
-
-        todo!("drop the root scope without leaking anything");
-
-        // Now, clean up the root scope
-        // safety: there are no more references to the root scope
-        let scope = unsafe { &mut *self.scopes.get_scope_raw(ScopeId(0)).unwrap() };
-        scope.reset();
-
-        // make sure there are no "live" components
-        for (_, scopeptr) in self.scopes.scopes.get_mut().drain() {
-            // safety: all scopes were made in the bump's allocator
-            // They are never dropped until now. The only way to drop is through Box.
-            let scope = unsafe { bumpalo::boxed::Box::from_raw(scopeptr) };
-            drop(scope);
-        }
-
-        for scopeptr in self.scopes.free_scopes.get_mut().drain(..) {
-            // safety: all scopes were made in the bump's allocator
-            // They are never dropped until now. The only way to drop is through Box.
-            let mut scope = unsafe { bumpalo::boxed::Box::from_raw(scopeptr) };
-            scope.reset();
-            drop(scope);
-        }
-    }
-}

+ 26 - 9
packages/core/src/any_props.rs

@@ -7,20 +7,33 @@ use crate::{
     Element,
 };
 
-pub trait AnyProps<'a> {
-    fn as_ptr(&self) -> *const ();
+/// A trait that essentially allows VComponentProps to be used generically
+pub unsafe trait AnyProps<'a> {
+    fn props_ptr(&self) -> *const ();
     fn render(&'a self, bump: &'a ScopeState) -> RenderReturn<'a>;
     unsafe fn memoize(&self, other: &dyn AnyProps) -> bool;
 }
 
-pub(crate) struct VComponentProps<'a, P, A, F: ComponentReturn<'a, A> = Element<'a>> {
+pub(crate) struct VProps<'a, P, A, F: ComponentReturn<'a, A> = Element<'a>> {
     pub render_fn: fn(Scope<'a, P>) -> F,
     pub memo: unsafe fn(&P, &P) -> bool,
     pub props: P,
-    pub _marker: PhantomData<A>,
+    // pub props: PropsAllocation<P>,
+    _marker: PhantomData<A>,
 }
 
-impl<'a, P, A, F: ComponentReturn<'a, A>> VComponentProps<'a, P, A, F> {
+enum PropsAllocation<P> {
+    /// If it's memoized, then the heap owns the props
+    Memoized(*mut P),
+
+    /// If it's borrowed, then the parent owns the props
+    Borrowed(P),
+}
+
+impl<'a, P, A, F> VProps<'a, P, A, F>
+where
+    F: ComponentReturn<'a, A>,
+{
     pub(crate) fn new(
         render_fn: fn(Scope<'a, P>) -> F,
         memo: unsafe fn(&P, &P) -> bool,
@@ -30,13 +43,17 @@ impl<'a, P, A, F: ComponentReturn<'a, A>> VComponentProps<'a, P, A, F> {
             render_fn,
             memo,
             props,
+            // props: PropsAllocation::Borrowed(props),
             _marker: PhantomData,
         }
     }
 }
 
-impl<'a, P, A, F: ComponentReturn<'a, A>> AnyProps<'a> for VComponentProps<'a, P, A, F> {
-    fn as_ptr(&self) -> *const () {
+unsafe impl<'a, P, A, F> AnyProps<'a> for VProps<'a, P, A, F>
+where
+    F: ComponentReturn<'a, A>,
+{
+    fn props_ptr(&self) -> *const () {
         &self.props as *const _ as *const ()
     }
 
@@ -45,8 +62,8 @@ impl<'a, P, A, F: ComponentReturn<'a, A>> AnyProps<'a> for VComponentProps<'a, P
     // you *must* make this check *before* calling this method
     // if your functions are not the same, then you will downcast a pointer into a different type (UB)
     unsafe fn memoize(&self, other: &dyn AnyProps) -> bool {
-        let real_other: &P = &*(other.as_ptr() as *const _ as *const P);
-        let real_us: &P = &*(self.as_ptr() as *const _ as *const P);
+        let real_other: &P = &*(other.props_ptr() as *const _ as *const P);
+        let real_us: &P = &*(self.props_ptr() as *const _ as *const P);
         (self.memo)(real_us, real_other)
     }
 

+ 6 - 9
packages/core/src/create.rs

@@ -70,11 +70,7 @@ impl VirtualDom {
                                 &template.dynamic_nodes[*id],
                                 *id,
                             ),
-                        DynamicNode::Text(VText {
-                            id: slot,
-                            value,
-                            inner,
-                        }) => {
+                        DynamicNode::Text(VText { id: slot, value }) => {
                             let id = self.next_element(template, template.template.node_paths[*id]);
                             slot.set(id);
                             mutations.push(CreateTextNode { value, id });
@@ -239,7 +235,7 @@ impl VirtualDom {
         idx: usize,
     ) -> usize {
         match &node {
-            DynamicNode::Text(VText { id, value, inner }) => {
+            DynamicNode::Text(VText { id, value }) => {
                 let new_id = self.next_element(template, template.template.node_paths[idx]);
                 id.set(new_id);
                 mutations.push(HydrateText {
@@ -251,9 +247,10 @@ impl VirtualDom {
             }
 
             DynamicNode::Component(component) => {
-                let scope = self
-                    .new_scope(unsafe { std::mem::transmute(component.props.get()) })
-                    .id;
+                let props = component.props.replace(None).unwrap();
+                let prop_ptr = unsafe { std::mem::transmute(props.as_ref()) };
+                let scope = self.new_scope(prop_ptr).id;
+                component.props.replace(Some(props));
 
                 component.scope.set(Some(scope));
 

+ 124 - 84
packages/core/src/diff.rs

@@ -5,7 +5,8 @@ use crate::innerlude::{Mutations, VComponent, VFragment, VText};
 use crate::virtual_dom::VirtualDom;
 use crate::{Attribute, AttributeValue, TemplateNode};
 
-use crate::any_props::VComponentProps;
+use crate::any_props::VProps;
+use DynamicNode::*;
 
 use crate::mutations::Mutation;
 use crate::nodes::{DynamicNode, Template, TemplateId};
@@ -77,7 +78,7 @@ impl<'b> VirtualDom {
         use RenderReturn::{Async, Sync};
         match (left, right) {
             // diff
-            (Sync(Some(l)), Sync(Some(r))) => self.diff_node(m, l, r),
+            (Sync(Some(l)), Sync(Some(r))) => self.diff_vnode(m, l, r),
 
             // remove old with placeholder
             (Sync(Some(l)), Sync(None)) | (Sync(Some(l)), Async(_)) => {
@@ -91,7 +92,7 @@ impl<'b> VirtualDom {
             (Sync(None), Sync(Some(_))) => {}
             (Async(_), Sync(Some(v))) => {}
 
-            // nothing...
+            // nothing... just transfer the placeholders over
             (Async(_), Async(_))
             | (Sync(None), Sync(None))
             | (Sync(None), Async(_))
@@ -99,23 +100,20 @@ impl<'b> VirtualDom {
         }
     }
 
-    pub fn diff_node(
+    pub fn diff_vnode(
         &mut self,
         muts: &mut Mutations<'b>,
         left_template: &'b VNode<'b>,
         right_template: &'b VNode<'b>,
     ) {
         if left_template.template.id != right_template.template.id {
-            // do a light diff of the roots nodes.
-            todo!("lightly diff roots and replace");
-            return;
+            return self.light_diff_templates(muts, left_template, right_template);
         }
 
-        for (_idx, (left_attr, right_attr)) in left_template
+        for (left_attr, right_attr) in left_template
             .dynamic_attrs
             .iter()
             .zip(right_template.dynamic_attrs.iter())
-            .enumerate()
         {
             // Move over the ID from the old to the new
             right_attr
@@ -135,67 +133,76 @@ impl<'b> VirtualDom {
             }
         }
 
-        for (idx, (left_node, right_node)) in left_template
+        for (left_node, right_node) in left_template
             .dynamic_nodes
             .iter()
             .zip(right_template.dynamic_nodes.iter())
-            .enumerate()
         {
-            use DynamicNode::*;
-
             match (left_node, right_node) {
                 (Component(left), Component(right)) => self.diff_vcomponent(muts, left, right),
                 (Text(left), Text(right)) => self.diff_vtext(muts, left, right),
                 (Fragment(left), Fragment(right)) => self.diff_vfragment(muts, left, right),
-
-                (Placeholder(_), Placeholder(_)) => todo!(),
-
-                // Make sure to drop all the fragment children properly
-                (DynamicNode::Fragment { .. }, right) => todo!(),
-
-                (Text(left), right) => {
-                    todo!()
-                    // let m = self.create_dynamic_node(muts, right_template, right, idx);
-                    // muts.push(Mutation::ReplaceWith { id: lid.get(), m });
-                }
-                (Placeholder(_), _) => todo!(),
-                // Make sure to drop the component properly
-                (Component { .. }, right) => {
-                    // remove all the component roots except for the first
-                    // replace the first with the new node
-                    let m = self.create_dynamic_node(muts, right_template, right, idx);
-                    todo!()
-                }
+                (Placeholder(left), Placeholder(right)) => right.set(left.get()),
+                _ => self.replace(muts, left_template, right_template, left_node, right_node),
             };
         }
     }
 
+    fn replace(
+        &mut self,
+        muts: &mut Mutations<'b>,
+        left_template: &'b VNode<'b>,
+        right_template: &'b VNode<'b>,
+        left: &'b DynamicNode<'b>,
+        right: &'b DynamicNode<'b>,
+    ) {
+    }
+
     fn diff_vcomponent(
         &mut self,
         muts: &mut Mutations<'b>,
         left: &'b VComponent<'b>,
         right: &'b VComponent<'b>,
     ) {
-        let left_props = unsafe { &mut *left.props.get() };
-        let right_props = unsafe { &mut *right.props.get() };
+        // Due to how templates work, we should never get two different components. The only way we could enter
+        // this codepath is through "light_diff", but we check there that the pointers are the same
+        assert_eq!(left.render_fn, right.render_fn);
 
-        // Ensure these two props are of the same component type
-        match left_props.as_ptr() == right_props.as_ptr() {
-            true => {
-                //
-                if left.static_props {
-                    let props_are_same = unsafe { left_props.memoize(right_props) };
-
-                    if props_are_same {
-                        //
-                    } else {
-                        //
-                    }
-                } else {
-                }
-            }
-            false => todo!(),
+        /*
+
+
+
+        let left = rsx!{ Component {} }
+        let right = rsx!{ Component {} }
+
+
+
+        */
+
+        // Make sure the new vcomponent has the right scopeid associated to it
+        let scope_id = left.scope.get().unwrap();
+        right.scope.set(Some(scope_id));
+
+        // copy out the box for both
+        let old = left.props.replace(None).unwrap();
+        let new = right.props.replace(None).unwrap();
+
+        // If the props are static, then we try to memoize by setting the new with the old
+        // The target scopestate still has the reference to the old props, so there's no need to update anything
+        // This also implicitly drops the new props since they're not used
+        if left.static_props && unsafe { old.memoize(new.as_ref()) } {
+            return right.props.set(Some(old));
         }
+
+        // If the props are dynamic *or* the memoization failed, then we need to diff the props
+
+        // First, move over the props from the old to the new, dropping old props in the process
+        self.scopes[scope_id.0].props = unsafe { std::mem::transmute(new.as_ref()) };
+        right.props.set(Some(new));
+
+        // Now run the component and diff it
+        self.run_scope(scope_id);
+        self.diff_scope(muts, scope_id);
     }
 
     /// Lightly diff the two templates, checking only their roots.
@@ -236,44 +243,23 @@ impl<'b> VirtualDom {
     ///     Component { ..props }
     /// }
     /// ```
-    fn light_diff_tempaltes(
+    fn light_diff_templates(
         &mut self,
         muts: &mut Mutations<'b>,
         left: &'b VNode<'b>,
         right: &'b VNode<'b>,
-    ) -> bool {
-        if left.template.roots.len() != right.template.roots.len() {
-            return false;
-        }
-
-        let mut components = vec![];
-
-        // run through the components, ensuring they're the same
-        for (l, r) in left.template.roots.iter().zip(right.template.roots.iter()) {
-            match (l, r) {
-                (TemplateNode::Dynamic(l), TemplateNode::Dynamic(r)) => {
-                    components.push(match (&left.dynamic_nodes[*l], &right.dynamic_nodes[*r]) {
-                        (DynamicNode::Component(l), DynamicNode::Component(r)) => {
-                            let l_props = unsafe { &*l.props.get() };
-                            let r_props = unsafe { &*r.props.get() };
-
-                            (l, r)
-                        }
-                        _ => return false,
-                    })
-                }
-                _ => return false,
-            }
-        }
-
-        // run through the components, diffing them
-        for (l, r) in components {
-            self.diff_vcomponent(muts, l, r);
+    ) {
+        if let Some(components) = matching_components(left, right) {
+            components
+                .into_iter()
+                .for_each(|(l, r)| self.diff_vcomponent(muts, l, r))
         }
-
-        true
     }
 
+    /// Diff the two text nodes
+    ///
+    /// This just moves the ID of the old node over to the new node, and then sets the text of the new node if it's
+    /// different.
     fn diff_vtext(&mut self, muts: &mut Mutations<'b>, left: &'b VText<'b>, right: &'b VText<'b>) {
         right.id.set(left.id.get());
         if left.value != right.value {
@@ -297,6 +283,7 @@ impl<'b> VirtualDom {
         //         todo!()
         //     }
         //     (_, []) => {
+        //         // if this fragment is the only child of its parent, then we can use the "RemoveAllChildren" mutation
         //         todo!()
         //     }
         //     _ => {
@@ -319,8 +306,6 @@ impl<'b> VirtualDom {
         //         }
         //     }
         // }
-
-        todo!()
     }
 
     // Diff children that are not keyed.
@@ -351,7 +336,7 @@ impl<'b> VirtualDom {
         }
 
         for (new, old) in new.iter().zip(old.iter()) {
-            self.diff_node(muts, old, new);
+            self.diff_vnode(muts, old, new);
         }
     }
 
@@ -693,3 +678,58 @@ impl<'b> VirtualDom {
         //
     }
 }
+
+fn matching_components<'a>(
+    left: &'a VNode<'a>,
+    right: &'a VNode<'a>,
+) -> Option<Vec<(&'a VComponent<'a>, &'a VComponent<'a>)>> {
+    if left.template.roots.len() != right.template.roots.len() {
+        return None;
+    }
+
+    // run through the components, ensuring they're the same
+    left.template
+        .roots
+        .iter()
+        .zip(right.template.roots.iter())
+        .map(|(l, r)| {
+            let (l, r) = match (l, r) {
+                (TemplateNode::Dynamic(l), TemplateNode::Dynamic(r)) => (l, r),
+                _ => return None,
+            };
+
+            let (l, r) = match (&left.dynamic_nodes[*l], &right.dynamic_nodes[*r]) {
+                (Component(l), Component(r)) => (l, r),
+                _ => return None,
+            };
+
+            (l.render_fn == r.render_fn).then(|| (l, r))
+        })
+        .collect()
+}
+
+/// We can apply various optimizations to dynamic nodes that are the single child of their parent.
+///
+/// IE
+///  - for text - we can use SetTextContent
+///  - for clearning children we can use RemoveChildren
+///  - for appending children we can use AppendChildren
+fn is_dyn_node_only_child(node: &VNode, idx: usize) -> bool {
+    let path = node.template.node_paths[idx];
+
+    // use a loop to index every static node's children until the path has run out
+    // only break if the last path index is a dynamic node
+    let mut static_node = &node.template.roots[path[0] as usize];
+
+    for i in 1..path.len() - 1 {
+        match static_node {
+            TemplateNode::Element { children, .. } => static_node = &children[path[i] as usize],
+            _ => return false,
+        }
+    }
+
+    match static_node {
+        TemplateNode::Element { children, .. } => children.len() == 1,
+        _ => false,
+    }
+}

+ 9 - 11
packages/core/src/factory.rs

@@ -1,4 +1,5 @@
 use std::{
+    any::Any,
     cell::{Cell, RefCell},
     fmt::Arguments,
 };
@@ -8,7 +9,7 @@ use bumpalo::Bump;
 use std::future::Future;
 
 use crate::{
-    any_props::{AnyProps, VComponentProps},
+    any_props::{AnyProps, VProps},
     arena::ElementId,
     innerlude::{DynamicNode, EventHandler, VComponent, VFragment, VText},
     Attribute, AttributeValue, Element, LazyNodes, Properties, Scope, ScopeState, VNode,
@@ -21,7 +22,6 @@ impl ScopeState {
         DynamicNode::Text(VText {
             id: Cell::new(ElementId(0)),
             value: text,
-            inner: false,
         })
     }
 
@@ -76,10 +76,11 @@ impl ScopeState {
         P: Properties + 'a,
     {
         let as_component = component;
-        let vcomp = VComponentProps::new(as_component, P::memoize, props);
-        let as_dyn = self.bump().alloc(vcomp) as &mut dyn AnyProps;
-        let detached_dyn: *mut dyn AnyProps = unsafe { std::mem::transmute(as_dyn) };
+        let vcomp = VProps::new(as_component, P::memoize, props);
+        let as_dyn: Box<dyn AnyProps<'a>> = Box::new(vcomp);
+        let extended: Box<dyn AnyProps> = unsafe { std::mem::transmute(as_dyn) };
 
+        // let as_dyn: &dyn AnyProps = self.bump().alloc(vcomp);
         // todo: clean up borrowed props
         // if !P::IS_STATIC {
         //     let vcomp = &*vcomp;
@@ -89,8 +90,9 @@ impl ScopeState {
 
         DynamicNode::Component(VComponent {
             name: fn_name,
+            render_fn: component as *const (),
             static_props: P::IS_STATIC,
-            props: Cell::new(detached_dyn),
+            props: Cell::new(Some(extended)),
             placeholder: Cell::new(None),
             scope: Cell::new(None),
         })
@@ -178,7 +180,6 @@ impl<'a, 'b> IntoDynNode<'a> for LazyNodes<'a, 'b> {
     fn into_vnode(self, cx: &'a ScopeState) -> DynamicNode<'a> {
         DynamicNode::Fragment(VFragment {
             nodes: cx.bump().alloc([self.call(cx)]),
-            inner: false,
         })
     }
 }
@@ -248,10 +249,7 @@ where
 
         match children.len() {
             0 => DynamicNode::Placeholder(Cell::new(ElementId(0))),
-            _ => DynamicNode::Fragment(VFragment {
-                inner: false,
-                nodes: children,
-            }),
+            _ => DynamicNode::Fragment(VFragment { nodes: children }),
         }
     }
 }

+ 13 - 55
packages/core/src/nodes.rs

@@ -131,26 +131,35 @@ impl<'a> DynamicNode<'a> {
     }
 }
 
-#[derive(Debug)]
 pub struct VComponent<'a> {
     pub name: &'static str,
     pub static_props: bool,
-    pub props: Cell<*mut dyn AnyProps<'a>>,
     pub placeholder: Cell<Option<ElementId>>,
     pub scope: Cell<Option<ScopeId>>,
+    pub props: Cell<Option<Box<dyn AnyProps<'a> + 'a>>>,
+    pub render_fn: *const (),
+}
+
+impl<'a> std::fmt::Debug for VComponent<'a> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("VComponent")
+            .field("name", &self.name)
+            .field("static_props", &self.static_props)
+            .field("placeholder", &self.placeholder)
+            .field("scope", &self.scope)
+            .finish()
+    }
 }
 
 #[derive(Debug)]
 pub struct VText<'a> {
     pub id: Cell<ElementId>,
     pub value: &'a str,
-    pub inner: bool,
 }
 
 #[derive(Debug)]
 pub struct VFragment<'a> {
     pub nodes: &'a [VNode<'a>],
-    pub inner: bool,
 }
 
 #[derive(Debug)]
@@ -268,54 +277,3 @@ fn what_are_the_sizes() {
     dbg!(std::mem::size_of::<Template>());
     dbg!(std::mem::size_of::<TemplateNode>());
 }
-
-/*
-
-
-SSR includes data-id which allows O(1) hydration
-
-
-we read the edit stream dn then we can just rehydare
-
-
-
-ideas:
-- IDs for lookup
-- use edit stream to hydrate
-- write comments to dom that specify size of children
-
-IDs for lookups
-- adds noise to generated html
-- doesnt work for text nodes
-- suspense could cause ordering to be weird
-
-Names for lookups:
-- label each root or something with the template name
-- label each dynamic node with a path
-- noisy too
-- allows reverse lookups
-
-Ideal:
-- no noise in the dom
-- fast, ideally O(1)
-- able to pick apart text nodes that get merged during SSR
-
-
---> render vdom
---> traverse vdom and real dom simultaneously
-
-IE
-
-div {
-    div {
-        div {
-            "thing"
-        }
-    }
-}
-
-
-
-
-
-*/

+ 8 - 1
packages/core/src/scope_arena.rs

@@ -1,6 +1,7 @@
 use crate::{
     any_props::AnyProps,
     bump_frame::BumpFrame,
+    diff::DirtyScope,
     factory::RenderReturn,
     innerlude::{SuspenseId, SuspenseLeaf},
     scheduler::RcWake,
@@ -16,7 +17,7 @@ use std::{
 };
 
 impl VirtualDom {
-    pub(super) fn new_scope(&mut self, props: *mut dyn AnyProps<'static>) -> &mut ScopeState {
+    pub(super) fn new_scope(&mut self, props: *const dyn AnyProps<'static>) -> &mut ScopeState {
         let parent = self.acquire_current_scope_raw();
         let entry = self.scopes.vacant_entry();
         let height = unsafe { parent.map(|f| (*f).height).unwrap_or(0) + 1 };
@@ -125,6 +126,12 @@ impl VirtualDom {
         // And move the render generation forward by one
         scope.render_cnt.set(scope.render_cnt.get() + 1);
 
+        // remove this scope from dirty scopes
+        self.dirty_scopes.remove(&DirtyScope {
+            height: scope.height,
+            id: scope.id,
+        });
+
         // rebind the lifetime now that its stored internally
         unsafe { mem::transmute(alloced) }
     }

+ 2 - 2
packages/core/src/virtual_dom.rs

@@ -3,7 +3,7 @@
 //! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
 
 use crate::{
-    any_props::VComponentProps,
+    any_props::VProps,
     arena::ElementId,
     arena::ElementRef,
     diff::DirtyScope,
@@ -240,7 +240,7 @@ impl VirtualDom {
             finished_fibers: Vec::new(),
         };
 
-        let root = dom.new_scope(Box::into_raw(Box::new(VComponentProps::new(
+        let root = dom.new_scope(Box::leak(Box::new(VProps::new(
             root,
             |_, _| unreachable!(),
             root_props,