and mut bound to mut methods on signals
This commit is contained in:
31 files changed
+129
-153
No files matched your search
@@ -477,13 +477,13 @@ impl Display for AlreadyBorrowedError {
|
||||
impl std::error::Error for AlreadyBorrowedError {}
|
||||
|
||||
/// A reference to a value in a generational box.
|
||||
pub struct GenerationalRef<T: 'static> {
|
||||
inner: Ref<'static, T>,
|
||||
pub struct GenerationalRef<'a, T: 'static> {
|
||||
inner: Ref<'a, T>,
|
||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||
borrow: GenerationalRefBorrowInfo,
|
||||
}
|
||||
|
||||
impl<T: 'static> GenerationalRef<T> {
|
||||
impl<'a, T: 'static> GenerationalRef<'a, T> {
|
||||
/// Map one ref type to another.
|
||||
pub fn map<U, F>(orig: GenerationalRef<T>, f: F) -> GenerationalRef<U>
|
||||
where
|
||||
@@ -500,7 +500,7 @@ impl<T: 'static> GenerationalRef<T> {
|
||||
}
|
||||
|
||||
/// Filter one ref type to another.
|
||||
pub fn filter_map<U, F>(orig: GenerationalRef<T>, f: F) -> Option<GenerationalRef<U>>
|
||||
pub fn filter_map<U, F>(orig: GenerationalRef<'a, T>, f: F) -> Option<GenerationalRef<'a, U>>
|
||||
where
|
||||
F: FnOnce(&T) -> Option<&U>,
|
||||
{
|
||||
@@ -520,7 +520,7 @@ impl<T: 'static> GenerationalRef<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Deref for GenerationalRef<T> {
|
||||
impl<T: 'static> Deref for GenerationalRef<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@@ -545,13 +545,13 @@ impl Drop for GenerationalRefBorrowInfo {
|
||||
}
|
||||
|
||||
/// A mutable reference to a value in a generational box.
|
||||
pub struct GenerationalRefMut<T: 'static> {
|
||||
inner: RefMut<'static, T>,
|
||||
pub struct GenerationalRefMut<'a, T: 'static> {
|
||||
inner: RefMut<'a, T>,
|
||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||
borrow: GenerationalRefMutBorrowInfo,
|
||||
}
|
||||
|
||||
impl<T: 'static> GenerationalRefMut<T> {
|
||||
impl<'a, T: 'static> GenerationalRefMut<'a, T> {
|
||||
/// Map one ref type to another.
|
||||
pub fn map<U, F>(orig: GenerationalRefMut<T>, f: F) -> GenerationalRefMut<U>
|
||||
where
|
||||
@@ -565,7 +565,10 @@ impl<T: 'static> GenerationalRefMut<T> {
|
||||
}
|
||||
|
||||
/// Filter one ref type to another.
|
||||
pub fn filter_map<U, F>(orig: GenerationalRefMut<T>, f: F) -> Option<GenerationalRefMut<U>>
|
||||
pub fn filter_map<U, F>(
|
||||
orig: GenerationalRefMut<'a, T>,
|
||||
f: F,
|
||||
) -> Option<GenerationalRefMut<'a, U>>
|
||||
where
|
||||
F: FnOnce(&mut T) -> Option<&mut U>,
|
||||
{
|
||||
@@ -584,7 +587,7 @@ impl<T: 'static> GenerationalRefMut<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Deref for GenerationalRefMut<T> {
|
||||
impl<'a, T: 'static> Deref for GenerationalRefMut<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@@ -592,7 +595,7 @@ impl<T: 'static> Deref for GenerationalRefMut<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> DerefMut for GenerationalRefMut<T> {
|
||||
impl<'a, T: 'static> DerefMut for GenerationalRefMut<'a, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.inner.deref_mut()
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ impl<T> Coroutine<T> {
|
||||
/// Restart this coroutine
|
||||
///
|
||||
/// Forces the component to re-render, which will re-invoke the coroutine.
|
||||
pub fn restart(&self) {
|
||||
pub fn restart(&mut self) {
|
||||
self.needs_regen.set(true);
|
||||
self.task().stop();
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ where
|
||||
T: 'static,
|
||||
F: Future<Output = T> + 'static,
|
||||
{
|
||||
let value = use_signal(|| None);
|
||||
let state = use_signal(|| UseFutureState::Pending);
|
||||
let mut value = use_signal(|| None);
|
||||
let mut state = use_signal(|| UseFutureState::Pending);
|
||||
|
||||
let task = use_signal(|| {
|
||||
// Create the user's task
|
||||
@@ -84,7 +84,7 @@ impl<T> UseFuture<T> {
|
||||
}
|
||||
|
||||
// Manually set the value in the future slot without starting the future over
|
||||
pub fn set(&self, new_value: T) {
|
||||
pub fn set(&mut self, new_value: T) {
|
||||
self.value.set(Some(new_value));
|
||||
}
|
||||
|
||||
|
||||
@@ -120,78 +120,81 @@ macro_rules! write_impls {
|
||||
|
||||
impl<T: 'static> $ty<Vec<T>> {
|
||||
/// Pushes a new value to the end of the vector.
|
||||
pub fn push(&self, value: T) {
|
||||
pub fn push(&mut self, value: T) {
|
||||
self.with_mut(|v| v.push(value))
|
||||
}
|
||||
|
||||
/// Pops the last value from the vector.
|
||||
pub fn pop(&self) -> Option<T> {
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
self.with_mut(|v| v.pop())
|
||||
}
|
||||
|
||||
/// Inserts a new value at the given index.
|
||||
pub fn insert(&self, index: usize, value: T) {
|
||||
pub fn insert(&mut self, index: usize, value: T) {
|
||||
self.with_mut(|v| v.insert(index, value))
|
||||
}
|
||||
|
||||
/// Removes the value at the given index.
|
||||
pub fn remove(&self, index: usize) -> T {
|
||||
pub fn remove(&mut self, index: usize) -> T {
|
||||
self.with_mut(|v| v.remove(index))
|
||||
}
|
||||
|
||||
/// Clears the vector, removing all values.
|
||||
pub fn clear(&self) {
|
||||
pub fn clear(&mut self) {
|
||||
self.with_mut(|v| v.clear())
|
||||
}
|
||||
|
||||
/// Extends the vector with the given iterator.
|
||||
pub fn extend(&self, iter: impl IntoIterator<Item = T>) {
|
||||
pub fn extend(&mut self, iter: impl IntoIterator<Item = T>) {
|
||||
self.with_mut(|v| v.extend(iter))
|
||||
}
|
||||
|
||||
/// Truncates the vector to the given length.
|
||||
pub fn truncate(&self, len: usize) {
|
||||
pub fn truncate(&mut self, len: usize) {
|
||||
self.with_mut(|v| v.truncate(len))
|
||||
}
|
||||
|
||||
/// Swaps two values in the vector.
|
||||
pub fn swap_remove(&self, index: usize) -> T {
|
||||
pub fn swap_remove(&mut self, index: usize) -> T {
|
||||
self.with_mut(|v| v.swap_remove(index))
|
||||
}
|
||||
|
||||
/// Retains only the values that match the given predicate.
|
||||
pub fn retain(&self, f: impl FnMut(&T) -> bool) {
|
||||
pub fn retain(&mut self, f: impl FnMut(&T) -> bool) {
|
||||
self.with_mut(|v| v.retain(f))
|
||||
}
|
||||
|
||||
/// Splits the vector into two at the given index.
|
||||
pub fn split_off(&self, at: usize) -> Vec<T> {
|
||||
pub fn split_off(&mut self, at: usize) -> Vec<T> {
|
||||
self.with_mut(|v| v.split_off(at))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> $ty<Option<T>> {
|
||||
/// 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) -> GenerationalRef<T> {
|
||||
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.
|
||||
pub fn get_or_insert_with(&self, default: impl FnOnce() -> T) -> GenerationalRef<T> {
|
||||
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.with_mut(|v| *v = Some(default()));
|
||||
self.write_unchecked().replace(default());
|
||||
GenerationalRef::map(self.read(), |v| v.as_ref().unwrap())
|
||||
} else {
|
||||
GenerationalRef::map(borrow, |v| v.as_ref().unwrap())
|
||||
@@ -281,14 +284,14 @@ impl<T: Clone + 'static> IntoIterator for Signal<Vec<T>> {
|
||||
|
||||
impl<T: 'static> Signal<Vec<T>> {
|
||||
/// Returns a reference to an element or `None` if out of bounds.
|
||||
pub fn get_mut(&self, index: usize) -> Option<Write<T, Vec<T>>> {
|
||||
pub fn get_mut(&mut self, index: usize) -> Option<Write<T, Vec<T>>> {
|
||||
Write::filter_map(self.write(), |v| v.get_mut(index))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Signal<Option<T>> {
|
||||
/// Returns a reference to an element or `None` if out of bounds.
|
||||
pub fn as_mut(&self) -> Option<Write<T, Option<T>>> {
|
||||
pub fn as_mut(&mut self) -> Option<Write<T, Option<T>>> {
|
||||
Write::filter_map(self.write(), |v| v.as_mut())
|
||||
}
|
||||
}
|
||||
@@ -151,6 +151,10 @@ impl<T: 'static> CopyValue<T> {
|
||||
self.value.try_write()
|
||||
}
|
||||
|
||||
pub fn write_unchecked(&self) -> GenerationalRefMut<T> {
|
||||
self.value.write()
|
||||
}
|
||||
|
||||
/// Write the value. If the value has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
pub fn write(&self) -> GenerationalRefMut<T> {
|
||||
@@ -188,8 +192,8 @@ impl<T: 'static> PartialEq for CopyValue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for CopyValue<T> {
|
||||
type Target = dyn Fn() -> GenerationalRef<T>;
|
||||
impl<T: 'static + Clone> Deref for CopyValue<T> {
|
||||
type Target = dyn Fn() -> T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
// https://github.com/dtolnay/case-studies/tree/master/callable-types
|
||||
@@ -197,7 +201,7 @@ impl<T> Deref for CopyValue<T> {
|
||||
// First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
|
||||
let uninit_callable = MaybeUninit::<Self>::uninit();
|
||||
// Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
|
||||
let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() });
|
||||
let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() }).clone();
|
||||
|
||||
// Check that the size of the closure is the same as the size of Self in case the compiler changed the layout of the closure.
|
||||
let size_of_closure = std::mem::size_of_val(&uninit_closure);
|
||||
|
||||
@@ -26,49 +26,11 @@ pub fn use_selector<R: PartialEq>(f: impl FnMut() -> R + 'static) -> ReadOnlySig
|
||||
use_hook(|| selector(f))
|
||||
}
|
||||
|
||||
/// Creates a new Selector with some local dependencies. The selector will be run immediately and whenever any signal it reads or any dependencies it tracks changes
|
||||
///
|
||||
/// Selectors can be used to efficiently compute derived data from signals.
|
||||
///
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
/// use dioxus_signals::*;
|
||||
///
|
||||
/// fn App() -> Element {
|
||||
/// let mut local_state = use_signal(|| 0);
|
||||
/// let double = use_selector_with_dependencies((local_state.get(),), move |(local_state,)| local_state * 2);
|
||||
/// local_state.set(1);
|
||||
///
|
||||
/// render! { "{double}" }
|
||||
/// }
|
||||
/// ```
|
||||
#[must_use = "Consider using `use_effect` to rerun a callback when dependencies change"]
|
||||
pub fn use_selector_with_dependencies<R: PartialEq, D: Dependency>(
|
||||
dependencies: D,
|
||||
mut f: impl FnMut(D::Out) -> R + 'static,
|
||||
) -> ReadOnlySignal<R>
|
||||
where
|
||||
D::Out: 'static,
|
||||
{
|
||||
let dependencies_signal = use_signal(|| dependencies.out());
|
||||
let selector = use_hook(|| {
|
||||
selector(move || {
|
||||
let deref = &*dependencies_signal.read();
|
||||
f(deref.clone())
|
||||
})
|
||||
});
|
||||
let changed = { dependencies.changed(&*dependencies_signal.read()) };
|
||||
if changed {
|
||||
dependencies_signal.set(dependencies.out());
|
||||
}
|
||||
selector
|
||||
}
|
||||
|
||||
/// Creates a new Selector. The selector will be run immediately and whenever any signal it reads changes.
|
||||
///
|
||||
/// Selectors can be used to efficiently compute derived data from signals.
|
||||
pub fn selector<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> ReadOnlySignal<R> {
|
||||
let state = Signal::<R> {
|
||||
let mut state = Signal::<R> {
|
||||
inner: CopyValue::invalid(),
|
||||
};
|
||||
let effect = Effect {
|
||||
|
||||
@@ -210,7 +210,7 @@ impl<T: 'static> Signal<T> {
|
||||
///
|
||||
/// If the signal has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
pub fn read(&self) -> GenerationalRef<T> {
|
||||
pub fn read<'a>(&'a self) -> GenerationalRef<'a, T> {
|
||||
let inner = self.inner.read();
|
||||
if let Some(effect) = inner.effect_stack.current() {
|
||||
let mut effect_subscribers = inner.effect_subscribers.borrow_mut();
|
||||
@@ -245,11 +245,8 @@ impl<T: 'static> Signal<T> {
|
||||
GenerationalRef::map(inner, |v| &v.value)
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the signal's value.
|
||||
///
|
||||
/// If the signal has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
pub fn write(&self) -> Write<T> {
|
||||
/// Write to the value through an immutable reference.
|
||||
pub fn write_unchecked(&self) -> Write<T> {
|
||||
let inner = self.inner.write();
|
||||
let borrow = GenerationalRefMut::map(inner, |v| &mut v.value);
|
||||
Write {
|
||||
@@ -258,6 +255,14 @@ impl<T: 'static> Signal<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the signal's value.
|
||||
///
|
||||
/// If the signal has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
pub fn write<'a>(&'a mut self) -> Write<'a, T> {
|
||||
self.write_unchecked()
|
||||
}
|
||||
|
||||
fn update_subscribers(&self) {
|
||||
{
|
||||
let inner = self.inner.read();
|
||||
@@ -288,7 +293,7 @@ impl<T: 'static> Signal<T> {
|
||||
|
||||
/// Set the value of the signal. This will trigger an update on all subscribers.
|
||||
#[track_caller]
|
||||
pub fn set(&self, value: T) {
|
||||
pub fn set(&mut self, value: T) {
|
||||
*self.write() = value;
|
||||
}
|
||||
|
||||
@@ -311,7 +316,7 @@ impl<T: 'static> Signal<T> {
|
||||
/// Run a closure with a mutable reference to the signal's value.
|
||||
/// If the signal has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
pub fn with_mut<O>(&self, f: impl FnOnce(&mut T) -> O) -> O {
|
||||
pub fn with_mut<O>(&mut self, f: impl FnOnce(&mut T) -> O) -> O {
|
||||
let mut write = self.write();
|
||||
f(&mut *write)
|
||||
}
|
||||
@@ -337,7 +342,7 @@ impl<T: Clone + 'static> Signal<T> {
|
||||
|
||||
impl Signal<bool> {
|
||||
/// Invert the boolean value of the signal. This will trigger an update on all subscribers.
|
||||
pub fn toggle(&self) {
|
||||
pub fn toggle(&mut self) {
|
||||
self.set(!self.cloned());
|
||||
}
|
||||
}
|
||||
@@ -351,7 +356,7 @@ impl<T: 'static> PartialEq for Signal<T> {
|
||||
/// Allow calling a signal with signal() syntax
|
||||
///
|
||||
/// Currently only limited to copy types, though could probably specialize for string/arc/rc
|
||||
impl<T: Copy + Clone> Deref for Signal<T> {
|
||||
impl<T: Copy> Deref for Signal<T> {
|
||||
type Target = dyn Fn() -> T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@@ -360,10 +365,7 @@ impl<T: Copy + Clone> Deref for Signal<T> {
|
||||
// First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
|
||||
let uninit_callable = MaybeUninit::<Self>::uninit();
|
||||
// Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
|
||||
let uninit_closure = move || {
|
||||
let res = Self::read(unsafe { &*uninit_callable.as_ptr() });
|
||||
res.clone()
|
||||
};
|
||||
let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() }).clone();
|
||||
|
||||
// Check that the size of the closure is the same as the size of Self in case the compiler changed the layout of the closure.
|
||||
let size_of_closure = std::mem::size_of_val(&uninit_closure);
|
||||
@@ -398,14 +400,14 @@ impl<T: 'static> Drop for SignalSubscriberDrop<T> {
|
||||
}
|
||||
|
||||
/// A mutable reference to a signal's value.
|
||||
pub struct Write<T: 'static, I: 'static = T> {
|
||||
write: GenerationalRefMut<T>,
|
||||
pub struct Write<'a, T: 'static, I: 'static = T> {
|
||||
write: GenerationalRefMut<'a, T>,
|
||||
signal: SignalSubscriberDrop<I>,
|
||||
}
|
||||
|
||||
impl<T: 'static, I: 'static> Write<T, I> {
|
||||
impl<'a, T: 'static, I: 'static> Write<'a, T, I> {
|
||||
/// Map the mutable reference to the signal's value to a new type.
|
||||
pub fn map<O>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<O, I> {
|
||||
pub fn map<O>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<'a, O, I> {
|
||||
let Self { write, signal } = myself;
|
||||
Write {
|
||||
write: GenerationalRefMut::map(write, f),
|
||||
@@ -417,14 +419,14 @@ impl<T: 'static, I: 'static> Write<T, I> {
|
||||
pub fn filter_map<O>(
|
||||
myself: Self,
|
||||
f: impl FnOnce(&mut T) -> Option<&mut O>,
|
||||
) -> Option<Write<O, I>> {
|
||||
) -> Option<Write<'a, O, I>> {
|
||||
let Self { write, signal } = myself;
|
||||
let write = GenerationalRefMut::filter_map(write, f);
|
||||
write.map(|write| Write { write, signal })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static, I: 'static> Deref for Write<T, I> {
|
||||
impl<'a, T: 'static, I: 'static> Deref for Write<'a, T, I> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@@ -432,7 +434,7 @@ impl<T: 'static, I: 'static> Deref for Write<T, I> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I> DerefMut for Write<T, I> {
|
||||
impl<'a, T, I> DerefMut for Write<'a, T, I> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.write
|
||||
}
|
||||
@@ -489,7 +491,7 @@ impl<T: 'static> PartialEq for ReadOnlySignal<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Clone> Deref for ReadOnlySignal<T> {
|
||||
impl<T: Copy> Deref for ReadOnlySignal<T> {
|
||||
type Target = dyn Fn() -> T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
||||
Reference in new issue
Block a user