Browse Source

wip: more work on suspense and documentation

Jonathan Kelley 4 years ago
parent
commit
37ed4bed8c

+ 5 - 5
packages/core/src/arena.rs

@@ -27,7 +27,7 @@ impl SharedArena {
 
     /// THIS METHOD IS CURRENTLY UNSAFE
     /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS
-    pub fn try_get(&self, idx: ScopeIdx) -> Result<&Scope> {
+    pub fn try_get(&self, idx: ScopeId) -> Result<&Scope> {
         let inner = unsafe { &*self.components.get() };
         let scope = inner.get(idx);
         scope.ok_or_else(|| Error::FatalInternal("Scope not found"))
@@ -35,7 +35,7 @@ impl SharedArena {
 
     /// THIS METHOD IS CURRENTLY UNSAFE
     /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS
-    pub fn try_get_mut(&self, idx: ScopeIdx) -> Result<&mut Scope> {
+    pub fn try_get_mut(&self, idx: ScopeId) -> Result<&mut Scope> {
         let inner = unsafe { &mut *self.components.get() };
         let scope = inner.get_mut(idx);
         scope.ok_or_else(|| Error::FatalInternal("Scope not found"))
@@ -59,7 +59,7 @@ impl SharedArena {
 
     pub fn with_scope<'b, O: 'static>(
         &'b self,
-        _id: ScopeIdx,
+        _id: ScopeId,
         _f: impl FnOnce(&'b mut Scope) -> O,
     ) -> Result<O> {
         todo!()
@@ -69,13 +69,13 @@ impl SharedArena {
     // this is useful for merging lifetimes
     pub fn with_scope_vnode<'b>(
         &self,
-        _id: ScopeIdx,
+        _id: ScopeId,
         _f: impl FnOnce(&mut Scope) -> &VNode<'b>,
     ) -> Result<&VNode<'b>> {
         todo!()
     }
 
-    pub fn try_remove(&self, id: ScopeIdx) -> Result<Scope> {
+    pub fn try_remove(&self, id: ScopeId) -> Result<Scope> {
         let inner = unsafe { &mut *self.components.get() };
         inner
             .remove(id)

+ 54 - 17
packages/core/src/context.rs

@@ -1,6 +1,5 @@
 use crate::innerlude::*;
 
-use bumpalo::Bump;
 use futures_util::FutureExt;
 
 use std::any::Any;
@@ -12,7 +11,6 @@ use std::{
     cell::RefCell,
     future::Future,
     ops::Deref,
-    pin::Pin,
     rc::{Rc, Weak},
 };
 
@@ -34,13 +32,20 @@ use std::{
 ///     }
 /// }
 /// ```
-// todo: force lifetime of source into T as a valid lifetime too
-// it's definitely possible, just needs some more messing around
+///
+/// ## Available Methods:
+/// - render
+/// - use_hook
+/// - use_task
+/// - use_suspense
+/// - submit_task
+/// - children
+/// - use_effect
+///
 pub struct Context<'src, T> {
     pub props: &'src T,
     pub scope: &'src Scope,
 }
-// pub type PinnedTask = Pin<Box<dyn Future<Output = ()>>>;
 
 impl<'src, T> Copy for Context<'src, T> {}
 impl<'src, T> Clone for Context<'src, T> {
@@ -52,9 +57,10 @@ impl<'src, T> Clone for Context<'src, T> {
     }
 }
 
+// We currently deref to props, but it might make more sense to deref to Scope?
+// This allows for code that takes cx.xyz instead of cx.props.xyz
 impl<'a, T> Deref for Context<'a, T> {
     type Target = &'a T;
-
     fn deref(&self) -> &Self::Target {
         &self.props
     }
@@ -62,14 +68,42 @@ impl<'a, T> Deref for Context<'a, T> {
 
 impl<'src, P> Context<'src, P> {
     /// 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
+    /// const App: FC<()> = |cx| {
+    ///     cx.render(rsx!{
+    ///         CustomCard {
+    ///             h1 {}
+    ///             p {}
+    ///         }
+    ///     })
+    /// }
+    ///
+    /// const CustomCard: FC<()> = |cx| {
+    ///     cx.render(rsx!{
+    ///         div {
+    ///             h1 {"Title card"}
+    ///             {cx.children()}
+    ///         }
+    ///     })
+    /// }
+    /// ```
     pub fn children(&self) -> &'src [VNode<'src>] {
-        // We're re-casting the nodes back out
-        // They don't really have a static lifetime
-        unsafe {
-            let scope = self.scope;
-            let nodes = scope.child_nodes;
-            nodes
-        }
+        self.scope.child_nodes
     }
 
     /// Create a subscription that schedules a future render for the reference component
@@ -227,7 +261,10 @@ Any function prefixed with "use" should not be called conditionally.
 
                 let ty = TypeId::of::<T>();
                 while let Some(inner) = scope {
-                    log::debug!("Searching {:#?} for valid shared_context", inner.arena_idx);
+                    log::debug!(
+                        "Searching {:#?} for valid shared_context",
+                        inner.our_arena_idx
+                    );
                     let shared_contexts = inner.shared_contexts.borrow();
 
                     if let Some(shared_cx) = shared_contexts.get(&ty) {
@@ -241,7 +278,7 @@ Any function prefixed with "use" should not be called conditionally.
                         hook.par = Some(rc);
                         return Ok(hook.par.as_ref().unwrap());
                     } else {
-                        match inner.parent {
+                        match inner.parent_idx {
                             Some(parent_id) => {
                                 let parent = inner
                                     .arena_link
@@ -324,7 +361,7 @@ Any function prefixed with "use" should not be called conditionally.
 
                 let slot = task_dump.clone();
                 let update = self.schedule_update();
-                let originator = self.scope.arena_idx.clone();
+                let originator = self.scope.our_arena_idx.clone();
 
                 self.submit_task(Box::pin(task_fut.then(move |output| async move {
                     *slot.as_ref().borrow_mut() = Some(output);
@@ -411,7 +448,7 @@ impl<'src, P> Context<'src, P> {
                     }
                 });
 
-                let originator = self.scope.arena_idx.clone();
+                let originator = self.scope.our_arena_idx.clone();
                 let task_fut = task_initializer();
                 let domnode = dom_node_id.clone();
 

+ 5 - 5
packages/core/src/diff.rs

@@ -75,10 +75,10 @@ pub struct DiffMachine<'real, 'bump, Dom: RealDom<'bump>> {
     pub edits: DomEditor<'real, 'bump>,
     pub components: &'bump SharedArena,
     pub task_queue: &'bump TaskQueue,
-    pub cur_idx: ScopeIdx,
-    pub diffed: FxHashSet<ScopeIdx>,
+    pub cur_idx: ScopeId,
+    pub diffed: FxHashSet<ScopeId>,
     pub event_queue: EventQueue,
-    pub seen_nodes: FxHashSet<ScopeIdx>,
+    pub seen_nodes: FxHashSet<ScopeId>,
 }
 
 impl<'real, 'bump, Dom> DiffMachine<'real, 'bump, Dom>
@@ -89,7 +89,7 @@ where
         edits: &'real mut Vec<DomEdit<'bump>>,
         dom: &'real mut Dom,
         components: &'bump SharedArena,
-        cur_idx: ScopeIdx,
+        cur_idx: ScopeId,
         event_queue: EventQueue,
         task_queue: &'bump TaskQueue,
     ) -> Self {
@@ -488,7 +488,7 @@ impl<'a, 'bump, Dom: RealDom<'bump>> DiffMachine<'a, 'bump, Dom> {
     ///
     /// Calling this will run the destuctors on all hooks in the tree.
     /// It will also add the destroyed nodes to the `seen_nodes` cache to prevent them from being renderered.
-    fn destroy_scopes(&mut self, old_scope: ScopeIdx) {
+    fn destroy_scopes(&mut self, old_scope: ScopeId) {
         let mut nodes_to_delete = vec![old_scope];
         let mut scopes_to_explore = vec![old_scope];
 

+ 26 - 11
packages/core/src/editor.rs

@@ -1,5 +1,3 @@
-//! Serialization
-//! -------------
 //!
 //!
 //!
@@ -7,7 +5,7 @@
 //!
 //!
 
-use crate::{innerlude::ScopeIdx, RealDomNode};
+use crate::{innerlude::ScopeId, RealDomNode};
 
 /// The `DomEditor` provides an imperative interface for the Diffing algorithm to plan out its changes.
 ///
@@ -18,6 +16,7 @@ use crate::{innerlude::ScopeIdx, RealDomNode};
 pub struct DomEditor<'real, 'bump> {
     pub edits: &'real mut Vec<DomEdit<'bump>>,
 }
+
 use DomEdit::*;
 impl<'real, 'bump> DomEditor<'real, 'bump> {
     pub fn new(edits: &'real mut Vec<DomEdit<'bump>>) -> Self {
@@ -29,35 +28,44 @@ impl<'real, 'bump> DomEditor<'real, 'bump> {
         let id = root.as_u64();
         self.edits.push(PushRoot { id });
     }
+
+    #[inline]
     pub(crate) fn pop(&mut self) {
         self.edits.push(PopRoot {});
     }
 
     // Add Nodes to the dom
     // add m nodes from the stack
+    #[inline]
     pub(crate) fn append_children(&mut self, many: u32) {
         self.edits.push(AppendChildren { many });
     }
 
     // replace the n-m node on the stack with the m nodes
     // ends with the last element of the chain on the top of the stack
+    #[inline]
     pub(crate) fn replace_with(&mut self, many: u32) {
         self.edits.push(ReplaceWith { many });
     }
 
     // Remove Nodesfrom the dom
+    #[inline]
     pub(crate) fn remove(&mut self) {
         self.edits.push(Remove);
     }
+
+    #[inline]
     pub(crate) fn remove_all_children(&mut self) {
         self.edits.push(RemoveAllChildren);
     }
 
     // Create
+    #[inline]
     pub(crate) fn create_text_node(&mut self, text: &'bump str, id: RealDomNode) {
         let id = id.as_u64();
         self.edits.push(CreateTextNode { text, id });
     }
+
     pub(crate) fn create_element(
         &mut self,
         tag: &'static str,
@@ -81,25 +89,30 @@ impl<'real, 'bump> DomEditor<'real, 'bump> {
     pub(crate) fn new_event_listener(
         &mut self,
         event: &'static str,
-        scope: ScopeIdx,
+        scope: ScopeId,
         element_id: usize,
         realnode: RealDomNode,
     ) {
         self.edits.push(NewEventListener {
             scope,
-            event,
-            idx: element_id,
-            node: realnode.as_u64(),
+            event_name: event,
+            element_id,
+            mounted_node_id: realnode.as_u64(),
         });
     }
+
+    #[inline]
     pub(crate) fn remove_event_listener(&mut self, event: &'static str) {
         self.edits.push(RemoveEventListener { event });
     }
 
     // modify
+    #[inline]
     pub(crate) fn set_text(&mut self, text: &'bump str) {
         self.edits.push(SetText { text });
     }
+
+    #[inline]
     pub(crate) fn set_attribute(
         &mut self,
         field: &'static str,
@@ -108,6 +121,8 @@ impl<'real, 'bump> DomEditor<'real, 'bump> {
     ) {
         self.edits.push(SetAttribute { field, value, ns });
     }
+
+    #[inline]
     pub(crate) fn remove_attribute(&mut self, name: &'static str) {
         self.edits.push(RemoveAttribute { name });
     }
@@ -151,10 +166,10 @@ pub enum DomEdit<'bump> {
         id: u64,
     },
     NewEventListener {
-        event: &'static str,
-        scope: ScopeIdx,
-        node: u64,
-        idx: usize,
+        event_name: &'static str,
+        scope: ScopeId,
+        mounted_node_id: u64,
+        element_id: usize,
     },
     RemoveEventListener {
         event: &'static str,

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

@@ -4,17 +4,14 @@
 //! 3rd party renderers are responsible for converting their native events into these virtual event types. Events might
 //! be heavy or need to interact through FFI, so the events themselves are designed to be lazy.
 
-use std::{
-    cell::{Cell, RefCell},
-    rc::Rc,
-};
+use std::{cell::Cell, rc::Rc};
 
-use crate::innerlude::{RealDomNode, ScopeIdx};
+use crate::innerlude::{RealDomNode, ScopeId};
 
 #[derive(Debug)]
 pub struct EventTrigger {
     /// The originator of the event trigger
-    pub originator: ScopeIdx,
+    pub originator: ScopeId,
 
     /// The optional real node associated with the trigger
     pub real_node_id: Option<RealDomNode>,
@@ -27,7 +24,7 @@ pub struct EventTrigger {
 }
 
 impl EventTrigger {
-    pub fn new_from_task(originator: ScopeIdx, hook_idx: usize) -> Self {
+    pub fn new_from_task(originator: ScopeId, hook_idx: usize) -> Self {
         Self {
             originator,
             event: VirtualEvent::AsyncEvent { hook_idx },
@@ -74,7 +71,7 @@ pub enum EventPriority {
 impl EventTrigger {
     pub fn new(
         event: VirtualEvent,
-        scope: ScopeIdx,
+        scope: ScopeId,
         mounted_dom_id: Option<RealDomNode>,
         priority: EventPriority,
     ) -> Self {
@@ -184,7 +181,7 @@ pub mod on {
                         Listener {
                             event: stringify!($name),
                             mounted_node: bump.alloc(Cell::new(RealDomNode::empty())),
-                            scope: c.scope_ref.arena_idx,
+                            scope: c.scope_ref.our_arena_idx,
                             callback: bump.alloc(move |evt: VirtualEvent| match evt {
                                 VirtualEvent::$wrapper(event) => callback(event),
                                 _ => unreachable!("Downcasted VirtualEvent to wrong event type - this is an internal bug!")

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

@@ -1,4 +1,4 @@
-#![allow(non_snake_case, dead_code, unused_must_use, unreachable_code)]
+#![allow(non_snake_case)]
 //! Dioxus Core
 //! ----------
 //!
@@ -11,7 +11,7 @@
 
 pub use crate::innerlude::{
     format_args_f, html, rsx, DioxusElement, DomEdit, EventTrigger, LazyNodes, NodeFactory,
-    Properties, RealDom, RealDomNode, ScopeIdx, VNode, VNodeKind, VirtualDom, VirtualEvent, FC,
+    Properties, RealDom, RealDomNode, ScopeId, VNode, VNodeKind, VirtualDom, VirtualEvent, FC,
 };
 
 pub mod prelude {

+ 64 - 42
packages/core/src/nodes.rs

@@ -5,10 +5,10 @@
 
 use crate::{
     events::VirtualEvent,
-    innerlude::{Context, Properties, RealDomNode, Scope, ScopeIdx, FC},
+    innerlude::{Context, Properties, RealDomNode, Scope, ScopeId, FC},
 };
 use std::{
-    cell::{Cell, RefCell},
+    cell::Cell,
     fmt::{Arguments, Debug, Formatter},
     marker::PhantomData,
     rc::Rc,
@@ -87,7 +87,7 @@ pub struct Attribute<'a> {
 pub struct Listener<'bump> {
     /// The type of event to listen for.
     pub(crate) event: &'static str,
-    pub scope: ScopeIdx,
+    pub scope: ScopeId,
     pub mounted_node: &'bump Cell<RealDomNode>,
     pub(crate) callback: &'bump dyn FnMut(VirtualEvent),
 }
@@ -95,7 +95,7 @@ pub struct Listener<'bump> {
 /// Virtual Components for custom user-defined components
 /// Only supports the functional syntax
 pub struct VComponent<'src> {
-    pub ass_scope: Cell<Option<ScopeIdx>>,
+    pub ass_scope: Cell<Option<ScopeId>>,
     pub(crate) caller: Rc<dyn Fn(&Scope) -> VNode>,
     pub(crate) children: &'src [VNode<'src>],
     pub(crate) comparator: Option<&'src dyn Fn(&VComponent) -> bool>,
@@ -328,6 +328,26 @@ impl<'a> NodeFactory<'a> {
     }
 }
 
+/// 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:
+/// ```
+/// impl IntoIterator<Item = impl IntoVNode<'a>>
+/// ```
+///
+/// As such, all node creation must go through the factory, which is only availble in the component context.
+/// These strict requirements make it possible to manage lifetimes and state.
+pub trait IntoVNode<'a> {
+    fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>;
+}
+
+// For the case where a rendered VNode is passed into the rsx! macro through curly braces
 impl<'a> IntoIterator for VNode<'a> {
     type Item = VNode<'a>;
     type IntoIter = std::iter::Once<Self::Item>;
@@ -335,25 +355,53 @@ impl<'a> IntoIterator for VNode<'a> {
         std::iter::once(self)
     }
 }
+
+// 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
     }
 }
 
+// For the case where a rendered VNode is by reference passed into the rsx! macro through curly braces
+// This behavior is designed for the cx.children method where child nodes are passed by reference.
+//
+// Designed to support indexing
 impl<'a> IntoVNode<'a> for &VNode<'a> {
     fn into_vnode(self, _: NodeFactory<'a>) -> VNode<'a> {
-        self.clone()
-    }
-}
+        let kind = match &self.kind {
+            VNodeKind::Element(element) => VNodeKind::Element(element),
+            VNodeKind::Text(old) => VNodeKind::Text(VText {
+                text: old.text,
+                is_static: old.is_static,
+            }),
+            VNodeKind::Fragment(fragment) => VNodeKind::Fragment(VFragment {
+                children: fragment.children,
+                is_static: fragment.is_static,
+            }),
+            VNodeKind::Component(component) => VNodeKind::Component(component),
 
-pub trait IntoVNode<'a> {
-    fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>;
+            // todo: it doesn't make much sense to pass in suspended nodes
+            // I think this is right but I'm not too sure.
+            VNodeKind::Suspended { node } => VNodeKind::Suspended { node: node.clone() },
+        };
+        VNode {
+            kind,
+            dom_id: self.dom_id.clone(),
+            key: self.key.clone(),
+        }
+    }
 }
 
-// Wrap the the node-builder closure in a concrete type.
-// ---
-// This is a bit of a hack to implement the IntoVNode trait for closure types.
+/// 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
+/// LazyNodes::new(|f| f.element("div", [], [], [] None))
+/// ```
 pub struct LazyNodes<'a, G>
 where
     G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
@@ -374,11 +422,7 @@ where
     }
 }
 
-// Cover the cases where nodes are used by macro.
-// Likely used directly.
-// ---
-//  let nodes = rsx!{ ... };
-//  rsx! { {nodes } }
+// Our blanket impl
 impl<'a, G> IntoVNode<'a> for LazyNodes<'a, G>
 where
     G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
@@ -388,7 +432,7 @@ where
     }
 }
 
-// Required because anything that enters brackets in the rsx! macro needs to implement IntoIterator
+// Our blanket impl
 impl<'a, G> IntoIterator for LazyNodes<'a, G>
 where
     G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
@@ -400,12 +444,14 @@ where
     }
 }
 
+// Conveniently, we also support "null" (nothing) passed in
 impl IntoVNode<'_> for () {
     fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
         cx.fragment_from_iter(None as Option<VNode>)
     }
 }
 
+// Conveniently, we also support "None"
 impl IntoVNode<'_> for Option<()> {
     fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
         cx.fragment_from_iter(None as Option<VNode>)
@@ -418,30 +464,6 @@ impl Debug for NodeFactory<'_> {
     }
 }
 
-// it's okay to clone because vnodes are just references to places into the bump
-impl<'a> Clone for VNode<'a> {
-    fn clone(&self) -> Self {
-        let kind = match &self.kind {
-            VNodeKind::Element(element) => VNodeKind::Element(element),
-            VNodeKind::Text(old) => VNodeKind::Text(VText {
-                text: old.text,
-                is_static: old.is_static,
-            }),
-            VNodeKind::Fragment(fragment) => VNodeKind::Fragment(VFragment {
-                children: fragment.children,
-                is_static: fragment.is_static,
-            }),
-            VNodeKind::Component(component) => VNodeKind::Component(component),
-            VNodeKind::Suspended { node } => VNodeKind::Suspended { node: node.clone() },
-        };
-        VNode {
-            kind,
-            dom_id: self.dom_id.clone(),
-            key: self.key.clone(),
-        }
-    }
-}
-
 impl Debug for VNode<'_> {
     fn fmt(&self, s: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
         match &self.kind {

+ 27 - 44
packages/core/src/scope.rs

@@ -22,53 +22,36 @@ pub type WrappedCaller = dyn for<'b> Fn(&'b Scope) -> VNode<'b>;
 /// 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.
 pub struct Scope {
-    // The parent's scope ID
-    pub parent: Option<ScopeIdx>,
+    // Book-keeping about the arena
+    pub(crate) parent_idx: Option<ScopeId>,
+    pub(crate) descendents: RefCell<HashSet<ScopeId>>,
+    pub(crate) our_arena_idx: ScopeId,
+    pub(crate) height: u32,
 
-    // IDs of children that this scope has created
-    // This enables us to drop the children and their children when this scope is destroyed
-    pub(crate) descendents: RefCell<HashSet<ScopeIdx>>,
-
-    pub child_nodes: &'static [VNode<'static>],
-
-    // A reference to the list of components.
-    // This lets us traverse the component list whenever we need to access our parent or children.
-    pub arena_link: SharedArena,
-
-    pub shared_contexts: RefCell<HashMap<TypeId, Rc<dyn Any>>>,
-
-    // Our own ID accessible from the component map
-    pub arena_idx: ScopeIdx,
-
-    pub height: u32,
-
-    pub event_channel: Rc<dyn Fn() + 'static>,
-
-    pub caller: Rc<WrappedCaller>,
-
-    // ==========================
-    // slightly unsafe stuff
-    // ==========================
+    // Nodes
     // an internal, highly efficient storage of vnodes
-    pub frames: ActiveFrame,
-
-    // These hooks are actually references into the hook arena
-    // These two could be combined with "OwningRef" to remove unsafe usage
-    // or we could dedicate a tiny bump arena just for them
-    // could also use ourborous
-    pub hooks: HookList,
+    pub(crate) frames: ActiveFrame,
+    pub(crate) child_nodes: &'static [VNode<'static>],
+    pub(crate) caller: Rc<WrappedCaller>,
 
+    // Listeners
+    pub(crate) listeners: RefCell<Vec<(*mut Cell<RealDomNode>, *mut dyn FnMut(VirtualEvent))>>,
     pub(crate) listener_idx: Cell<usize>,
 
-    // Unsafety:
-    // - is self-refenrential and therefore needs to point into the bump
-    // Stores references into the listeners attached to the vnodes
-    // NEEDS TO BE PRIVATE
-    pub(crate) listeners: RefCell<Vec<(*mut Cell<RealDomNode>, *mut dyn FnMut(VirtualEvent))>>,
+    // State
+    pub(crate) hooks: HookList,
+    pub(crate) shared_contexts: RefCell<HashMap<TypeId, Rc<dyn Any>>>,
 
-    pub task_submitter: TaskSubmitter,
+    // Events
+    pub(crate) event_channel: Rc<dyn Fn() + 'static>,
 
+    // Tasks
+    pub(crate) task_submitter: TaskSubmitter,
     pub(crate) suspended_tasks: Vec<*mut Pin<Box<dyn Future<Output = VNode<'static>>>>>,
+
+    // A reference to the list of components.
+    // This lets us traverse the component list whenever we need to access our parent or children.
+    pub(crate) arena_link: SharedArena,
 }
 
 pub type FiberTask = Pin<Box<dyn Future<Output = EventTrigger>>>;
@@ -83,8 +66,8 @@ impl Scope {
     // Therefore, their lifetimes are connected exclusively to the virtual dom
     pub fn new<'creator_node>(
         caller: Rc<WrappedCaller>,
-        arena_idx: ScopeIdx,
-        parent: Option<ScopeIdx>,
+        arena_idx: ScopeId,
+        parent: Option<ScopeId>,
         height: u32,
         event_channel: EventChannel,
         arena_link: SharedArena,
@@ -102,8 +85,8 @@ impl Scope {
         Self {
             child_nodes,
             caller,
-            parent,
-            arena_idx,
+            parent_idx: parent,
+            our_arena_idx: arena_idx,
             height,
             event_channel,
             arena_link,
@@ -190,7 +173,7 @@ impl Scope {
         log::debug!(
             "There are  {:?} listeners associated with this scope {:#?}",
             self.listeners.borrow().len(),
-            self.arena_idx
+            self.our_arena_idx
         );
 
         let listners = self.listeners.borrow_mut();

+ 4 - 6
packages/core/src/tasks.rs

@@ -11,15 +11,13 @@
 
 use std::{
     cell::Cell,
-    pin::Pin,
     sync::{Arc, RwLock},
-    task::{Context, Poll},
 };
 
 use futures_util::{stream::FuturesUnordered, Future, Stream, StreamExt};
 use slotmap::{DefaultKey, SlotMap};
 
-use crate::innerlude::{EventTrigger, FiberTask, ScopeIdx};
+use crate::innerlude::{EventTrigger, FiberTask, ScopeId};
 
 pub type TaskSubmitter = Arc<dyn Fn(FiberTask)>;
 
@@ -117,11 +115,11 @@ pub struct TaskHandle {
 
 pub struct DTask {
     fut: FiberTask,
-    originator: ScopeIdx,
+    originator: ScopeId,
     dead: Cell<bool>,
 }
 impl DTask {
-    pub fn new(fut: FiberTask, originator: ScopeIdx) -> Self {
+    pub fn new(fut: FiberTask, originator: ScopeId) -> Self {
         Self {
             fut,
             originator,
@@ -129,7 +127,7 @@ impl DTask {
         }
     }
     pub fn debug_new(fut: FiberTask) -> Self {
-        let originator = ScopeIdx::default();
+        let originator = ScopeId::default();
         Self {
             fut,
             originator,

+ 16 - 10
packages/core/src/util.rs

@@ -14,7 +14,7 @@ pub struct EventQueue {
 }
 
 impl EventQueue {
-    pub fn new_channel(&self, height: u32, idx: ScopeIdx) -> Rc<dyn Fn()> {
+    pub fn new_channel(&self, height: u32, idx: ScopeId) -> Rc<dyn Fn()> {
         let inner = self.clone();
         let marker = HeightMarker { height, idx };
         Rc::new(move || {
@@ -35,7 +35,7 @@ impl EventQueue {
 /// A helper type that lets scopes be ordered by their height
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub struct HeightMarker {
-    pub idx: ScopeIdx,
+    pub idx: ScopeId,
     pub height: u32,
 }
 
@@ -59,23 +59,29 @@ impl PartialOrd for HeightMarker {
 
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Clone, Copy, Debug, PartialEq)]
-pub struct RealDomNode(pub DefaultKey);
+pub struct RealDomNode(pub u64);
 impl RealDomNode {
+    #[inline]
     pub fn empty() -> Self {
-        let data = KeyData::from_ffi(u64::MIN);
-        let key: DefaultKey = data.into();
-        Self(key)
+        // let data = KeyData::from_ffi(u64::MIN);
+        // let key: DefaultKey = data.into();
+        Self(u64::MIN)
     }
+    #[inline]
     pub fn empty_cell() -> Cell<Self> {
         Cell::new(Self::empty())
     }
+    #[inline]
     pub fn from_u64(id: u64) -> Self {
-        let data = KeyData::from_ffi(id);
-        let key: DefaultKey = data.into();
-        Self(key)
+        // let data = KeyData::from_ffi(id);
+        // let key: DefaultKey = data.into();
+        Self(id)
     }
+
+    #[inline]
     pub fn as_u64(&self) -> u64 {
-        self.0.data().as_ffi()
+        // self.0.data().as_ffi()
+        self.0
     }
 }
 

+ 10 - 3
packages/core/src/virtual_dom.rs

@@ -30,10 +30,17 @@ use std::any::TypeId;
 use std::cell::RefCell;
 use std::pin::Pin;
 
-pub type ScopeIdx = DefaultKey;
+pub type ScopeId = DefaultKey;
 
 /// An integrated virtual node system that progresses events and diffs UI trees.
 /// Differences are converted into patches which a renderer can use to draw the UI.
+///
+///
+///
+///
+///
+///
+///
 pub struct VirtualDom {
     /// All mounted components are arena allocated to make additions, removals, and references easy to work with
     /// A generational arena is used to re-use slots of deleted scopes without having to resize the underlying arena.
@@ -44,7 +51,7 @@ pub struct VirtualDom {
 
     /// The index of the root component
     /// Should always be the first (gen=0, id=0)
-    pub base_scope: ScopeIdx,
+    pub base_scope: ScopeId,
 
     pub triggers: RefCell<Vec<EventTrigger>>,
 
@@ -55,7 +62,7 @@ pub struct VirtualDom {
 
     root_props: std::pin::Pin<Box<dyn std::any::Any>>,
 
-    /// Type of the original cx. This is stored as TypeId so VirtualDom does not need to be generic.
+    /// Type of the original props. This is stored as TypeId so VirtualDom does not need to be generic.
     ///
     /// Whenver props need to be updated, an Error will be thrown if the new props do not
     /// match the props used to create the VirtualDom.

+ 3 - 1
packages/ssr/src/lib.rs

@@ -130,7 +130,9 @@ impl<'a> TextRenderer<'a> {
 
                 self.html_render(new_node, f, il + 1)?;
             }
-            VNodeKind::Suspended => todo!(),
+            VNodeKind::Suspended { .. } => {
+                // we can't do anything with suspended nodes
+            }
         }
         Ok(())
     }

+ 14 - 33
packages/web/src/new.rs

@@ -2,7 +2,7 @@ use std::{collections::HashMap, rc::Rc, sync::Arc};
 
 use dioxus_core::{
     events::{EventTrigger, VirtualEvent},
-    DomEdit, RealDomNode, ScopeIdx,
+    DomEdit, RealDomNode, ScopeId,
 };
 use fxhash::FxHashMap;
 use slotmap::{DefaultKey, Key, KeyData};
@@ -85,10 +85,10 @@ impl WebsysDom {
                 DomEdit::CreateElementNs { tag, id, ns } => self.create_element(tag, Some(ns), id),
                 DomEdit::CreatePlaceholder { id } => self.create_placeholder(id),
                 DomEdit::NewEventListener {
-                    event,
+                    event_name: event,
                     scope,
-                    node,
-                    idx,
+                    mounted_node_id: node,
+                    element_id: idx,
                 } => self.new_event_listener(event, scope, idx, node),
                 DomEdit::RemoveEventListener { event } => todo!(),
                 DomEdit::SetText { text } => self.set_text(text),
@@ -234,7 +234,7 @@ impl WebsysDom {
     fn new_event_listener(
         &mut self,
         event: &'static str,
-        scope: ScopeIdx,
+        scope: ScopeId,
         _element_id: usize,
         real_id: u64,
     ) {
@@ -335,7 +335,7 @@ impl<'a> dioxus_core::diff::RealDom<'a> for WebsysDom {
     fn request_available_node(&mut self) -> RealDomNode {
         let key = self.nodes.insert(None);
         log::debug!("making new key: {:#?}", key);
-        RealDomNode(key)
+        RealDomNode(key.data().as_ffi())
     }
 
     fn raw_node_as_any(&self) -> &mut dyn std::any::Any {
@@ -349,22 +349,24 @@ pub struct Stack {
 }
 
 impl Stack {
+    #[inline]
     pub fn with_capacity(cap: usize) -> Self {
         Stack {
             list: Vec::with_capacity(cap),
         }
     }
 
+    #[inline]
     pub fn push(&mut self, node: Node) {
-        // debug!("stack-push: {:?}", node);
         self.list.push(node);
     }
 
+    #[inline]
     pub fn pop(&mut self) -> Node {
-        let res = self.list.pop().unwrap();
-        res
+        self.list.pop().unwrap()
     }
 
+    #[inline]
     pub fn clear(&mut self) {
         self.list.clear();
     }
@@ -588,16 +590,11 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<EventTrigger> {
 
     use anyhow::Context;
 
-    // for attr in  {
     let attrs = target.attributes();
     for x in 0..attrs.length() {
         let attr = attrs.item(x).unwrap();
         log::debug!("attrs include: {:#?}", attr);
     }
-    // }
-    // for attr in target.attributes() {
-    //     log::debug!("attrs include: {:#?}", attr);
-    // }
 
     // The error handling here is not very descriptive and needs to be replaced with a zero-cost error system
     let val: String = target
@@ -613,34 +610,18 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<EventTrigger> {
 
     let real_id = fields
         .next()
-        .and_then(|raw_id| {
-            raw_id
-                .parse::<u64>()
-                .ok()
-                .map(|value| KeyData::from_ffi(value))
-                .map(|f| RealDomNode(f.into()))
-        })
+        .and_then(|raw_id| raw_id.parse::<u64>().ok())
         .context("failed to parse real id")?;
 
     // Call the trigger
     log::debug!("decoded scope_id: {}, node_id: {:#?}", gi_id, real_id);
 
-    let triggered_scope: ScopeIdx = KeyData::from_ffi(gi_id).into();
+    let triggered_scope: ScopeId = KeyData::from_ffi(gi_id).into();
     log::debug!("Triggered scope is {:#?}", triggered_scope);
     Ok(EventTrigger::new(
         virtual_event_from_websys_event(event),
         triggered_scope,
-        Some(real_id),
+        Some(RealDomNode::from_u64(real_id)),
         dioxus_core::events::EventPriority::High,
     ))
 }
-
-struct ListenerMap {}
-impl ListenerMap {
-    fn get(&self, event: &'static str) -> bool {
-        false
-    }
-}
-
-struct JsStringCache {}
-impl JsStringCache {}

+ 1 - 1
packages/webview/src/dom.rs

@@ -1,6 +1,6 @@
 //! webview dom
 
-use dioxus_core::{DomEdit, RealDom, RealDomNode, ScopeIdx};
+use dioxus_core::{DomEdit, RealDom, RealDomNode, ScopeId};
 use DomEdit::*;
 
 pub struct WebviewRegistry {}