fix signals

This commit is contained in:
Evan Almloff committed 2024-01-16 13:57:31 -06:00
1 parent 611f0d3b5f
commit f6fd20bb61
7 files changed
+32 -67

No files matched your search

Generated
+8
View File
@@ -2881,11 +2881,17 @@ dependencies = [
"dioxus", "dioxus",
"dioxus-core", "dioxus-core",
"dioxus-desktop", "dioxus-desktop",
"futures-channel",
"futures-util",
"generational-box", "generational-box",
"once_cell",
"parking_lot",
"rustc-hash",
"serde", "serde",
"simple_logger", "simple_logger",
"tokio", "tokio",
"tracing", "tracing",
"tracing-subscriber",
] ]
[[package]] [[package]]
@@ -3868,6 +3874,8 @@ dependencies = [
name = "generational-box" name = "generational-box"
version = "0.4.3" version = "0.4.3"
dependencies = [ dependencies = [
"criterion 0.3.6",
"parking_lot",
"rand 0.8.5", "rand 0.8.5",
] ]
+6 -6
View File
@@ -27,14 +27,14 @@ impl<R: Eq + Hash> Comparer<R> {
if let Some(previous) = previous.take() { if let Some(previous) = previous.take() {
if let Some(value) = subscribers.get(&previous) { if let Some(value) = subscribers.get(&previous) {
value.set(false); *value.write_unchecked() = false;
} }
} }
let current = f(); let current = f();
if let Some(value) = subscribers.get(&current) { if let Some(value) = subscribers.get(&current) {
value.set(true); *value.write_unchecked() = true;
} }
*previous = Some(current); *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(previous) = previous.take() {
if let Some(value) = subscribers.get(&previous) { if let Some(value) = subscribers.get(&previous) {
value.set(false); *value.write_unchecked() = false;
} }
} }
let current = f(); let current = f();
if let Some(value) = subscribers.get(&current) { if let Some(value) = subscribers.get(&current) {
value.set(true); *value.write_unchecked() = true;
} }
*previous = Some(current); *previous = Some(current);
@@ -136,6 +136,6 @@ impl<R, S: Storage<SignalData<bool>>> Copy for Comparer<R, S> {}
/// } /// }
/// ``` /// ```
#[must_use] #[must_use]
pub fn use_comparer<R: Eq + Hash>(cx: &ScopeState, f: impl FnMut() -> R + 'static) -> Comparer<R> { pub fn use_comparer<R: Eq + Hash>(f: impl FnMut() -> R + 'static) -> Comparer<R> {
*cx.use_hook(move || Comparer::new(f)) use_hook(move || Comparer::new(f))
} }
+1 -2
View File
@@ -7,8 +7,7 @@ use parking_lot::RwLock;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use std::fmt::{self, Formatter}; use std::fmt::{self, Formatter};
use crate::use_signal; use crate::CopyValue;
use crate::{dependency::Dependency, CopyValue};
thread_local! { thread_local! {
pub(crate)static EFFECT_STACK: EffectStack = EffectStack::default(); pub(crate)static EFFECT_STACK: EffectStack = EffectStack::default();
+4 -40
View File
@@ -177,42 +177,6 @@ macro_rules! write_impls {
self.with_mut(|v| v.split_off(at)) 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> { impl<T: 'static, S: Storage<SignalData<Option<T>>>> Signal<Option<T>, S> {
/// Takes the value out of the Option. /// 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()) self.with_mut(|v| v.take())
} }
/// Replace the value in the Option. /// 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)) self.with_mut(|v| v.replace(value))
} }
/// Gets the value out of the Option, or inserts the given value if the Option is empty. /// 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) 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. /// 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( pub fn get_or_insert_with(
&self, &mut self,
default: impl FnOnce() -> T, default: impl FnOnce() -> T,
) -><<S::Ref as Mappable<SignalData<Option<T>>>>::Mapped<Option<T>> as Mappable<Option<T>>>::Mapped<T>{ ) -><<S::Ref as Mappable<SignalData<Option<T>>>>::Mapped<Option<T>> as Mappable<Option<T>>>::Mapped<T>{
let borrow = self.read(); let borrow = self.read();
+4 -4
View File
@@ -23,7 +23,7 @@ fn current_owner<S: Storage<T>, T>() -> Rc<Owner<S>> {
Some(rt) => rt, Some(rt) => rt,
None => { None => {
let owner = Rc::new(S::owner()); 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, Some(rt) => rt,
None => { None => {
let owner = Rc::new(S::owner()); 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() self.value.try_write()
} }
pub fn write_unchecked(&self) -> GenerationalRefMut<T> { pub fn write_unchecked(&self) -> S::Mut {
self.value.write() 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; type Target = dyn Fn() -> T;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
+5 -8
View File
@@ -72,14 +72,13 @@ pub fn use_maybe_sync_selector<R: PartialEq, S: Storage<SignalData<R>>>(
#[track_caller] #[track_caller]
#[must_use = "Consider using `use_effect` to rerun a callback when dependencies change"] #[must_use = "Consider using `use_effect` to rerun a callback when dependencies change"]
pub fn use_selector_with_dependencies<R: PartialEq, D: Dependency>( pub fn use_selector_with_dependencies<R: PartialEq, D: Dependency>(
cx: &ScopeState,
dependencies: D, dependencies: D,
f: impl FnMut(D::Out) -> R + 'static, f: impl FnMut(D::Out) -> R + 'static,
) -> ReadOnlySignal<R> ) -> ReadOnlySignal<R>
where where
D::Out: 'static, 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 /// 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, D: Dependency,
S: Storage<SignalData<R>>, S: Storage<SignalData<R>>,
>( >(
cx: &ScopeState,
dependencies: D, dependencies: D,
mut f: impl FnMut(D::Out) -> R + 'static, mut f: impl FnMut(D::Out) -> R + 'static,
) -> ReadOnlySignal<R, S> ) -> ReadOnlySignal<R, S>
where where
D::Out: 'static, D::Out: 'static,
{ {
let dependencies_signal = use_signal(cx, || dependencies.out()); let mut dependencies_signal = use_signal(|| dependencies.out());
let selector = *cx.use_hook(|| { let selector = use_hook(|| {
maybe_sync_selector(move || { maybe_sync_selector(move || {
let deref = &*dependencies_signal.read(); let deref = &*dependencies_signal.read();
f(deref.clone()) 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>>>( pub fn maybe_sync_selector<R: PartialEq, S: Storage<SignalData<R>>>(
mut f: impl FnMut() -> R + 'static, mut f: impl FnMut() -> R + 'static,
) -> ReadOnlySignal<R, S> { ) -> ReadOnlySignal<R, S> {
let state = Signal::<R, S> { let mut state = Signal::<R, S> {
inner: CopyValue::invalid(), inner: CopyValue::invalid(),
}; };
let effect = Effect { let effect = Effect {
@@ -154,8 +152,7 @@ pub fn maybe_sync_selector<R: PartialEq, S: Storage<SignalData<R>>>(
} }
state.inner.value.set(SignalData { state.inner.value.set(SignalData {
subscribers: Default::default(), subscribers: Default::default(),
effect_subscribers: Default::default(), update_any: schedule_update_any(),
update_any: schedule_update_any().expect("in a virtual dom"),
value: f(), value: f(),
effect_ref: get_effect_ref(), effect_ref: get_effect_ref(),
}); });
+4 -7
View File
@@ -104,13 +104,10 @@ pub fn use_signal<T: 'static>(f: impl FnOnce() -> T) -> Signal<T, UnsyncStorage>
/// ``` /// ```
#[must_use] #[must_use]
#[track_caller] #[track_caller]
pub fn use_signal_sync<T: Send + Sync + 'static>( pub fn use_signal_sync<T: Send + Sync + 'static>(f: impl FnOnce() -> T) -> Signal<T, SyncStorage> {
cx: &ScopeState,
f: impl FnOnce() -> T,
) -> Signal<T, SyncStorage> {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
let caller = std::panic::Location::caller(); let caller = std::panic::Location::caller();
*cx.use_hook(|| { use_hook(|| {
Signal::new_with_caller( Signal::new_with_caller(
f(), f(),
#[cfg(debug_assertions)] #[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 /// Allow calling a signal with signal() syntax
/// ///
/// Currently only limited to copy types, though could probably specialize for string/arc/rc /// 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; type Target = dyn Fn() -> T;
fn deref(&self) -> &Self::Target { 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; type Target = dyn Fn() -> T;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {