From 050add21d7b3d950524e3fc3e7e236f4274495eb Mon Sep 17 00:00:00 2001
From: Evan Almloff <evanalmloff@gmail.com>
Date: Tue, 17 Oct 2023 12:56:12 -0500
Subject: [PATCH 1/2] effect-outside-of-runtime

---
 packages/signals/src/effect.rs   | 28 +++++++++++++++++++++-------
 packages/signals/src/selector.rs |  6 ++++--
 packages/signals/src/signal.rs   |  7 +++++--
 3 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/packages/signals/src/effect.rs b/packages/signals/src/effect.rs
index 9a54188d9e..ad950b94bf 100644
--- a/packages/signals/src/effect.rs
+++ b/packages/signals/src/effect.rs
@@ -1,16 +1,28 @@
 use core::{self, fmt::Debug};
-use std::cell::RefCell;
 use std::fmt::{self, Formatter};
-use std::rc::Rc;
 //
 use dioxus_core::prelude::*;
 
 use crate::use_signal;
 use crate::{dependency::Dependency, CopyValue};
 
-#[derive(Default, Clone)]
+#[derive(Copy, Clone, PartialEq)]
 pub(crate) struct EffectStack {
-    pub(crate) effects: Rc<RefCell<Vec<Effect>>>,
+    pub(crate) effects: CopyValue<Vec<Effect>>,
+}
+
+impl Default for EffectStack {
+    fn default() -> Self {
+        Self {
+            effects: CopyValue::new_in_scope(Vec::new(), ScopeId::ROOT),
+        }
+    }
+}
+
+impl EffectStack {
+    pub(crate) fn current(&self) -> Option<Effect> {
+        self.effects.read().last().copied()
+    }
 }
 
 pub(crate) fn get_effect_stack() -> EffectStack {
@@ -57,6 +69,7 @@ pub fn use_effect_with_dependencies<D: Dependency>(
 pub struct Effect {
     pub(crate) source: ScopeId,
     pub(crate) callback: CopyValue<Box<dyn FnMut()>>,
+    pub(crate) effect_stack: EffectStack,
 }
 
 impl Debug for Effect {
@@ -67,7 +80,7 @@ impl Debug for Effect {
 
 impl Effect {
     pub(crate) fn current() -> Option<Self> {
-        get_effect_stack().effects.borrow().last().copied()
+        get_effect_stack().effects.read().last().copied()
     }
 
     /// Create a new effect. The effect will be run immediately and whenever any signal it reads changes.
@@ -77,6 +90,7 @@ impl Effect {
         let myself = Self {
             source: current_scope_id().expect("in a virtual dom"),
             callback: CopyValue::new(Box::new(callback)),
+            effect_stack: get_effect_stack(),
         };
 
         myself.try_run();
@@ -88,11 +102,11 @@ impl Effect {
     pub fn try_run(&self) {
         if let Some(mut callback) = self.callback.try_write() {
             {
-                get_effect_stack().effects.borrow_mut().push(*self);
+                self.effect_stack.effects.write().push(*self);
             }
             callback();
             {
-                get_effect_stack().effects.borrow_mut().pop();
+                self.effect_stack.effects.write().pop();
             }
         }
     }
diff --git a/packages/signals/src/selector.rs b/packages/signals/src/selector.rs
index 91ab920c8b..556c8437c9 100644
--- a/packages/signals/src/selector.rs
+++ b/packages/signals/src/selector.rs
@@ -78,19 +78,21 @@ pub fn selector<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> ReadOnlySig
     let effect = Effect {
         source: current_scope_id().expect("in a virtual dom"),
         callback: CopyValue::invalid(),
+        effect_stack: get_effect_stack(),
     };
 
     {
-        get_effect_stack().effects.borrow_mut().push(effect);
+        get_effect_stack().effects.write().push(effect);
     }
     state.inner.value.set(SignalData {
         subscribers: Default::default(),
         effect_subscribers: Default::default(),
         update_any: schedule_update_any().expect("in a virtual dom"),
         value: f(),
+        effect_stack: get_effect_stack(),
     });
     {
-        get_effect_stack().effects.borrow_mut().pop();
+        get_effect_stack().effects.write().pop();
     }
 
     effect.callback.value.set(Box::new(move || {
diff --git a/packages/signals/src/signal.rs b/packages/signals/src/signal.rs
index c35b040314..9b11572b49 100644
--- a/packages/signals/src/signal.rs
+++ b/packages/signals/src/signal.rs
@@ -11,7 +11,7 @@ use dioxus_core::{
     ScopeId, ScopeState,
 };
 
-use crate::{CopyValue, Effect};
+use crate::{get_effect_stack, CopyValue, Effect, EffectStack};
 
 /// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
 ///
@@ -82,6 +82,7 @@ pub(crate) struct SignalData<T> {
     pub(crate) subscribers: Rc<RefCell<Vec<ScopeId>>>,
     pub(crate) effect_subscribers: Rc<RefCell<Vec<Effect>>>,
     pub(crate) update_any: Arc<dyn Fn(ScopeId)>,
+    pub(crate) effect_stack: EffectStack,
     pub(crate) value: T,
 }
 
@@ -144,6 +145,7 @@ impl<T: 'static> Signal<T> {
                 effect_subscribers: Default::default(),
                 update_any: schedule_update_any().expect("in a virtual dom"),
                 value,
+                effect_stack: get_effect_stack(),
             }),
         }
     }
@@ -157,6 +159,7 @@ impl<T: 'static> Signal<T> {
                     effect_subscribers: Default::default(),
                     update_any: schedule_update_any().expect("in a virtual dom"),
                     value,
+                    effect_stack: get_effect_stack(),
                 },
                 owner,
             ),
@@ -172,7 +175,7 @@ impl<T: 'static> Signal<T> {
     /// If the signal has been dropped, this will panic.
     pub fn read(&self) -> Ref<T> {
         let inner = self.inner.read();
-        if let Some(effect) = Effect::current() {
+        if let Some(effect) = inner.effect_stack.current() {
             let mut effect_subscribers = inner.effect_subscribers.borrow_mut();
             if !effect_subscribers.contains(&effect) {
                 effect_subscribers.push(effect);

From ce86aabf262d53cbf8cbf0a5cbb74630725b8970 Mon Sep 17 00:00:00 2001
From: Evan Almloff <evanalmloff@gmail.com>
Date: Tue, 17 Oct 2023 13:02:51 -0500
Subject: [PATCH 2/2] fix clippy

---
 packages/desktop/src/protocol.rs | 2 +-
 packages/signals/src/effect.rs   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs
index 53652f82f2..2f660b7a2f 100644
--- a/packages/desktop/src/protocol.rs
+++ b/packages/desktop/src/protocol.rs
@@ -153,7 +153,7 @@ fn get_asset_root() -> Option<PathBuf> {
 
 /// Get the mime type from a path-like string
 fn get_mime_from_path(trimmed: &Path) -> Result<&'static str> {
-    if trimmed.ends_with(".svg") {
+    if trimmed.extension().is_some_and(|ext| ext == "svg") {
         return Ok("image/svg+xml");
     }
 
diff --git a/packages/signals/src/effect.rs b/packages/signals/src/effect.rs
index ad950b94bf..307ee98ab2 100644
--- a/packages/signals/src/effect.rs
+++ b/packages/signals/src/effect.rs
@@ -30,7 +30,7 @@ pub(crate) fn get_effect_stack() -> EffectStack {
         Some(rt) => rt,
         None => {
             let store = EffectStack::default();
-            provide_root_context(store.clone());
+            provide_root_context(store);
             store
         }
     }