1
0
Эх сурвалжийг харах

Wip: pre-diffmachine merge fork

Jonathan Kelley 4 жил өмнө
parent
commit
424a18137f

+ 1 - 0
.vscode/spellright.dict

@@ -45,3 +45,4 @@ namespacing
 impl
 destructured
 linting
+lodash

+ 1 - 0
README.md

@@ -85,6 +85,7 @@ TypeScript is a great addition to JavaScript, but comes with a lot of tweaking f
 - inline built-in unit/integration testing
 - best-in-class error handling
 - simple and fast build system
+- powerful standard library (no need for lodash or underscore)
 - include_str! for integrating html/css/svg templates directly
 - various macros (`html!`, `rsx!`) for fast template iteration
 

+ 1 - 1
packages/core/.vscode/settings.json

@@ -1,3 +1,3 @@
 {
-    "rust-analyzer.inlayHints.enable": true
+    "rust-analyzer.inlayHints.enable": false
 }

+ 14 - 13
packages/core/examples/fragment.rs

@@ -1,17 +1,18 @@
 use dioxus_core::prelude::*;
 
 fn main() {
-    let g = rsx! {
-        Fragment {
-            // div {}
-            // div {}
-            // div {}
-            // div {}
-            // div {}
-            // div {}
-            // div {}
-            // div {}
-            // div {}
-        }
-    };
+
+    // let g = rsx! {
+    //     Fragment {
+    //         // div {}
+    //         // div {}
+    //         // div {}
+    //         // div {}
+    //         // div {}
+    //         // div {}
+    //         // div {}
+    //         // div {}
+    //         // div {}
+    //     }
+    // };
 }

+ 1 - 2
packages/core/src/arena.rs

@@ -1,14 +1,13 @@
 use std::{
     cell::{RefCell, UnsafeCell},
     collections::HashMap,
-    sync::Arc,
+    rc::Rc,
 };
 
 use generational_arena::Arena;
 
 use crate::innerlude::*;
 
-type Rc<T> = Arc<T>;
 #[derive(Clone)]
 pub struct ScopeArena(Rc<RefCell<ScopeArenaInner>>);
 

+ 0 - 135
packages/core/src/diff.rs

@@ -1007,138 +1007,3 @@ enum KeyedPrefixResult {
     // the beginning of `new` and `old` we already processed.
     MoreWorkToDo(usize),
 }
-
-mod support {
-
-    // // Get or create the template.
-    // //
-    // // Upon entering this function the change list stack may be in any shape:
-    // //
-    // //     [...]
-    // //
-    // // When this function returns, it leaves a freshly cloned copy of the template
-    // // on the top of the change list stack:
-    // //
-    // //     [... template]
-    // #[inline]
-    // pub fn get_or_create_template<'a>(// cached_set: &'a CachedSet,
-    //     // change_list: &mut ChangeListBuilder,
-    //     // registry: &mut EventsRegistry,
-    //     // cached_roots: &mut FxHashSet<CacheId>,
-    //     // template_id: CacheId,
-    // ) -> (&'a Node<'a>, bool) {
-    //     let (template, template_template) = cached_set.get(template_id);
-    //     debug_assert!(
-    //         template_template.is_none(),
-    //         "templates should not be templated themselves"
-    //     );
-
-    //     // If we haven't already created and saved the physical DOM subtree for this
-    //     // template, do that now.
-    //     if change_list.has_template(template_id) {
-    //         // Clone the template and push it onto the stack.
-    //         //
-    //         // [...]
-    //         change_list.push_template(template_id);
-    //         // [... template]
-
-    //         (template, true)
-    //     } else {
-    //         // [...]
-    //         create(cached_set, change_list, registry, template, cached_roots);
-    //         // [... template]
-    //         change_list.save_template(template_id);
-    //         // [... template]
-
-    //         (template, false)
-    //     }
-    // }
-
-    // pub fn create_and_replace(
-    //     cached_set: &CachedSet,
-    //     change_list: &mut ChangeListBuilder,
-    //     registry: &mut EventsRegistry,
-    //     new_template: Option<CacheId>,
-    //     old: &Node,
-    //     new: &Node,
-    //     cached_roots: &mut FxHashSet<CacheId>,
-    // ) {
-    //     debug_assert!(change_list.traversal_is_committed());
-
-    //     if let Some(template_id) = new_template {
-    //         let (template, needs_listeners) = get_or_create_template(
-    //             cached_set,
-    //             change_list,
-    //             registry,
-    //             cached_roots,
-    //             template_id,
-    //         );
-    //         change_list.replace_with();
-
-    //         let mut old_forcing = None;
-    //         if needs_listeners {
-    //             old_forcing = Some(change_list.push_force_new_listeners());
-    //         }
-
-    //         diff(
-    //             cached_set,
-    //             change_list,
-    //             registry,
-    //             template,
-    //             new,
-    //             cached_roots,
-    //         );
-
-    //         if let Some(old) = old_forcing {
-    //             change_list.pop_force_new_listeners(old);
-    //         }
-
-    //         change_list.commit_traversal();
-    //     } else {
-    //         create(cached_set, change_list, registry, new, cached_roots);
-    //         change_list.replace_with();
-    //     }
-    //     registry.remove_subtree(old);
-    // }
-
-    // pub fn create_with_template(
-    //     cached_set: &CachedSet,
-    //     change_list: &mut ChangeListBuilder,
-    //     registry: &mut EventsRegistry,
-    //     template_id: CacheId,
-    //     node: &Node,
-    //     cached_roots: &mut FxHashSet<CacheId>,
-    // ) {
-    //     debug_assert!(change_list.traversal_is_committed());
-
-    //     // [...]
-    //     let (template, needs_listeners) =
-    //         get_or_create_template(cached_set, change_list, registry, cached_roots, template_id);
-    //     // [... template]
-
-    //     // Now diff the node with its template.
-    //     //
-    //     // We must force adding new listeners instead of updating existing ones,
-    //     // since listeners don't get cloned in `cloneNode`.
-    //     let mut old_forcing = None;
-    //     if needs_listeners {
-    //         old_forcing = Some(change_list.push_force_new_listeners());
-    //     }
-
-    //     diff(
-    //         cached_set,
-    //         change_list,
-    //         registry,
-    //         template,
-    //         node,
-    //         cached_roots,
-    //     );
-
-    //     if let Some(old) = old_forcing {
-    //         change_list.pop_force_new_listeners(old);
-    //     }
-
-    //     // Make sure that we come back up to the level we were at originally.
-    //     change_list.commit_traversal();
-    // }
-}

+ 8 - 8
packages/core/src/nodes.rs

@@ -6,6 +6,7 @@
 use crate::{
     events::VirtualEvent,
     innerlude::{Context, Properties, Scope, ScopeIdx, FC},
+    nodebuilder::text3,
 };
 use bumpalo::Bump;
 use std::{
@@ -28,6 +29,8 @@ pub enum VNode<'src> {
     /// A text node (node type `TEXT_NODE`).
     Text(VText<'src>),
 
+    /// A fragment is a "virtual position" in the DOM
+    /// Fragments may have children and keys
     Fragment(&'src VFragment<'src>),
 
     /// A "suspended component"
@@ -86,8 +89,8 @@ impl<'a> VNode<'a> {
         VNode::Text(VText { text })
     }
 
-    pub fn text_args(b: &'a Bump, f: Arguments) -> VNode<'a> {
-        todo!()
+    pub fn text_args(bump: &'a Bump, args: Arguments) -> VNode<'a> {
+        text3(bump, args)
     }
 
     #[inline]
@@ -95,11 +98,11 @@ impl<'a> VNode<'a> {
         match &self {
             VNode::Text(_) => NodeKey::NONE,
             VNode::Element(e) => e.key,
-            VNode::Suspended => {
-                todo!()
-            }
             VNode::Fragment(frag) => frag.key,
             VNode::Component(c) => c.key,
+
+            // todo suspend should be allowed to have keys
+            VNode::Suspended => NodeKey::NONE,
         }
     }
 }
@@ -254,9 +257,6 @@ pub struct VComponent<'src> {
     _p: PhantomData<&'src ()>,
 }
 
-unsafe fn transmogrify<'a>(p: impl Properties + 'a) -> impl Properties + 'static {
-    todo!()
-}
 impl<'a> VComponent<'a> {
     // use the type parameter on props creation and move it into a portable context
     // this lets us keep scope generic *and* downcast its props when we need to:

+ 41 - 72
packages/core/src/virtual_dom.rs

@@ -154,10 +154,11 @@ impl VirtualDom {
         // Make the first scope
         // We don't run the component though, so renderers will need to call "rebuild" when they initialize their DOM
         let link = components.clone();
+        let event_channel = Rc::new(move || {});
         let base_scope = components
             .with(|arena| {
                 arena.insert_with(move |myidx| {
-                    Scope::new(caller_ref, myidx, None, 0, _event_queue, link)
+                    Scope::new(caller_ref, myidx, None, 0, event_channel, link, &[])
                 })
             })
             .unwrap();
@@ -172,6 +173,7 @@ impl VirtualDom {
     }
 
     /// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch
+    /// Currently this doesn't do what we want it to do
     pub fn rebuild<'s>(&'s mut self) -> Result<EditList<'s>> {
         let mut diff_machine = DiffMachine::new();
 
@@ -180,8 +182,9 @@ impl VirtualDom {
         // Instead, this is done on top-level component
 
         let base = self.components.try_get(self.base_scope)?;
-        let immediate_update = self.event_queue.schedule_update(base);
-        immediate_update();
+
+        let update = &base.event_channel;
+        update();
 
         self.progress_completely(&mut diff_machine)?;
 
@@ -319,21 +322,23 @@ impl VirtualDom {
 
                         // Insert a new scope into our component list
                         let idx = self.components.with(|components| {
-                            components.insert_with(|f| {
+                            components.insert_with(|new_idx| {
+                                let height = cur_height + 1;
                                 Scope::new(
                                     caller,
-                                    f,
+                                    new_idx,
                                     Some(cur_component.arena_idx),
-                                    cur_height + 1,
-                                    self.event_queue.clone(),
+                                    height,
+                                    self.event_queue.new_channel(height, new_idx),
                                     self.components.clone(),
+                                    &[],
                                 )
                             })
                         })?;
 
                         {
                             let cur_component = self.components.try_get_mut(update.idx).unwrap();
-                            let mut ch = cur_component.children.borrow_mut();
+                            let mut ch = cur_component.descendents.borrow_mut();
                             ch.insert(idx);
                             std::mem::drop(ch);
                         }
@@ -444,7 +449,7 @@ impl VirtualDom {
                         // Accumulate all the child components that need to be removed
                         while let Some(child_id) = children_to_remove.pop_back() {
                             let comp = self.components.try_get(child_id).unwrap();
-                            let children = comp.children.borrow();
+                            let children = comp.descendents.borrow();
                             for child in children.iter() {
                                 children_to_remove.push_front(*child);
                             }
@@ -471,7 +476,6 @@ impl VirtualDom {
 }
 
 // TODO!
-//
 // These impls are actually wrong. The DOM needs to have a mutex implemented.
 unsafe impl Sync for VirtualDom {}
 unsafe impl Send for VirtualDom {}
@@ -488,7 +492,9 @@ pub struct Scope {
 
     // IDs of children that this scope has created
     // This enables us to drop the children and their children when this scope is destroyed
-    children: RefCell<HashSet<ScopeIdx>>,
+    descendents: RefCell<HashSet<ScopeIdx>>,
+
+    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.
@@ -501,8 +507,9 @@ pub struct Scope {
 
     pub height: u32,
 
-    pub event_queue: EventQueue,
+    pub event_channel: Rc<dyn Fn() + 'static>,
 
+    // pub event_queue: EventQueue,
     pub caller: Weak<OpaqueComponent<'static>>,
 
     pub hookidx: RefCell<usize>,
@@ -528,6 +535,7 @@ pub struct Scope {
 
 // We need to pin the hook so it doesn't move as we initialize the list of hooks
 type Hook = Pin<Box<dyn std::any::Any>>;
+type EventChannel = Rc<dyn Fn()>;
 
 impl Scope {
     // we are being created in the scope of an existing component (where the creator_node lifetime comes into play)
@@ -542,8 +550,9 @@ impl Scope {
         arena_idx: ScopeIdx,
         parent: Option<ScopeIdx>,
         height: u32,
-        event_queue: EventQueue,
+        event_channel: EventChannel,
         arena_link: ScopeArena,
+        child_nodes: &'creator_node [VNode<'creator_node>],
     ) -> Self {
         log::debug!(
             "New scope created, height is {}, idx is {:?}",
@@ -569,18 +578,19 @@ impl Scope {
         };
 
         Self {
+            child_nodes: &[],
             caller,
             parent,
             arena_idx,
             height,
-            event_queue,
+            event_channel,
             arena_link,
             frames: ActiveFrame::new(),
             hooks: Default::default(),
             shared_contexts: Default::default(),
             listeners: Default::default(),
             hookidx: Default::default(),
-            children: Default::default(),
+            descendents: Default::default(),
         }
     }
 
@@ -732,14 +742,18 @@ pub trait Scoped<'src>: Sized {
 
     /// Access the children elements passed into the component
     fn children(&self) -> &'src [VNode<'src>] {
-        todo!("Children API not yet implemented for component Context")
+        // We're re-casting the nodes back out
+        // They don't really have a static lifetime
+        unsafe {
+            let scope = self.get_scope();
+            let nodes = scope.child_nodes;
+            nodes
+        }
     }
 
     /// Create a subscription that schedules a future render for the reference component
     fn schedule_update(&self) -> Rc<dyn Fn() + 'static> {
-        todo!()
-        // pub fn schedule_update(self) -> impl Fn() + 'static {
-        // self.scope.event_queue.schedule_update(&self.scope)
+        self.get_scope().event_channel.clone()
     }
 
     /// Take a lazy VNode structure and actually build it with the context of the VDom's efficient VNode allocator.
@@ -759,22 +773,12 @@ pub trait Scoped<'src>: Sized {
     ///```
     fn render<'a, F: for<'b> FnOnce(&'b NodeCtx<'src>) -> VNode<'src> + 'src + 'a>(
         self,
-        // &'a/ self,
         lazy_nodes: LazyNodes<'src, F>,
-        // lazy_nodes: LazyNodes<'src, F>,
     ) -> VNode<'src> {
-        let scope_ref = self.get_scope();
-        let ctx = NodeCtx {
-            scope_ref,
+        lazy_nodes.into_vnode(&NodeCtx {
+            scope_ref: self.get_scope(),
             listener_id: 0.into(),
-        };
-
-        todo!()
-        // VNode {
-        //     root: unsafe {
-        //         std::mem::transmute::<VNode<'scope>, VNode<'static>>(lazy_nodes.into_vnode(&ctx))
-        //     },
-        // }
+        })
     }
 
     // impl<'scope> Context<'scope> {
@@ -957,17 +961,14 @@ Any function prefixed with "use" should not be called conditionally.
 // We then expose a handle to use those props for render in the form of "OpaqueComponent"
 pub(crate) type OpaqueComponent<'e> = dyn for<'b> Fn(&'b Scope) -> VNode<'b> + 'e;
 
-#[derive(Debug, Default, Clone)]
-pub struct EventQueue(pub(crate) Rc<RefCell<Vec<HeightMarker>>>);
+#[derive(PartialEq, Debug, Clone, Default)]
+pub(crate) struct EventQueue(pub Rc<RefCell<Vec<HeightMarker>>>);
 
 impl EventQueue {
-    pub fn schedule_update(&self, source: &Scope) -> impl Fn() {
+    pub fn new_channel(&self, height: u32, idx: ScopeIdx) -> Rc<dyn Fn()> {
         let inner = self.clone();
-        let marker = HeightMarker {
-            height: source.height,
-            idx: source.arena_idx,
-        };
-        move || inner.0.as_ref().borrow_mut().push(marker)
+        let marker = HeightMarker { height, idx };
+        Rc::new(move || inner.0.as_ref().borrow_mut().push(marker))
     }
 }
 
@@ -1107,35 +1108,3 @@ impl ActiveFrame {
         }
     }
 }
-
-mod tests {
-    use super::*;
-
-    #[test]
-    fn simulate() {
-        let dom = VirtualDom::new(|ctx| {
-            //
-            ctx.render(rsx! {
-                div {
-
-                }
-            })
-        });
-        // let root = dom.components.get(dom.base_scope).unwrap();
-    }
-
-    // ensure the virtualdom is send + sync
-    // needed for use in async/await contexts
-    #[test]
-    fn is_send_sync() {
-        fn check_send<T: Send>(_a: T) -> T {
-            todo!()
-        }
-        fn check_sync<T: Sync>(_a: T) -> T {
-            todo!()
-        }
-
-        let _ = check_send(VirtualDom::new(|ctx| ctx.render(rsx! { div {}})));
-        let _ = check_sync(VirtualDom::new(|ctx| ctx.render(rsx! { div {}})));
-    }
-}