fix signals

This commit is contained in:
Evan Almloff 2024-01-16 13:57:31 -06:00
parent 611f0d3b5f
commit f6fd20bb61
7 changed files with 32 additions and 67 deletions

8
Cargo.lock generated
View file

@ -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",
]

View file

@ -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))
}

View file

@ -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();

View file

@ -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();

View file

@ -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 {

View file

@ -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(),
});

View file

@ -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 {