mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 04:33:06 +00:00
fix comparer
This commit is contained in:
parent
69a1ec0e3c
commit
78a5592d6d
6 changed files with 94 additions and 53 deletions
|
@ -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}" }
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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(¤t) {
|
||||
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(¤t) {
|
||||
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(¤t) {
|
||||
value.set(true);
|
||||
}
|
||||
|
||||
*previous = Some(current);
|
||||
});
|
||||
|
||||
Comparer { subscribers }
|
||||
*cx.use_hook(move || Comparer::new(f))
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,9 +32,7 @@ async fn effects_rerun() {
|
|||
});
|
||||
signal += 1;
|
||||
|
||||
render! {
|
||||
div {}
|
||||
}
|
||||
render! { div {} }
|
||||
},
|
||||
counter.clone(),
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue