Browse Source

fix comparer

Evan Almloff 1 year ago
parent
commit
78a5592d6d

+ 1 - 1
examples/compose.rs

@@ -61,7 +61,7 @@ fn compose(cx: Scope<ComposeProps>) -> Element {
                 },
                 "Click to send"
             }
-          
+
             input { oninput: move |e| user_input.set(e.value()), value: "{user_input}" }
         }
     })

+ 18 - 3
packages/core/tests/event_propagation.rs

@@ -12,7 +12,12 @@ fn events_propagate() {
     _ = dom.rebuild();
 
     // Top-level click is registered
-    dom.handle_event("click", Rc::new(PlatformEventData::new(Box::<SerializedMouseData>::default())), ElementId(1), true);
+    dom.handle_event(
+        "click",
+        Rc::new(PlatformEventData::new(Box::<SerializedMouseData>::default())),
+        ElementId(1),
+        true,
+    );
     assert_eq!(*CLICKS.lock().unwrap(), 1);
 
     // break reference....
@@ -22,7 +27,12 @@ fn events_propagate() {
     }
 
     // Lower click is registered
-    dom.handle_event("click", Rc::new(PlatformEventData::new(Box::<SerializedMouseData>::default())), ElementId(2), true);
+    dom.handle_event(
+        "click",
+        Rc::new(PlatformEventData::new(Box::<SerializedMouseData>::default())),
+        ElementId(2),
+        true,
+    );
     assert_eq!(*CLICKS.lock().unwrap(), 3);
 
     // break reference....
@@ -32,7 +42,12 @@ fn events_propagate() {
     }
 
     // Stop propagation occurs
-    dom.handle_event("click", Rc::new(PlatformEventData::new(Box::<SerializedMouseData>::default())), ElementId(2), true);
+    dom.handle_event(
+        "click",
+        Rc::new(PlatformEventData::new(Box::<SerializedMouseData>::default())),
+        ElementId(2),
+        true,
+    );
     assert_eq!(*CLICKS.lock().unwrap(), 3);
 }
 

+ 1 - 1
packages/desktop/src/lib.rs

@@ -149,7 +149,7 @@ pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, cfg: Config)
 
     // Copy over any assets we find
     crate::collect_assets::copy_assets();
-  
+
     // Set the event converter
     dioxus_html::set_event_converter(Box::new(SerializedHtmlEventConverter));
 

+ 71 - 37
packages/signals/src/comparer.rs

@@ -1,19 +1,82 @@
 use std::hash::Hash;
 
 use dioxus_core::prelude::*;
+use generational_box::{Storage, UnsyncStorage};
 
-use crate::{CopyValue, Effect, ReadOnlySignal, Signal};
+use crate::{CopyValue, Effect, ReadOnlySignal, Signal, SignalData};
 use rustc_hash::FxHashMap;
 
 /// An object that can efficiently compare a value to a set of values.
 #[derive(Debug)]
-pub struct Comparer<R: 'static> {
-    subscribers: CopyValue<FxHashMap<R, Signal<bool>>>,
+pub struct Comparer<R: 'static, S: Storage<SignalData<bool>> = UnsyncStorage> {
+    subscribers: CopyValue<FxHashMap<R, Signal<bool, S>>>,
 }
 
 impl<R: Eq + Hash> Comparer<R> {
+    /// Creates a new Comparer which efficiently tracks when a value changes to check if it is equal to a set of values.
+    ///
+    /// Generally, you shouldn't need to use this hook. Instead you can use [`crate::use_selector`]. If you have many values that you need to compare to a single value, this hook will change updates from O(n) to O(1) where n is the number of values you are comparing to.
+    pub fn new(mut f: impl FnMut() -> R + 'static) -> Comparer<R> {
+        let subscribers: CopyValue<FxHashMap<R, Signal<bool>>> =
+            CopyValue::new(FxHashMap::default());
+        let previous = CopyValue::new(None);
+
+        Effect::new(move || {
+            let subscribers = subscribers.read();
+            let mut previous = previous.write();
+
+            if let Some(previous) = previous.take() {
+                if let Some(value) = subscribers.get(&previous) {
+                    value.set(false);
+                }
+            }
+
+            let current = f();
+
+            if let Some(value) = subscribers.get(&current) {
+                value.set(true);
+            }
+
+            *previous = Some(current);
+        });
+
+        Comparer { subscribers }
+    }
+}
+
+impl<R: Eq + Hash, S: Storage<SignalData<bool>>> Comparer<R, S> {
+    /// Creates a new Comparer that may be `Sync + Send` which efficiently tracks when a value changes to check if it is equal to a set of values.
+    ///
+    /// Generally, you shouldn't need to use this hook. Instead you can use [`crate::use_selector`]. If you have many values that you need to compare to a single value, this hook will change updates from O(n) to O(1) where n is the number of values you are comparing to.
+    pub fn new_maybe_sync(mut f: impl FnMut() -> R + 'static) -> Comparer<R> {
+        let subscribers: CopyValue<FxHashMap<R, Signal<bool>>> =
+            CopyValue::new(FxHashMap::default());
+        let previous = CopyValue::new(None);
+
+        Effect::new(move || {
+            let subscribers = subscribers.read();
+            let mut previous = previous.write();
+
+            if let Some(previous) = previous.take() {
+                if let Some(value) = subscribers.get(&previous) {
+                    value.set(false);
+                }
+            }
+
+            let current = f();
+
+            if let Some(value) = subscribers.get(&current) {
+                value.set(true);
+            }
+
+            *previous = Some(current);
+        });
+
+        Comparer { subscribers }
+    }
+
     /// Returns a signal which is true when the value is equal to the value passed to this function.
-    pub fn equal(&self, value: R) -> ReadOnlySignal<bool> {
+    pub fn equal(&self, value: R) -> ReadOnlySignal<bool, S> {
         let subscribers = self.subscribers.read();
 
         match subscribers.get(&value) {
@@ -21,7 +84,7 @@ impl<R: Eq + Hash> Comparer<R> {
             None => {
                 drop(subscribers);
                 let mut subscribers = self.subscribers.write();
-                let signal = Signal::new(false);
+                let signal = Signal::new_maybe_sync(false);
                 subscribers.insert(value, signal);
                 signal.into()
             }
@@ -29,13 +92,13 @@ impl<R: Eq + Hash> Comparer<R> {
     }
 }
 
-impl<R> Clone for Comparer<R> {
+impl<R, S: Storage<SignalData<bool>>> Clone for Comparer<R, S> {
     fn clone(&self) -> Self {
         *self
     }
 }
 
-impl<R> Copy for Comparer<R> {}
+impl<R, S: Storage<SignalData<bool>>> Copy for Comparer<R, S> {}
 
 /// Creates a new Comparer which efficiently tracks when a value changes to check if it is equal to a set of values.
 ///
@@ -74,34 +137,5 @@ impl<R> Copy for Comparer<R> {}
 /// ```
 #[must_use]
 pub fn use_comparer<R: Eq + Hash>(cx: &ScopeState, f: impl FnMut() -> R + 'static) -> Comparer<R> {
-    *cx.use_hook(move || comparer(f))
-}
-
-/// Creates a new Comparer which efficiently tracks when a value changes to check if it is equal to a set of values.
-///
-/// Generally, you shouldn't need to use this hook. Instead you can use [`crate::use_selector`]. If you have many values that you need to compare to a single value, this hook will change updates from O(n) to O(1) where n is the number of values you are comparing to.
-pub fn comparer<R: Eq + Hash>(mut f: impl FnMut() -> R + 'static) -> Comparer<R> {
-    let subscribers: CopyValue<FxHashMap<R, Signal<bool>>> = CopyValue::new(FxHashMap::default());
-    let previous = CopyValue::new(None);
-
-    Effect::new(move || {
-        let subscribers = subscribers.read();
-        let mut previous = previous.write();
-
-        if let Some(previous) = previous.take() {
-            if let Some(value) = subscribers.get(&previous) {
-                value.set(false);
-            }
-        }
-
-        let current = f();
-
-        if let Some(value) = subscribers.get(&current) {
-            value.set(true);
-        }
-
-        *previous = Some(current);
-    });
-
-    Comparer { subscribers }
+    *cx.use_hook(move || Comparer::new(f))
 }

+ 2 - 8
packages/signals/src/signal.rs

@@ -536,8 +536,8 @@ pub struct ReadOnlySignal<T: 'static, S: Storage<SignalData<T>> = UnsyncStorage>
     inner: Signal<T, S>,
 }
 
-impl<T: 'static> From<Signal<T>> for ReadOnlySignal<T> {
-    fn from(inner: Signal<T>) -> Self {
+impl<T: 'static, S: Storage<SignalData<T>>> From<Signal<T, S>> for ReadOnlySignal<T, S> {
+    fn from(inner: Signal<T, S>) -> Self {
         Self { inner }
     }
 }
@@ -634,9 +634,3 @@ impl<T, S: Storage<SignalData<T>> + 'static> Deref for ReadOnlySignal<T, S> {
         reference_to_closure as &Self::Target
     }
 }
-
-impl<T> From<Signal<T>> for ReadOnlySignal<T> {
-    fn from(signal: Signal<T>) -> Self {
-        Self::new(signal)
-    }
-}

+ 1 - 3
packages/signals/tests/effect.rs

@@ -32,9 +32,7 @@ async fn effects_rerun() {
             });
             signal += 1;
 
-            render! {
-                div {}
-            }
+            render! { div {} }
         },
         counter.clone(),
     );