fix comparer

This commit is contained in:
Evan Almloff committed 2024-01-08 14:03:17 -06:00
1 parent 69a1ec0e3c
commit 78a5592d6d
6 files changed
+94 -53

No files matched your search

+71 -37
View File
@@ -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
View File
@@ -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)
}
}