fix signals
This commit is contained in:
1 parent
611f0d3b5f
commit
f6fd20bb61
7 files changed
+32
-67
No files matched your search
Generated
+8
@@ -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",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -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(¤t) {
|
if let Some(value) = subscribers.get(¤t) {
|
||||||
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(¤t) {
|
if let Some(value) = subscribers.get(¤t) {
|
||||||
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))
|
||||||
}
|
}
|
||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in new issue
Block a user