dioxus_signals/
write.rs

1use std::ops::{DerefMut, IndexMut};
2
3use crate::read::Readable;
4
5/// A reference to a value that can be read from.
6#[allow(type_alias_bounds)]
7pub type WritableRef<'a, T: Writable, O = <T as Readable>::Target> = T::Mut<'a, O>;
8
9/// A trait for states that can be written to like [`crate::Signal`]. You may choose to accept this trait as a parameter instead of the concrete type to allow for more flexibility in your API.
10///
11/// # Example
12/// ```rust
13/// # use dioxus::prelude::*;
14/// enum MyEnum {
15///     String(String),
16///     Number(i32),
17/// }
18///
19/// fn MyComponent(mut count: Signal<MyEnum>) -> Element {
20///     rsx! {
21///         button {
22///             onclick: move |_| {
23///                 // You can use any methods from the Writable trait on Signals
24///                 match &mut *count.write() {
25///                     MyEnum::String(s) => s.push('a'),
26///                     MyEnum::Number(n) => *n += 1,
27///                 }
28///             },
29///             "Add value"
30///         }
31///     }
32/// }
33/// ```
34pub trait Writable: Readable {
35    /// The type of the reference.
36    type Mut<'a, R: ?Sized + 'static>: DerefMut<Target = R>;
37
38    /// Map the reference to a new type.
39    fn map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> &mut U>(
40        ref_: Self::Mut<'_, I>,
41        f: F,
42    ) -> Self::Mut<'_, U>;
43
44    /// Try to map the reference to a new type.
45    fn try_map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> Option<&mut U>>(
46        ref_: Self::Mut<'_, I>,
47        f: F,
48    ) -> Option<Self::Mut<'_, U>>;
49
50    /// Downcast a mutable reference in a RefMut to a more specific lifetime
51    ///
52    /// This function enforces the variance of the lifetime parameter `'a` in Ref.
53    fn downcast_lifetime_mut<'a: 'b, 'b, T: ?Sized + 'static>(
54        mut_: Self::Mut<'a, T>,
55    ) -> Self::Mut<'b, T>;
56
57    /// Get a mutable reference to the value. If the value has been dropped, this will panic.
58    #[track_caller]
59    fn write(&mut self) -> WritableRef<'_, Self> {
60        self.try_write().unwrap()
61    }
62
63    /// Try to get a mutable reference to the value.
64    #[track_caller]
65    fn try_write(&mut self) -> Result<WritableRef<'_, Self>, generational_box::BorrowMutError> {
66        self.try_write_unchecked().map(Self::downcast_lifetime_mut)
67    }
68
69    /// Try to get a mutable reference to the value without checking the lifetime. This will update any subscribers.
70    ///
71    /// NOTE: This method is completely safe because borrow checking is done at runtime.
72    fn try_write_unchecked(
73        &self,
74    ) -> Result<WritableRef<'static, Self>, generational_box::BorrowMutError>;
75
76    /// Get a mutable reference to the value without checking the lifetime. This will update any subscribers.
77    ///
78    /// NOTE: This method is completely safe because borrow checking is done at runtime.
79    #[track_caller]
80    fn write_unchecked(&self) -> WritableRef<'static, Self> {
81        self.try_write_unchecked().unwrap()
82    }
83
84    /// Run a function with a mutable reference to the value. If the value has been dropped, this will panic.
85    #[track_caller]
86    fn with_mut<O>(&mut self, f: impl FnOnce(&mut Self::Target) -> O) -> O {
87        f(&mut *self.write())
88    }
89
90    /// Set the value of the signal. This will trigger an update on all subscribers.
91    #[track_caller]
92    fn set(&mut self, value: Self::Target)
93    where
94        Self::Target: Sized,
95    {
96        *self.write() = value;
97    }
98
99    /// Invert the boolean value of the signal. This will trigger an update on all subscribers.
100    #[track_caller]
101    fn toggle(&mut self)
102    where
103        Self::Target: std::ops::Not<Output = Self::Target> + Clone,
104    {
105        self.set(!self.cloned());
106    }
107
108    /// Index into the inner value and return a reference to the result.
109    #[track_caller]
110    fn index_mut<I>(
111        &mut self,
112        index: I,
113    ) -> WritableRef<'_, Self, <Self::Target as std::ops::Index<I>>::Output>
114    where
115        Self::Target: std::ops::IndexMut<I>,
116    {
117        Self::map_mut(self.write(), |v| v.index_mut(index))
118    }
119
120    /// Takes the value out of the Signal, leaving a Default in its place.
121    #[track_caller]
122    fn take(&mut self) -> Self::Target
123    where
124        Self::Target: Default,
125    {
126        self.with_mut(std::mem::take)
127    }
128
129    /// Replace the value in the Signal, returning the old value.
130    #[track_caller]
131    fn replace(&mut self, value: Self::Target) -> Self::Target
132    where
133        Self::Target: Sized,
134    {
135        self.with_mut(|v| std::mem::replace(v, value))
136    }
137}
138
139/// An extension trait for [`Writable<Option<T>>`]` that provides some convenience methods.
140pub trait WritableOptionExt<T: 'static>: Writable<Target = Option<T>> {
141    /// Gets the value out of the Option, or inserts the given value if the Option is empty.
142    #[track_caller]
143    fn get_or_insert(&mut self, default: T) -> WritableRef<'_, Self, T> {
144        self.get_or_insert_with(|| default)
145    }
146
147    /// Gets the value out of the Option, or inserts the value returned by the given function if the Option is empty.
148    #[track_caller]
149    fn get_or_insert_with(&mut self, default: impl FnOnce() -> T) -> WritableRef<'_, Self, T> {
150        let is_none = self.read().is_none();
151        if is_none {
152            self.with_mut(|v| *v = Some(default()));
153            Self::map_mut(self.write(), |v| v.as_mut().unwrap())
154        } else {
155            Self::map_mut(self.write(), |v| v.as_mut().unwrap())
156        }
157    }
158
159    /// Attempts to write the inner value of the Option.
160    #[track_caller]
161    fn as_mut(&mut self) -> Option<WritableRef<'_, Self, T>> {
162        Self::try_map_mut(self.write(), |v: &mut Option<T>| v.as_mut())
163    }
164}
165
166impl<T, W> WritableOptionExt<T> for W
167where
168    T: 'static,
169    W: Writable<Target = Option<T>>,
170{
171}
172
173/// An extension trait for [`Writable<Vec<T>>`] that provides some convenience methods.
174pub trait WritableVecExt<T: 'static>: Writable<Target = Vec<T>> {
175    /// Pushes a new value to the end of the vector.
176    #[track_caller]
177    fn push(&mut self, value: T) {
178        self.with_mut(|v| v.push(value))
179    }
180
181    /// Pops the last value from the vector.
182    #[track_caller]
183    fn pop(&mut self) -> Option<T> {
184        self.with_mut(|v| v.pop())
185    }
186
187    /// Inserts a new value at the given index.
188    #[track_caller]
189    fn insert(&mut self, index: usize, value: T) {
190        self.with_mut(|v| v.insert(index, value))
191    }
192
193    /// Removes the value at the given index.
194    #[track_caller]
195    fn remove(&mut self, index: usize) -> T {
196        self.with_mut(|v| v.remove(index))
197    }
198
199    /// Clears the vector, removing all values.
200    #[track_caller]
201    fn clear(&mut self) {
202        self.with_mut(|v| v.clear())
203    }
204
205    /// Extends the vector with the given iterator.
206    #[track_caller]
207    fn extend(&mut self, iter: impl IntoIterator<Item = T>) {
208        self.with_mut(|v| v.extend(iter))
209    }
210
211    /// Truncates the vector to the given length.
212    #[track_caller]
213    fn truncate(&mut self, len: usize) {
214        self.with_mut(|v| v.truncate(len))
215    }
216
217    /// Swaps two values in the vector.
218    #[track_caller]
219    fn swap_remove(&mut self, index: usize) -> T {
220        self.with_mut(|v| v.swap_remove(index))
221    }
222
223    /// Retains only the values that match the given predicate.
224    #[track_caller]
225    fn retain(&mut self, f: impl FnMut(&T) -> bool) {
226        self.with_mut(|v| v.retain(f))
227    }
228
229    /// Splits the vector into two at the given index.
230    #[track_caller]
231    fn split_off(&mut self, at: usize) -> Vec<T> {
232        self.with_mut(|v| v.split_off(at))
233    }
234
235    /// Try to mutably get an element from the vector.
236    #[track_caller]
237    fn get_mut(&mut self, index: usize) -> Option<WritableRef<'_, Self, T>> {
238        Self::try_map_mut(self.write(), |v: &mut Vec<T>| v.get_mut(index))
239    }
240
241    /// Gets an iterator over the values of the vector.
242    #[track_caller]
243    fn iter_mut(&mut self) -> WritableValueIterator<'_, Self>
244    where
245        Self: Sized + Clone,
246    {
247        WritableValueIterator {
248            index: 0,
249            value: self,
250        }
251    }
252}
253
254/// An iterator over the values of a [`Writable<Vec<T>>`].
255pub struct WritableValueIterator<'a, R> {
256    index: usize,
257    value: &'a mut R,
258}
259
260impl<'a, T: 'static, R: Writable<Target = Vec<T>>> Iterator for WritableValueIterator<'a, R> {
261    type Item = WritableRef<'a, R, T>;
262
263    fn next(&mut self) -> Option<Self::Item> {
264        let index = self.index;
265        self.index += 1;
266        R::try_map_mut(
267            self.value.try_write_unchecked().unwrap(),
268            |v: &mut Vec<T>| v.get_mut(index),
269        )
270        .map(R::downcast_lifetime_mut)
271    }
272}
273
274impl<T, W> WritableVecExt<T> for W
275where
276    T: 'static,
277    W: Writable<Target = Vec<T>>,
278{
279}