Procházet zdrojové kódy

feat: code quality improvements for core

Jonathan Kelley před 4 roky
rodič
revize
00231ad

+ 3 - 8
packages/core/src/arena.rs

@@ -1,16 +1,11 @@
-use std::{
-    cell::{RefCell, UnsafeCell},
-    collections::HashMap,
-    rc::Rc,
-    sync::Arc,
-};
+use std::{cell::UnsafeCell, rc::Rc};
 
 use crate::innerlude::*;
 use slotmap::{DefaultKey, SlotMap};
 
 #[derive(Clone)]
 pub struct SharedArena {
-    pub components: Arc<UnsafeCell<ScopeMap>>,
+    pub components: Rc<UnsafeCell<ScopeMap>>,
 }
 pub type ScopeMap = SlotMap<DefaultKey, Scope>;
 
@@ -21,7 +16,7 @@ enum MutStatus {
 
 impl SharedArena {
     pub fn new(arena: ScopeMap) -> Self {
-        let components = Arc::new(UnsafeCell::new(arena));
+        let components = Rc::new(UnsafeCell::new(arena));
         SharedArena { components }
     }
 

+ 4 - 24
packages/core/src/context.rs

@@ -1,15 +1,11 @@
 use crate::innerlude::*;
 
 use futures_util::FutureExt;
-
-use std::any::Any;
-use std::cell::Cell;
-use std::marker::PhantomData;
-
 use std::{
-    any::TypeId,
-    cell::RefCell,
+    any::{Any, TypeId},
+    cell::{Cell, RefCell},
     future::Future,
+    marker::PhantomData,
     ops::Deref,
     rc::{Rc, Weak},
 };
@@ -316,23 +312,7 @@ Any function prefixed with "use" should not be called conditionally.
     ///
     ///
     pub fn submit_task(&self, task: FiberTask) -> TaskHandle {
-        let r = (self.scope.task_submitter)(task);
-        // self.scope.submit_task(task);
-        // let r = task.then(|f| async {
-        //     //
-        // });
-        // self.use_hook(|| Box::new(r), |_| {}, |_| {});
-        // *task = task.then(|f| async {
-        //     //
-        //     t
-        //     // ()
-        // });
-        // let new_fut = task.then(|f| async {
-        //     //
-        //     ()
-        // });
-        // self.tasks.borrow_mut().push(new_fut);
-
+        (self.scope.task_submitter)(task);
         TaskHandle { _p: PhantomData {} }
     }
 

+ 0 - 32
packages/core/src/debug_renderer.rs

@@ -76,35 +76,3 @@ impl DebugRenderer {
         Ok(())
     }
 }
-
-pub struct DebugVNodeSource {
-    bump: Bump,
-}
-impl DebugVNodeSource {
-    fn new() -> Self {
-        Self { bump: Bump::new() }
-    }
-
-    fn render_nodes(&self) -> VNode {
-        // let cx = NodeFactory
-        todo!()
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn ensure_creation() -> Result<(), ()> {
-        // static Example: FC<()> = |cx| {
-        //     //
-        //     cx.render(html! { <div> "hello world" </div> })
-        // };
-
-        // let mut dom = VirtualDom::new(Example);
-        // let machine = DiffMachine::new();
-
-        Ok(())
-    }
-}

+ 1 - 1
packages/core/src/editor.rs

@@ -12,7 +12,7 @@ use crate::{innerlude::ScopeId, RealDomNode};
 /// However, the DomEditor only builds a change list - it does not apply them. In contrast with the "RealDom", the DomEditor
 /// is cancellable and flushable. At any moment in time, Dioxus may choose to completely clear the edit list and start over.
 ///
-/// This behavior is used in the cooperative scheduling algorithm
+/// This behavior is used in the cooperative scheduling algorithm.
 pub struct DomEditor<'real, 'bump> {
     pub edits: &'real mut Vec<DomEdit<'bump>>,
 }

+ 3 - 0
packages/core/src/lib.rs

@@ -26,6 +26,7 @@ pub mod prelude {
 
 // types used internally that are important
 pub(crate) mod innerlude {
+    pub use crate::arena::*;
     pub use crate::bumpframe::*;
     pub use crate::component::*;
     pub use crate::context::*;
@@ -33,6 +34,7 @@ pub(crate) mod innerlude {
     pub use crate::editor::*;
     pub use crate::error::*;
     pub use crate::events::*;
+    pub use crate::hooklist::*;
     pub use crate::nodes::*;
     pub use crate::scope::*;
     pub use crate::tasks::*;
@@ -46,6 +48,7 @@ pub(crate) mod innerlude {
 
 pub mod exports {
     // export important things here
+    pub use bumpalo;
 }
 
 pub mod arena;

+ 86 - 38
packages/core/src/nodes.rs

@@ -1,8 +1,8 @@
 //! 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 insanely quick.
-
 use crate::{
     events::VirtualEvent,
     innerlude::{Context, Properties, RealDomNode, Scope, ScopeId, FC},
@@ -16,8 +16,13 @@ use std::{
 
 pub struct VNode<'src> {
     pub kind: VNodeKind<'src>,
-    pub dom_id: Cell<RealDomNode>,
-    pub key: Option<&'src str>,
+    pub(crate) dom_id: Cell<RealDomNode>,
+    pub(crate) key: Option<&'src str>,
+}
+impl VNode<'_> {
+    fn key(&self) -> Option<&str> {
+        self.key
+    }
 }
 
 /// Tools for the base unit of the virtual dom - the VNode
@@ -27,9 +32,13 @@ pub struct VNode<'src> {
 /// limit the amount of heap allocations / overly large enum sizes.
 pub enum VNodeKind<'src> {
     Text(VText<'src>),
+
     Element(&'src VElement<'src>),
+
     Fragment(VFragment<'src>),
+
     Component(&'src VComponent<'src>),
+
     Suspended { node: Rc<Cell<RealDomNode>> },
 }
 
@@ -55,6 +64,7 @@ pub trait DioxusElement {
         Self::NAME_SPACE
     }
 }
+
 pub struct VElement<'a> {
     // tag is always static
     pub tag_name: &'static str,
@@ -75,9 +85,13 @@ pub struct VElement<'a> {
 #[derive(Clone, Debug)]
 pub struct Attribute<'a> {
     pub name: &'static str,
+
     pub value: &'a str,
+
     pub is_static: bool,
+
     pub is_volatile: bool,
+
     // Doesn't exist in the html spec, mostly used to denote "style" tags - could be for any type of group
     pub namespace: Option<&'static str>,
 }
@@ -87,8 +101,11 @@ pub struct Attribute<'a> {
 pub struct Listener<'bump> {
     /// The type of event to listen for.
     pub(crate) event: &'static str,
+
     pub scope: ScopeId,
-    pub mounted_node: &'bump Cell<RealDomNode>,
+
+    pub mounted_node: &'bump mut Cell<RealDomNode>,
+
     pub(crate) callback: &'bump dyn FnMut(VirtualEvent),
 }
 
@@ -96,9 +113,13 @@ pub struct Listener<'bump> {
 /// Only supports the functional syntax
 pub struct VComponent<'src> {
     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>,
+
     pub is_static: bool,
 
     // a pointer into the bump arena (given by the 'src lifetime)
@@ -124,20 +145,7 @@ impl<'a> NodeFactory<'a> {
         &self.scope_ref.cur_frame().bump
     }
 
-    pub const fn const_text(&self, text: &'static str) -> VNodeKind<'static> {
-        VNodeKind::Text(VText {
-            is_static: true,
-            text,
-        })
-    }
-
-    pub const fn const_fragment(&self, children: &'static [VNode<'static>]) -> VNodeKind<'static> {
-        VNodeKind::Fragment(VFragment {
-            children,
-            is_static: true,
-        })
-    }
-
+    /// Used in a place or two to make it easier to build vnodes from dummy text
     pub fn static_text(text: &'static str) -> VNode {
         VNode {
             dom_id: RealDomNode::empty_cell(),
@@ -149,6 +157,9 @@ impl<'a> NodeFactory<'a> {
         }
     }
 
+    /// 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),
@@ -162,6 +173,7 @@ impl<'a> NodeFactory<'a> {
     }
 
     /// 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 {
@@ -171,27 +183,40 @@ impl<'a> NodeFactory<'a> {
         }
     }
 
-    pub fn raw_element(
+    pub fn element(
         &self,
-        _tag: &'static str,
-        _listeners: &[Listener],
-        _attributes: &[Attribute],
-        _children: &'a [VNode<'a>],
+        el: impl DioxusElement,
+        listeners: &'a mut [Listener<'a>],
+        attributes: &'a [Attribute<'a>],
+        children: &'a [VNode<'a>],
+        key: Option<&'a str>,
     ) -> VNode<'a> {
-        todo!()
+        self.raw_element(
+            el.tag_name(),
+            el.namespace(),
+            listeners,
+            attributes,
+            children,
+            key,
+        )
     }
 
-    pub fn element(
+    pub fn raw_element(
         &self,
-        el: impl DioxusElement,
-        listeners: &'a [Listener<'a>],
-        attributes: &'a [Attribute<'a>],
+        tag: &'static str,
+        namespace: Option<&'static str>,
+        listeners: &'a mut [Listener],
+        attributes: &'a [Attribute],
         children: &'a [VNode<'a>],
         key: Option<&'a str>,
     ) -> VNode<'a> {
+        // We take the references directly from the bump arena
+        // TODO: this code shouldn't necessarily be here of all places
+        // It would make more sense to do this in diffing
+
         let mut queue = self.scope_ref.listeners.borrow_mut();
-        for listener in listeners {
-            let mounted = listener.mounted_node as *const _ as *mut _;
+        for listener in listeners.iter_mut() {
+            let mounted = listener.mounted_node as *mut _;
             let callback = listener.callback as *const _ as *mut _;
             queue.push((mounted, callback))
         }
@@ -200,14 +225,16 @@ impl<'a> NodeFactory<'a> {
             dom_id: RealDomNode::empty_cell(),
             key,
             kind: VNodeKind::Element(self.bump().alloc(VElement {
-                tag_name: el.tag_name(),
-                namespace: el.namespace(),
-                static_listeners: false,
+                tag_name: tag,
+                namespace,
                 listeners,
-                static_attrs: false,
                 attributes,
-                static_children: false,
                 children,
+
+                // todo: wire up more constization
+                static_listeners: false,
+                static_attrs: false,
+                static_children: false,
             })),
         }
     }
@@ -243,12 +270,15 @@ impl<'a> NodeFactory<'a> {
         &self,
         component: FC<P>,
         props: P,
-        key: Option<&'a str>, // key: NodeKey<'a>,
+        key: Option<&'a str>,
         children: &'a [VNode<'a>],
     ) -> VNode<'a>
     where
         P: Properties + 'a,
     {
+        // TODO
+        // It's somewhat wrong to go about props like this
+
         // We don't want the fat part of the fat pointer
         // This function does static dispatch so we don't need any VTable stuff
         let props = self.bump().alloc(props);
@@ -271,6 +301,8 @@ impl<'a> NodeFactory<'a> {
             }
         }));
 
+        let is_static = children.len() == 0 && P::IS_STATIC && key.is_none();
+
         VNode {
             key,
             dom_id: Cell::new(RealDomNode::empty()),
@@ -280,7 +312,7 @@ impl<'a> NodeFactory<'a> {
                 raw_props,
                 children,
                 caller: NodeFactory::create_component_caller(component, raw_props),
-                is_static: children.len() == 0 && P::IS_STATIC && key.is_none(),
+                is_static,
                 ass_scope: Cell::new(None),
             })),
         }
@@ -313,10 +345,26 @@ impl<'a> NodeFactory<'a> {
         node_iter: impl IntoIterator<Item = impl IntoVNode<'a>>,
     ) -> VNode<'a> {
         let mut nodes = bumpalo::collections::Vec::new_in(self.bump());
-        // TODO throw an error if there are nodes without keys
+
         for node in node_iter.into_iter() {
             nodes.push(node.into_vnode(self));
         }
+
+        if cfg!(debug_assertions) {
+            if nodes.len() > 1 {
+                if nodes.last().unwrap().key().is_none() {
+                    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. 
+---
+To help you identify where this error is coming from, we've generated a backtrace.
+                        "#,
+                    );
+                }
+            }
+        }
         VNode {
             dom_id: RealDomNode::empty_cell(),
             key: None,

+ 0 - 484
packages/core/src/oldbuilder.rs

@@ -1,484 +0,0 @@
-/// Typically constructed with element-specific constructors, eg the `div`
-/// function for building `<div>` elements or the `button` function for building
-/// `<button>` elements.
-#[derive(Debug)]
-pub struct ElementBuilder<'a, 'b, Listeners, Attributes, Children>
-where
-    Listeners: 'a + AsRef<[Listener<'a>]>,
-    Attributes: 'a + AsRef<[Attribute<'a>]>,
-    Children: 'a + AsRef<[VNode<'a>]>,
-{
-    cx: &'b NodeFactory<'a>,
-    key: NodeKey<'a>,
-    tag_name: &'static str,
-    listeners: Listeners,
-    attributes: Attributes,
-    children: Children,
-    namespace: Option<&'static str>,
-}
-
-impl<'a, 'b>
-    ElementBuilder<
-        'a,
-        'b,
-        bumpalo::collections::Vec<'a, Listener<'a>>,
-        bumpalo::collections::Vec<'a, Attribute<'a>>,
-        bumpalo::collections::Vec<'a, VNode<'a>>,
-    >
-{
-    /// Create a new `ElementBuilder` for an element with the given tag name.
-    ///
-    /// In general, only use this constructor if the tag is dynamic (i.e. you
-    /// might build a `<div>` or you might build a `<span>` and you don't know
-    /// until runtime). Prefer using the tag-specific constructors instead:
-    /// `div(bump)` or `span(bump)`, etc.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use dioxus::{builder::*, bumpalo::Bump};
-    ///
-    /// let b = Bump::new();
-    ///
-    /// let tag_name = if flip_coin() {
-    ///     "div"
-    /// } else {
-    ///     "span"
-    /// };
-    ///
-    /// let my_element_builder = ElementBuilder::new(&b, tag_name);
-    /// # fn flip_coin() -> bool { true }
-    /// ```
-    pub fn new(cx: &'b NodeFactory<'a>, tag_name: &'static str) -> Self {
-        let bump = cx.bump();
-        ElementBuilder {
-            cx,
-            key: NodeKey::NONE,
-            tag_name,
-            listeners: bumpalo::collections::Vec::new_in(bump),
-            attributes: bumpalo::collections::Vec::new_in(bump),
-            children: bumpalo::collections::Vec::new_in(bump),
-            namespace: None,
-        }
-    }
-}
-
-impl<'a, 'b, Listeners, Attributes, Children>
-    ElementBuilder<'a, 'b, Listeners, Attributes, Children>
-where
-    Listeners: 'a + AsRef<[Listener<'a>]>,
-    Attributes: 'a + AsRef<[Attribute<'a>]>,
-    Children: 'a + AsRef<[VNode<'a>]>,
-{
-    /// Set the listeners for this element.
-    ///
-    /// You can use this method to customize the backing storage for listeners,
-    /// for example to use a fixed-size array instead of the default
-    /// dynamically-sized `bumpalo::collections::Vec`.
-    ///
-    /// Any listeners already added to the builder will be overridden.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// use dioxus::{builder::*, bumpalo::Bump};
-    ///
-    /// let b = Bump::new();
-    ///
-    /// // Create a `<div>` with a fixed-size array of two listeners.
-    /// let my_div = div(&b)
-    ///     .listeners([
-    ///         on(&b, "click", |root, vdom, event| {
-    ///             // ...
-    ///         }),
-    ///         on(&b, "dblclick", |root, vdom, event| {
-    ///             // ...
-    ///         }),
-    ///     ])
-    ///     .finish();
-    /// ```
-    #[inline]
-    pub fn listeners<L>(self, listeners: L) -> ElementBuilder<'a, 'b, L, Attributes, Children>
-    where
-        L: 'a + AsRef<[Listener<'a>]>,
-    {
-        ElementBuilder {
-            cx: self.cx,
-            key: self.key,
-            tag_name: self.tag_name,
-            listeners,
-            attributes: self.attributes,
-            children: self.children,
-            namespace: self.namespace,
-        }
-    }
-
-    /// Set the attributes for this element.
-    ///
-    /// You can use this method to customize the backing storage for attributes,
-    /// for example to use a fixed-size array instead of the default
-    /// dynamically-sized `bumpalo::collections::Vec`.
-    ///
-    /// Any attributes already added to the builder will be overridden.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// use dioxus::{builder::*, bumpalo::Bump, Attribute};
-    ///
-    /// let b = Bump::new();
-    ///
-    /// // Create a `<div>` with a fixed-size array of two attributes.
-    /// let my_div = div(&b)
-    ///     .attributes([
-    ///         attr("id", "my-div"),
-    ///         attr("class", "notification"),
-    ///     ])
-    ///     .finish();
-    /// ```
-    #[inline]
-    pub fn attributes<A>(self, attributes: A) -> ElementBuilder<'a, 'b, Listeners, A, Children>
-    where
-        A: 'a + AsRef<[Attribute<'a>]>,
-    {
-        ElementBuilder {
-            cx: self.cx,
-            key: self.key,
-            tag_name: self.tag_name,
-            listeners: self.listeners,
-            attributes,
-            children: self.children,
-            namespace: self.namespace,
-        }
-    }
-
-    /// Set the children for this element.
-    ///
-    /// You can use this method to customize the backing storage for children,
-    /// for example to use a fixed-size array instead of the default
-    /// dynamically-sized `bumpalo::collections::Vec`.
-    ///
-    /// Any children already added to the builder will be overridden.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// use dioxus::{builder::*, bumpalo::Bump};
-    ///
-    /// let b = Bump::new();
-    ///
-    /// // Create a `<div>` with a fixed-size array of two `<span>` children.
-    /// let my_div = div(&b)
-    ///     .children([
-    ///         span(&b).finish(),
-    ///         span(&b).finish(),
-    ///     ])
-    ///     .finish();
-    /// ```
-    #[inline]
-    pub fn children<C>(self, children: C) -> ElementBuilder<'a, 'b, Listeners, Attributes, C>
-    where
-        C: 'a + AsRef<[VNode<'a>]>,
-    {
-        ElementBuilder {
-            cx: self.cx,
-            key: self.key,
-            tag_name: self.tag_name,
-            listeners: self.listeners,
-            attributes: self.attributes,
-            children,
-            namespace: self.namespace,
-        }
-    }
-
-    /// Set the namespace for this element.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// use dioxus::{builder::*, bumpalo::Bump};
-    ///
-    /// let b = Bump::new();
-    ///
-    /// // Create a `<td>` tag with an xhtml namespace
-    /// let my_td = td(&b)
-    ///     .namespace(Some("http://www.w3.org/1999/xhtml"))
-    ///     .finish();
-    /// ```
-    #[inline]
-    pub fn namespace(self, namespace: Option<&'static str>) -> Self {
-        ElementBuilder {
-            cx: self.cx,
-            key: self.key,
-            tag_name: self.tag_name,
-            listeners: self.listeners,
-            attributes: self.attributes,
-            children: self.children,
-            namespace,
-        }
-    }
-
-    /// Set this element's key.
-    ///
-    /// When diffing sets of siblings, if an old sibling and new sibling share a
-    /// key, then they will always reuse the same physical DOM VNode. This is
-    /// important when using CSS animations, web components, third party JS, or
-    /// anything else that makes the diffing implementation observable.
-    ///
-    /// Do not use keys if such a scenario does not apply. Keyed diffing is
-    /// generally more expensive than not, since it is putting greater
-    /// constraints on the diffing algorithm.
-    ///
-    /// # Invariants You Must Uphold
-    ///
-    /// The key may not be `u32::MAX`, which is a reserved key value.
-    ///
-    /// Keys must be unique among siblings.
-    ///
-    /// All sibling VNodes must be keyed, or they must all not be keyed. You may
-    /// not mix keyed and unkeyed siblings.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// use dioxus::{builder::*, bumpalo::Bump};
-    ///
-    /// let b = Bump::new();
-    ///
-    /// let my_li = li(&b)
-    ///     .key(1337)
-    ///     .finish();
-    /// ```
-    #[inline]
-    pub fn key(mut self, key: &'a str) -> Self {
-        self.key = NodeKey(Some(key));
-        self
-    }
-
-    pub fn key2(mut self, args: Arguments) -> Self {
-        let key = match args.as_str() {
-            Some(static_str) => static_str,
-            None => {
-                use bumpalo::core_alloc::fmt::Write;
-                let mut s = bumpalo::collections::String::new_in(self.cx.bump());
-                s.write_fmt(args).unwrap();
-                s.into_bump_str()
-            }
-        };
-        self.key = NodeKey(Some(key));
-        self
-    }
-
-    /// Create the virtual DOM VNode described by this builder.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// use dioxus::{builder::*, bumpalo::Bump, VNode};
-    ///
-    /// let b = Bump::new();
-    ///
-    /// // Start with a builder...
-    /// let builder: ElementBuilder<_, _, _> = div(&b);
-    ///
-    /// // ...and finish it to create a virtual DOM VNode!
-    /// let my_div: VNode = builder.finish();
-    /// ```
-    #[inline]
-    pub fn finish(mut self) -> VNode<'a> {
-        let bump = self.cx.bump();
-
-        let children: &'a Children = bump.alloc(self.children);
-        let children: &'a [VNode<'a>] = children.as_ref();
-
-        let listeners: &'a Listeners = bump.alloc(self.listeners);
-        let listeners: &'a [Listener<'a>] = listeners.as_ref();
-
-        for listener in listeners {
-            // bump the context id forward
-            let id = self.cx.listener_id.get();
-            self.cx.listener_id.set(id + 1);
-
-            // Add this listener to the context list
-            // This casts the listener to a self-referential pointer
-            // This is okay because the bump arena is stable
-
-            // TODO: maybe not add it into CTX immediately
-            let r = unsafe { std::mem::transmute::<&Listener<'a>, &Listener<'static>>(listener) };
-            self.cx.scope_ref.listeners.borrow_mut().push((
-                r.mounted_node as *const _ as *mut _,
-                r.callback as *const _ as *mut _,
-            ));
-        }
-
-        let attributes: &'a Attributes = bump.alloc(self.attributes);
-        let attributes: &'a [Attribute<'a>] = attributes.as_ref();
-
-        VNode::element(
-            bump,
-            self.key,
-            self.tag_name,
-            listeners,
-            attributes,
-            children,
-            self.namespace,
-        )
-    }
-}
-
-impl<'a, 'b, Attributes, Children>
-    ElementBuilder<'a, 'b, bumpalo::collections::Vec<'a, Listener<'a>>, Attributes, Children>
-where
-    Attributes: 'a + AsRef<[Attribute<'a>]>,
-    Children: 'a + AsRef<[VNode<'a>]>,
-{
-    // / Add a new event listener to this element.
-    // /
-    // / The `event` string specifies which event will be listened for. The
-    // / `callback` function is the function that will be invoked if the
-    // / specified event occurs.
-    // /
-    // / # Example
-    // /
-    // / ```no_run
-    // / use dioxus::{builder::*, bumpalo::Bump};
-    // /
-    // / let b = Bump::new();
-    // /
-    // / // A button that does something when clicked!
-    // / let my_button = button(&b)
-    // /     .on("click", |event| {
-    // /         // ...
-    // /     })
-    // /     .finish();
-    // / ```
-    // pub fn on(self, event: &'static str, callback: impl FnMut(VirtualEvent) + 'a) -> Self {
-    //     let bump = &self.cx.bump();
-    //     let listener = Listener {
-    //         event,
-    //         callback: bump.alloc(callback),
-    //         scope: self.cx.scope_ref.arena_idx,
-    //         mounted_node: bump.alloc(Cell::new(RealDomNode::empty())),
-    //     };
-    //     self.add_listener(listener)
-    // }
-
-    // pub fn add_listener(mut self, listener: Listener<'a>) -> Self {
-    //     self.listeners.push(listener);
-
-    //     // bump the context id forward
-    //     let id = self.cx.listener_id.get();
-    //     self.cx.listener_id.set(id + 1);
-
-    //     // Add this listener to the context list
-    //     // This casts the listener to a self-referential pointer
-    //     // This is okay because the bump arena is stable
-    //     self.listeners.last().map(|g| {
-    //         let r = unsafe { std::mem::transmute::<&Listener<'a>, &Listener<'static>>(g) };
-    //         self.cx.scope_ref.listeners.borrow_mut().push((
-    //             r.mounted_node as *const _ as *mut _,
-    //             r.callback as *const _ as *mut _,
-    //         ));
-    //     });
-
-    //     self
-    // }
-}
-
-impl<'a, 'b, Listeners, Children>
-    ElementBuilder<'a, 'b, Listeners, bumpalo::collections::Vec<'a, Attribute<'a>>, Children>
-where
-    Listeners: 'a + AsRef<[Listener<'a>]>,
-    Children: 'a + AsRef<[VNode<'a>]>,
-{
-    /// Add a new attribute to this element.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// use dioxus::{builder::*, bumpalo::Bump};
-    ///
-    /// let b = Bump::new();
-    ///
-    /// // Create the `<div id="my-div"/>` element.
-    /// let my_div = div(&b).attr("id", "my-div").finish();
-    /// ```
-    pub fn attr(mut self, name: &'static str, args: std::fmt::Arguments) -> Self {
-        let (value, is_static) = raw_text(self.cx.bump(), args);
-
-        self.attributes.push(Attribute {
-            name,
-            value,
-            is_static,
-            namespace: None,
-        });
-        self
-    }
-}
-
-impl<'a, 'b, Listeners, Attributes>
-    ElementBuilder<'a, 'b, Listeners, Attributes, bumpalo::collections::Vec<'a, VNode<'a>>>
-where
-    Listeners: 'a + AsRef<[Listener<'a>]>,
-    Attributes: 'a + AsRef<[Attribute<'a>]>,
-{
-    /// Add a new child to this element.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// use dioxus::{builder::*, bumpalo::Bump};
-    /// use js_sys::Math;
-    ///
-    /// let b = Bump::new();
-    ///
-    /// // Create `<p><span></span></p>`.
-    /// let my_div = p(&b)
-    ///     .child(span(&b).finish())
-    ///     .finish();
-    /// ```
-    #[inline]
-    pub fn child(mut self, child: VNode<'a>) -> Self {
-        self.children.push(child);
-        self
-    }
-
-    /// Add multiple children to this element from an iterator.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// use dioxus::{builder::*, bumpalo::Bump};
-    ///
-    /// let b = Bump::new();
-    ///
-    /// let my_div = p(&b)
-    ///     .iter_child((0..10).map(|f| span(&b).finish())
-    ///     .finish();
-    /// ```    
-    pub fn iter_child(mut self, nodes: impl IntoIterator<Item = impl IntoVNode<'a>>) -> Self {
-        todo!();
-        let len_before = self.children.len();
-        for item in nodes {
-            todo!()
-            // let child = item.into_vnode(&self.cx);
-            // self.children.push(child);
-        }
-        if cfg!(debug_assertions) {
-            if self.children.len() > len_before + 1 {
-                if self.children.last().unwrap().key().is_none() {
-                    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. 
----
-To help you identify where this error is coming from, we've generated a backtrace.
-                        "#,
-                    );
-                }
-            }
-        }
-        self
-    }
-}

+ 20 - 41
packages/core/src/scope.rs

@@ -1,6 +1,4 @@
-use crate::hooklist::HookList;
-use crate::{arena::SharedArena, innerlude::*};
-
+use crate::innerlude::*;
 use std::{
     any::{Any, TypeId},
     cell::{Cell, RefCell},
@@ -10,17 +8,15 @@ use std::{
     rc::Rc,
 };
 
-// We need to pin the hook so it doesn't move as we initialize the list of hooks
-type Hook = Box<dyn std::any::Any>;
-type EventChannel = Rc<dyn Fn()>;
-pub type WrappedCaller = dyn for<'b> Fn(&'b Scope) -> VNode<'b>;
-
 /// Every component in Dioxus is represented by a `Scope`.
 ///
 /// 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
+/// usecase they might have.
 pub struct Scope {
     // Book-keeping about the arena
     pub(crate) parent_idx: Option<ScopeId>,
@@ -47,13 +43,19 @@ pub struct Scope {
 
     // 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,
 }
 
+// The type of the channel function
+type EventChannel = Rc<dyn Fn()>;
+
+// The type of closure that wraps calling components
+pub type WrappedCaller = dyn for<'b> Fn(&'b Scope) -> VNode<'b>;
+
+// The type of task that gets sent to the task scheduler
 pub type FiberTask = Pin<Box<dyn Future<Output = EventTrigger>>>;
 
 impl Scope {
@@ -74,14 +76,7 @@ impl Scope {
         child_nodes: &'creator_node [VNode<'creator_node>],
         task_submitter: TaskSubmitter,
     ) -> Self {
-        log::debug!(
-            "New scope created, height is {}, idx is {:?}",
-            height,
-            arena_idx
-        );
-
         let child_nodes = unsafe { std::mem::transmute(child_nodes) };
-
         Self {
             child_nodes,
             caller,
@@ -97,15 +92,14 @@ impl Scope {
             shared_contexts: Default::default(),
             listeners: Default::default(),
             descendents: Default::default(),
-            suspended_tasks: Default::default(),
         }
     }
 
-    pub fn update_caller<'creator_node>(&mut self, caller: Rc<WrappedCaller>) {
+    pub(crate) fn update_caller<'creator_node>(&mut self, caller: Rc<WrappedCaller>) {
         self.caller = caller;
     }
 
-    pub fn update_children<'creator_node>(
+    pub(crate) fn update_children<'creator_node>(
         &mut self,
         child_nodes: &'creator_node [VNode<'creator_node>],
     ) {
@@ -113,13 +107,14 @@ impl Scope {
         self.child_nodes = child_nodes;
     }
 
-    pub fn run_scope<'sel>(&'sel mut self) -> Result<()> {
+    pub(crate) fn run_scope<'sel>(&'sel mut self) -> Result<()> {
         // 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
+
+        // This is a very dangerous operation
         self.frames.next().bump.reset();
 
-        log::debug!("clearing listeners!");
-        // Remove all the outdated listeners
         self.listeners.borrow_mut().clear();
 
         unsafe { self.hooks.reset() };
@@ -133,17 +128,6 @@ impl Scope {
         Ok(())
     }
 
-    /// Progress a suspended node
-    pub fn progress_suspended(&mut self) -> Result<()> {
-        // load the hook
-        // downcast to our special state
-        // run just this hook
-        // create a new vnode
-        // diff this new vnode with the original suspended vnode
-
-        Ok(())
-    }
-
     // this is its own function so we can preciesly control how lifetimes flow
     unsafe fn call_user_component<'a>(&'a self, caller: &WrappedCaller) -> VNode<'static> {
         let new_head: VNode<'a> = caller(self);
@@ -153,7 +137,7 @@ impl Scope {
     // A safe wrapper around calling listeners
     // calling listeners will invalidate the list of listeners
     // The listener list will be completely drained because the next frame will write over previous listeners
-    pub fn call_listener(&mut self, trigger: EventTrigger) -> Result<()> {
+    pub(crate) fn call_listener(&mut self, trigger: EventTrigger) -> Result<()> {
         let EventTrigger {
             real_node_id,
             event,
@@ -165,11 +149,6 @@ impl Scope {
             return Ok(());
         }
 
-        // todo: implement scanning for outdated events
-
-        // Convert the raw ptr into an actual object
-        // This operation is assumed to be safe
-
         log::debug!(
             "There are  {:?} listeners associated with this scope {:#?}",
             self.listeners.borrow().len(),
@@ -178,7 +157,6 @@ impl Scope {
 
         let listners = self.listeners.borrow_mut();
 
-        // let listener = listners.get(trigger);
         let raw_listener = listners.iter().find(|(domptr, _)| {
             let search = unsafe { &**domptr };
             let search_id = search.get();
@@ -201,7 +179,7 @@ impl Scope {
         Ok(())
     }
 
-    pub fn submit_task(&self, task: FiberTask) {
+    pub(crate) fn submit_task(&self, task: FiberTask) {
         log::debug!("Task submitted into scope");
         (self.task_submitter)(task);
     }
@@ -221,6 +199,7 @@ impl Scope {
         self.frames.cur_frame()
     }
 
+    /// Get the root VNode of this component
     #[inline]
     pub fn root<'a>(&'a self) -> &'a VNode<'a> {
         &self.frames.cur_frame().head_node

+ 1 - 4
packages/core/src/signals.rs

@@ -2,7 +2,4 @@
 //! -----------------------------
 //!
 //!
-//!
-//!
-//!
-//!
+//! TODO!

+ 0 - 42
packages/core/src/tasks.rs

@@ -135,45 +135,3 @@ impl DTask {
         }
     }
 }
-
-// #[cfg(test)]
-// mod tests {
-//     use std::time::Duration;
-
-//     use super::*;
-//     use bumpalo::Bump;
-
-//     #[async_std::test]
-//     async fn example() {
-//         let bump = Bump::new();
-//         type RawTask = Pin<Box<dyn Future<Output = ()>>>;
-//         // build the three
-//         let f1 = bump.alloc(Box::pin(async {
-//             //
-//             async_std::task::sleep(Duration::from_secs(3)).await;
-//             println!("3 sec")
-//         }) as RawTask);
-
-//         let f2 = bump.alloc(Box::pin(async {
-//             //
-//             async_std::task::sleep(Duration::from_secs(2)).await;
-//             println!("2 sec")
-//         }) as RawTask);
-
-//         let f3 = bump.alloc(Box::pin(async {
-//             //
-//             async_std::task::sleep(Duration::from_secs(1)).await;
-//             println!("1 sec");
-//         }) as RawTask);
-
-//         let mut queue = TaskQueue::new();
-//         queue.submit_task(DTask::debug_new(f1));
-//         queue.submit_task(DTask::debug_new(f2));
-//         queue.submit_task(DTask::debug_new(f3));
-
-//         while !queue.is_empty() {
-//             let next = queue.next().await;
-//             println!("Event received {:#?}", next);
-//         }
-//     }
-// }

+ 4 - 76
packages/core/src/util.rs

@@ -63,8 +63,6 @@ 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(u64::MIN)
     }
     #[inline]
@@ -73,101 +71,31 @@ impl RealDomNode {
     }
     #[inline]
     pub fn from_u64(id: u64) -> Self {
-        // 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
     }
 }
 
 pub struct DebugDom {
     counter: u64,
-    logging: bool,
 }
 impl DebugDom {
     pub fn new() -> Self {
-        Self {
-            counter: 0,
-            logging: false,
-        }
-    }
-    pub fn with_logging_enabled() -> Self {
-        Self {
-            counter: 0,
-            logging: true,
-        }
+        Self { counter: 0 }
     }
 }
+
 impl<'a> RealDom<'a> for DebugDom {
     fn raw_node_as_any(&self) -> &mut dyn std::any::Any {
         todo!()
     }
 
     fn request_available_node(&mut self) -> RealDomNode {
-        todo!()
-    }
-}
-
-async fn launch_demo(app: FC<()>) {
-    let mut dom = VirtualDom::new(app);
-    let mut real_dom = DebugDom::new();
-    let mut edits = Vec::new();
-    dom.rebuild(&mut real_dom, &mut edits).unwrap();
-
-    while let Some(evt) = dom.tasks.next().await {
-        //
-        log::debug!("Event triggered! {:#?}", evt);
+        self.counter += 1;
+        RealDomNode::from_u64(self.counter)
     }
 }
-
-// #[cfg(test)]
-// mod tests {
-//     use super::*;
-//     use crate as dioxus;
-//     use std::{pin::Pin, time::Duration};
-
-//     use crate::builder::DioxusElement;
-//     use dioxus::prelude::*;
-//     use futures::Future;
-
-//     #[async_std::test]
-//     async fn async_tick() {
-//         static App: FC<()> = |cx| {
-//             // let mut count = use_state(cx, || 0);
-//             let mut fut = cx.use_hook(
-//                 move || {
-//                     Box::pin(async {
-//                         //
-//                         let mut tick: i32 = 0;
-//                         loop {
-//                             async_std::task::sleep(Duration::from_millis(250)).await;
-//                             log::debug!("ticking forward... {}", tick);
-//                             tick += 1;
-//                             // match surf::get(ENDPOINT).recv_json::<DogApi>().await {
-//                             //     Ok(_) => (),
-//                             //     Err(_) => (),
-//                             // }
-//                         }
-//                     }) as Pin<Box<dyn Future<Output = ()> + 'static>>
-//                 },
-//                 |h| h,
-//                 |_| {},
-//             );
-
-//             cx.submit_task(fut);
-
-//             cx.render(LazyNodes::new(move |f| {
-//                 f.text(format_args!("it's sorta working"))
-//             }))
-//         };
-
-//         std::env::set_var("RUST_LOG", "debug");
-//         env_logger::init();
-//         launch_demo(App).await;
-//     }
-// }

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

@@ -120,13 +120,7 @@ impl<'a> TextRenderer<'a> {
             VNodeKind::Component(vcomp) => {
                 let idx = vcomp.ass_scope.get().unwrap();
 
-                let new_node = self
-                    .vdom
-                    .components
-                    .try_get(idx)
-                    .unwrap()
-                    .frames
-                    .current_head_node();
+                let new_node = self.vdom.components.try_get(idx).unwrap().root();
 
                 self.html_render(new_node, f, il + 1)?;
             }