Browse Source

fix signals

Evan Almloff 1 year ago
parent
commit
f6fd20bb61

+ 8 - 0
Cargo.lock

@@ -2881,11 +2881,17 @@ dependencies = [
  "dioxus",
  "dioxus-core",
  "dioxus-desktop",
+ "futures-channel",
+ "futures-util",
  "generational-box",
+ "once_cell",
+ "parking_lot",
+ "rustc-hash",
  "serde",
  "simple_logger",
  "tokio",
  "tracing",
+ "tracing-subscriber",
 ]
 
 [[package]]
@@ -3868,6 +3874,8 @@ dependencies = [
 name = "generational-box"
 version = "0.4.3"
 dependencies = [
+ "criterion 0.3.6",
+ "parking_lot",
  "rand 0.8.5",
 ]
 

+ 6 - 6
packages/signals/src/comparer.rs

@@ -27,14 +27,14 @@ impl<R: Eq + Hash> Comparer<R> {
 
             if let Some(previous) = previous.take() {
                 if let Some(value) = subscribers.get(&previous) {
-                    value.set(false);
+                    *value.write_unchecked() = false;
                 }
             }
 
             let current = f();
 
             if let Some(value) = subscribers.get(&current) {
-                value.set(true);
+                *value.write_unchecked() = true;
             }
 
             *previous = Some(current);
@@ -59,14 +59,14 @@ impl<R: Eq + Hash, S: Storage<SignalData<bool>>> Comparer<R, S> {
 
             if let Some(previous) = previous.take() {
                 if let Some(value) = subscribers.get(&previous) {
-                    value.set(false);
+                    *value.write_unchecked() = false;
                 }
             }
 
             let current = f();
 
             if let Some(value) = subscribers.get(&current) {
-                value.set(true);
+                *value.write_unchecked() = true;
             }
 
             *previous = Some(current);
@@ -136,6 +136,6 @@ impl<R, S: Storage<SignalData<bool>>> Copy for Comparer<R, S> {}
 /// }
 /// ```
 #[must_use]
-pub fn use_comparer<R: Eq + Hash>(cx: &ScopeState, f: impl FnMut() -> R + 'static) -> Comparer<R> {
-    *cx.use_hook(move || Comparer::new(f))
+pub fn use_comparer<R: Eq + Hash>(f: impl FnMut() -> R + 'static) -> Comparer<R> {
+    use_hook(move || Comparer::new(f))
 }

+ 1 - 2
packages/signals/src/effect.rs

@@ -7,8 +7,7 @@ use parking_lot::RwLock;
 use rustc_hash::FxHashMap;
 use std::fmt::{self, Formatter};
 
-use crate::use_signal;
-use crate::{dependency::Dependency, CopyValue};
+use crate::CopyValue;
 
 thread_local! {
     pub(crate)static EFFECT_STACK: EffectStack = EffectStack::default();

+ 4 - 40
packages/signals/src/impls.rs

@@ -177,42 +177,6 @@ macro_rules! write_impls {
                 self.with_mut(|v| v.split_off(at))
             }
         }
-
-        impl<T: 'static> $ty<Option<T>> {
-            /// Takes the value out of the Option.
-            #[track_caller]
-            pub fn take(&mut self) -> Option<T> {
-                self.with_mut(|v| v.take())
-            }
-
-            /// Replace the value in the Option.
-            #[track_caller]
-            pub fn replace(&mut self, value: T) -> Option<T> {
-                self.with_mut(|v| v.replace(value))
-            }
-
-            /// Gets the value out of the Option, or inserts the given value if the Option is empty.
-            #[track_caller]
-            pub fn get_or_insert(&mut self, default: T) -> GenerationalRef<T> {
-                self.get_or_insert_with(|| default)
-            }
-
-            /// Gets the value out of the Option, or inserts the value returned by the given function if the Option is empty.
-            #[track_caller]
-            pub fn get_or_insert_with(
-                &mut self,
-                default: impl FnOnce() -> T,
-            ) -> GenerationalRef<T> {
-                let borrow = self.read();
-                if borrow.is_none() {
-                    drop(borrow);
-                    self.write_unchecked().replace(default());
-                    GenerationalRef::map(self.read(), |v| v.as_ref().unwrap())
-                } else {
-                    GenerationalRef::map(borrow, |v| v.as_ref().unwrap())
-                }
-            }
-        }
     };
 }
 
@@ -324,23 +288,23 @@ write_impls!(Signal, Storage<SignalData<T>>, Storage<SignalData<Vec<T>>>);
 
 impl<T: 'static, S: Storage<SignalData<Option<T>>>> Signal<Option<T>, S> {
     /// Takes the value out of the Option.
-    pub fn take(&self) -> Option<T> {
+    pub fn take(&mut self) -> Option<T> {
         self.with_mut(|v| v.take())
     }
 
     /// Replace the value in the Option.
-    pub fn replace(&self, value: T) -> Option<T> {
+    pub fn replace(&mut self, value: T) -> Option<T> {
         self.with_mut(|v| v.replace(value))
     }
 
     /// Gets the value out of the Option, or inserts the given value if the Option is empty.
-    pub fn get_or_insert(&self, default: T) -> <<S::Ref as Mappable<SignalData<Option<T>>>>::Mapped<Option<T>> as Mappable<Option<T>>>::Mapped<T>{
+    pub fn get_or_insert(&mut self, default: T) -> <<S::Ref as Mappable<SignalData<Option<T>>>>::Mapped<Option<T>> as Mappable<Option<T>>>::Mapped<T>{
         self.get_or_insert_with(|| default)
     }
 
     /// Gets the value out of the Option, or inserts the value returned by the given function if the Option is empty.
     pub fn get_or_insert_with(
-        &self,
+        &mut self,
         default: impl FnOnce() -> T,
     ) -><<S::Ref as Mappable<SignalData<Option<T>>>>::Mapped<Option<T>> as Mappable<Option<T>>>::Mapped<T>{
         let borrow = self.read();

+ 4 - 4
packages/signals/src/rt.rs

@@ -23,7 +23,7 @@ fn current_owner<S: Storage<T>, T>() -> Rc<Owner<S>> {
             Some(rt) => rt,
             None => {
                 let owner = Rc::new(S::owner());
-                provide_context(owner).expect("in a virtual dom")
+                provide_context(owner)
             }
         },
     }
@@ -34,7 +34,7 @@ fn owner_in_scope<S: Storage<T>, T>(scope: ScopeId) -> Rc<Owner<S>> {
         Some(rt) => rt,
         None => {
             let owner = Rc::new(S::owner());
-            provide_context_to_scope(scope, owner).expect("in a virtual dom")
+            scope.provide_context(owner)
         }
     }
 }
@@ -159,7 +159,7 @@ impl<T: 'static, S: Storage<T>> CopyValue<T, S> {
         self.value.try_write()
     }
 
-    pub fn write_unchecked(&self) -> GenerationalRefMut<T> {
+    pub fn write_unchecked(&self) -> S::Mut {
         self.value.write()
     }
 
@@ -205,7 +205,7 @@ impl<T: 'static, S: Storage<T>> PartialEq for CopyValue<T, S> {
     }
 }
 
-impl<T, S: Storage<T>> Deref for CopyValue<T, S> {
+impl<T: Copy, S: Storage<T>> Deref for CopyValue<T, S> {
     type Target = dyn Fn() -> T;
 
     fn deref(&self) -> &Self::Target {

+ 5 - 8
packages/signals/src/selector.rs

@@ -72,14 +72,13 @@ pub fn use_maybe_sync_selector<R: PartialEq, S: Storage<SignalData<R>>>(
 #[track_caller]
 #[must_use = "Consider using `use_effect` to rerun a callback when dependencies change"]
 pub fn use_selector_with_dependencies<R: PartialEq, D: Dependency>(
-    cx: &ScopeState,
     dependencies: D,
     f: impl FnMut(D::Out) -> R + 'static,
 ) -> ReadOnlySignal<R>
 where
     D::Out: 'static,
 {
-    use_maybe_sync_selector_with_dependencies(cx, dependencies, f)
+    use_maybe_sync_selector_with_dependencies(dependencies, f)
 }
 
 /// Creates a new Selector that may be sync with some local dependencies. The selector will be run immediately and whenever any signal it reads or any dependencies it tracks changes
@@ -105,15 +104,14 @@ pub fn use_maybe_sync_selector_with_dependencies<
     D: Dependency,
     S: Storage<SignalData<R>>,
 >(
-    cx: &ScopeState,
     dependencies: D,
     mut f: impl FnMut(D::Out) -> R + 'static,
 ) -> ReadOnlySignal<R, S>
 where
     D::Out: 'static,
 {
-    let dependencies_signal = use_signal(cx, || dependencies.out());
-    let selector = *cx.use_hook(|| {
+    let mut dependencies_signal = use_signal(|| dependencies.out());
+    let selector = use_hook(|| {
         maybe_sync_selector(move || {
             let deref = &*dependencies_signal.read();
             f(deref.clone())
@@ -141,7 +139,7 @@ pub fn selector<R: PartialEq>(f: impl FnMut() -> R + 'static) -> ReadOnlySignal<
 pub fn maybe_sync_selector<R: PartialEq, S: Storage<SignalData<R>>>(
     mut f: impl FnMut() -> R + 'static,
 ) -> ReadOnlySignal<R, S> {
-    let state = Signal::<R, S> {
+    let mut state = Signal::<R, S> {
         inner: CopyValue::invalid(),
     };
     let effect = Effect {
@@ -154,8 +152,7 @@ pub fn maybe_sync_selector<R: PartialEq, S: Storage<SignalData<R>>>(
     }
     state.inner.value.set(SignalData {
         subscribers: Default::default(),
-        effect_subscribers: Default::default(),
-        update_any: schedule_update_any().expect("in a virtual dom"),
+        update_any: schedule_update_any(),
         value: f(),
         effect_ref: get_effect_ref(),
     });

+ 4 - 7
packages/signals/src/signal.rs

@@ -104,13 +104,10 @@ pub fn use_signal<T: 'static>(f: impl FnOnce() -> T) -> Signal<T, UnsyncStorage>
 /// ```
 #[must_use]
 #[track_caller]
-pub fn use_signal_sync<T: Send + Sync + 'static>(
-    cx: &ScopeState,
-    f: impl FnOnce() -> T,
-) -> Signal<T, SyncStorage> {
+pub fn use_signal_sync<T: Send + Sync + 'static>(f: impl FnOnce() -> T) -> Signal<T, SyncStorage> {
     #[cfg(debug_assertions)]
     let caller = std::panic::Location::caller();
-    *cx.use_hook(|| {
+    use_hook(|| {
         Signal::new_with_caller(
             f(),
             #[cfg(debug_assertions)]
@@ -467,7 +464,7 @@ impl<T: 'static, S: Storage<SignalData<T>>> PartialEq for Signal<T, S> {
 /// Allow calling a signal with signal() syntax
 ///
 /// Currently only limited to copy types, though could probably specialize for string/arc/rc
-impl<T, S: Storage<SignalData<T>> + 'static> Deref for Signal<T, S> {
+impl<T: Copy, S: Storage<SignalData<T>> + 'static> Deref for Signal<T, S> {
     type Target = dyn Fn() -> T;
 
     fn deref(&self) -> &Self::Target {
@@ -634,7 +631,7 @@ impl<T: 'static, S: Storage<SignalData<T>>> PartialEq for ReadOnlySignal<T, S> {
     }
 }
 
-impl<T, S: Storage<SignalData<T>> + 'static> Deref for ReadOnlySignal<T, S> {
+impl<T: Copy, S: Storage<SignalData<T>> + 'static> Deref for ReadOnlySignal<T, S> {
     type Target = dyn Fn() -> T;
 
     fn deref(&self) -> &Self::Target {