Evan Almloff преди 1 година
родител
ревизия
cb4c46154d
променени са 7 файла, в които са добавени 83 реда и са изтрити 45 реда
  1. 1 3
      examples/clock.rs
  2. 6 4
      packages/core/src/arena.rs
  3. 1 1
      packages/core/src/diff.rs
  4. 38 26
      packages/core/src/runtime.rs
  5. 9 2
      packages/core/src/scope_arena.rs
  6. 17 6
      packages/core/src/scope_context.rs
  7. 11 3
      packages/core/src/scopes.rs

+ 1 - 3
examples/clock.rs

@@ -3,15 +3,13 @@
 //! The example from the README.md.
 
 use dioxus::prelude::*;
-use dioxus_signals::{use_init_signal_rt, use_signal};
+use dioxus_signals::use_signal;
 
 fn main() {
     dioxus_desktop::launch(app);
 }
 
 fn app(cx: Scope) -> Element {
-    use_init_signal_rt(cx);
-
     let mut count = use_signal(cx, || 0);
 
     use_future!(cx, || async move {

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

@@ -110,11 +110,13 @@ impl VirtualDom {
         // Drop all the hooks once the children are dropped
         // this means we'll drop hooks bottom-up
         scope.hooks.get_mut().clear();
-        let context = scope.context();
+        {
+            let context = scope.context();
 
-        // Drop all the futures once the hooks are dropped
-        for task_id in context.spawned_tasks.borrow_mut().drain() {
-            context.tasks.remove(task_id);
+            // Drop all the futures once the hooks are dropped
+            for task_id in context.spawned_tasks.borrow_mut().drain() {
+                context.tasks.remove(task_id);
+            }
         }
 
         self.scopes.remove(id.0);

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

@@ -209,7 +209,7 @@ impl<'b> VirtualDom {
         self.diff_scope(scope_id);
 
         self.dirty_scopes.remove(&DirtyScope {
-            height: self.runtime.scope_contexts[scope_id.0].height,
+            height: self.runtime.get_context(scope_id).unwrap().height,
             id: scope_id,
         });
     }

+ 38 - 26
packages/core/src/runtime.rs

@@ -1,20 +1,14 @@
-use std::cell::RefCell;
+use std::cell::{Ref, RefCell};
 
-use crate::{
-    innerlude::{DirtyScope, Scheduler, SchedulerMsg},
-    scope_context::ScopeContext,
-    scopes::{ScopeId, ScopeState},
-};
-use rustc_hash::FxHashSet;
-use slab::Slab;
-use std::{collections::BTreeSet, rc::Rc};
+use crate::{innerlude::Scheduler, scope_context::ScopeContext, scopes::ScopeId};
+use std::rc::Rc;
 
 thread_local! {
-    static RUNTIMES: RefCell<Vec<Runtime>> = RefCell::new(vec![]);
+    static RUNTIMES: RefCell<Vec<Rc<Runtime>>> = RefCell::new(vec![]);
 }
 
 /// Pushes a new scope onto the stack
-pub(crate) fn push_runtime(runtime: Runtime) {
+pub(crate) fn push_runtime(runtime: Rc<Runtime>) {
     RUNTIMES.with(|stack| stack.borrow_mut().push(runtime));
 }
 
@@ -30,7 +24,7 @@ where
 {
     RUNTIMES.with(|stack| {
         let stack = stack.borrow();
-        stack.last().map(f)
+        stack.last().map(|r| f(&**r))
     })
 }
 
@@ -42,28 +36,50 @@ where
     with_runtime(|runtime| {
         runtime
             .current_scope_id()
-            .and_then(|scope| runtime.get_context(scope).map(f))
+            .and_then(|scope| runtime.get_context(scope).map(|sc| f(&*sc)))
     })
     .flatten()
 }
 
 pub struct Runtime {
-    pub(crate) scope_contexts: Slab<ScopeContext>,
+    pub(crate) scope_contexts: RefCell<Vec<Option<ScopeContext>>>,
     pub(crate) scheduler: Rc<Scheduler>,
 
     // While diffing we need some sort of way of breaking off a stream of suspended mutations.
     pub(crate) scope_stack: RefCell<Vec<ScopeId>>,
 }
 
+impl Drop for Runtime {
+    fn drop(&mut self) {
+        // todo: do this better
+        pop_runtime();
+    }
+}
+
 impl Runtime {
     pub(crate) fn new(scheduler: Rc<Scheduler>) -> Rc<Self> {
-        Rc::new(Self {
+        let runtime = Rc::new(Self {
             scheduler,
 
             scope_contexts: Default::default(),
 
             scope_stack: Default::default(),
-        })
+        });
+        push_runtime(runtime.clone());
+        runtime
+    }
+
+    /// Create a scope context. This slab is synchronized with the scope slab.
+    pub(crate) fn create_context_at(&self, id: ScopeId, context: ScopeContext) {
+        let mut contexts = self.scope_contexts.borrow_mut();
+        if contexts.len() <= id.0 {
+            contexts.resize_with(id.0 + 1, Default::default);
+        }
+        contexts[id.0] = Some(context);
+    }
+
+    pub(crate) fn remove_context(&self, id: ScopeId) {
+        self.scope_contexts.borrow_mut()[id.0] = None;
     }
 
     /// Get the current scope id
@@ -71,17 +87,13 @@ impl Runtime {
         self.scope_stack.borrow().last().copied()
     }
 
-    /// Get the state for any scope given its ID
+    /// Get the context for any scope given its ID
     ///
     /// This is useful for inserting or removing contexts from a scope, or rendering out its root node
-    pub fn get_context(&self, id: ScopeId) -> Option<&ScopeContext> {
-        self.scope_contexts.get(id.0).map(|f| &*f)
-    }
-
-    /// Get the single scope at the top of the Runtime tree that will always be around
-    ///
-    /// This scope has a ScopeId of 0 and is the root of the tree
-    pub fn base_context(&self) -> &ScopeContext {
-        self.get_context(ScopeId(0)).unwrap()
+    pub fn get_context(&self, id: ScopeId) -> Option<Ref<'_, ScopeContext>> {
+        Ref::filter_map(self.scope_contexts.borrow(), |contexts| {
+            contexts.get(id.0).and_then(|f| f.as_ref())
+        })
+        .ok()
     }
 }

+ 9 - 2
packages/core/src/scope_arena.rs

@@ -3,6 +3,7 @@ use crate::{
     bump_frame::BumpFrame,
     innerlude::DirtyScope,
     nodes::RenderReturn,
+    scope_context::ScopeContext,
     scopes::{ScopeId, ScopeState},
     virtual_dom::VirtualDom,
 };
@@ -20,7 +21,7 @@ impl VirtualDom {
         let entry = self.scopes.vacant_entry();
         let id = ScopeId(entry.key());
 
-        entry.insert(ScopeState {
+        let scope = entry.insert(ScopeState {
             runtime: self.runtime.clone(),
             context_id: id,
 
@@ -35,7 +36,13 @@ impl VirtualDom {
 
             borrowed_props: Default::default(),
             attributes_to_drop: Default::default(),
-        })
+        });
+
+        let context =
+            ScopeContext::new(name, id, parent_id, height, self.runtime.scheduler.clone());
+        self.runtime.create_context_at(id, context);
+
+        scope
     }
 
     pub(crate) fn run_scope(&mut self, scope_id: ScopeId) -> &RenderReturn {

+ 17 - 6
packages/core/src/scope_context.rs

@@ -32,12 +32,23 @@ pub struct ScopeContext {
 }
 
 impl ScopeContext {
-    pub fn name(&self) -> &str {
-        self.name
-    }
-
-    pub fn height(&self) -> u32 {
-        self.height
+    pub(crate) fn new(
+        name: &'static str,
+        id: ScopeId,
+        parent_id: Option<ScopeId>,
+        height: u32,
+        tasks: Rc<Scheduler>,
+    ) -> Self {
+        Self {
+            name,
+            id,
+            parent_id,
+            height,
+            suspended: Cell::new(false),
+            shared_contexts: RefCell::new(vec![]),
+            tasks,
+            spawned_tasks: RefCell::new(FxHashSet::default()),
+        }
     }
 
     pub fn parent_id(&self) -> Option<ScopeId> {

+ 11 - 3
packages/core/src/scopes.rs

@@ -13,7 +13,7 @@ use crate::{
 use bumpalo::{boxed::Box as BumpBox, Bump};
 use std::{
     any::Any,
-    cell::{Cell, RefCell, UnsafeCell},
+    cell::{Cell, Ref, RefCell, UnsafeCell},
     fmt::{Arguments, Debug},
     future::Future,
     rc::Rc,
@@ -84,8 +84,14 @@ pub struct ScopeState {
     pub(crate) props: Option<Box<dyn AnyProps<'static>>>,
 }
 
+impl Drop for ScopeState {
+    fn drop(&mut self) {
+        self.runtime.remove_context(self.context_id);
+    }
+}
+
 impl<'src> ScopeState {
-    pub(crate) fn context(&self) -> &ScopeContext {
+    pub(crate) fn context(&self) -> Ref<'_, ScopeContext> {
         self.runtime.get_context(self.context_id).unwrap()
     }
 
@@ -494,7 +500,9 @@ impl<'src> ScopeState {
 
     /// Mark this component as suspended and then return None
     pub fn suspend(&self) -> Option<Element> {
-        self.context().suspend()
+        let cx = self.context();
+        cx.suspend();
+        None
     }
 
     /// Store a value between renders. The foundational hook for all other hooks.