document Write, GenerationalRef, and GenerationalRefMut (#3253)
This commit is contained in:
1 parent
9dc567255a
commit
5fc099b30a
2 files changed
+257
-5
No files matched your search
@@ -3,7 +3,82 @@ use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
/// A reference to a value in a generational box.
|
||||
/// A reference to a value in a generational box. This reference acts similarly to [`std::cell::Ref`], but has extra debug information
|
||||
/// to track when all references to the value are created and dropped.
|
||||
///
|
||||
/// [`GenerationalRef`] implements [`Deref`] which means you can call methods on the inner value just like you would on a reference to the
|
||||
/// inner value. If you need to get the inner reference directly, you can call [`GenerationalRef::deref`].
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use generational_box::{Owner, UnsyncStorage, AnyStorage};
|
||||
/// let owner = UnsyncStorage::owner();
|
||||
/// let value = owner.insert(String::from("hello"));
|
||||
/// let reference = value.read();
|
||||
///
|
||||
/// // You call methods like `as_str` on the reference just like you would with the inner String
|
||||
/// assert_eq!(reference.as_str(), "hello");
|
||||
/// ```
|
||||
///
|
||||
/// ## Matching on GenerationalRef
|
||||
///
|
||||
/// You need to get the inner reference with [`GenerationalRef::deref`] before you match the inner value. If you try to match without
|
||||
/// calling [`GenerationalRef::deref`], you will get an error like this:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// # use generational_box::{Owner, UnsyncStorage, AnyStorage};
|
||||
/// enum Colors {
|
||||
/// Red,
|
||||
/// Green
|
||||
/// }
|
||||
/// let owner = UnsyncStorage::owner();
|
||||
/// let value = owner.insert(Colors::Red);
|
||||
/// let reference = value.read();
|
||||
///
|
||||
/// match reference {
|
||||
/// // Since we are matching on the `GenerationalRef` type instead of &Colors, we can't match on the enum directly
|
||||
/// Colors::Red => {}
|
||||
/// Colors::Green => {}
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```text
|
||||
/// error[E0308]: mismatched types
|
||||
/// --> packages/generational-box/tests/basic.rs:25:9
|
||||
/// |
|
||||
/// 2 | Red,
|
||||
/// | --- unit variant defined here
|
||||
/// ...
|
||||
/// 3 | match reference {
|
||||
/// | --------- this expression has type `GenerationalRef<Ref<'_, Colors>>`
|
||||
/// 4 | // Since we are matching on the `GenerationalRef` type instead of &Colors, we can't match on the enum directly
|
||||
/// 5 | Colors::Red => {}
|
||||
/// | ^^^^^^^^^^^ expected `GenerationalRef<Ref<'_, Colors>>`, found `Colors`
|
||||
/// |
|
||||
/// = note: expected struct `GenerationalRef<Ref<'_, Colors>>`
|
||||
/// found enum `Colors`
|
||||
/// ```
|
||||
///
|
||||
/// Instead, you need to deref the reference to get the inner value **before** you match on it:
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::ops::Deref;
|
||||
/// # use generational_box::{AnyStorage, Owner, UnsyncStorage};
|
||||
/// enum Colors {
|
||||
/// Red,
|
||||
/// Green
|
||||
/// }
|
||||
/// let owner = UnsyncStorage::owner();
|
||||
/// let value = owner.insert(Colors::Red);
|
||||
/// let reference = value.read();
|
||||
///
|
||||
/// // Deref converts the `GenerationalRef` into a `&Colors`
|
||||
/// match reference.deref() {
|
||||
/// // Now we can match on the inner value
|
||||
/// Colors::Red => {}
|
||||
/// Colors::Green => {}
|
||||
/// }
|
||||
/// ```
|
||||
pub struct GenerationalRef<R> {
|
||||
pub(crate) inner: R,
|
||||
guard: GenerationalRefBorrowGuard,
|
||||
@@ -65,7 +140,79 @@ impl Drop for GenerationalRefBorrowGuard {
|
||||
}
|
||||
}
|
||||
|
||||
/// A mutable reference to a value in a generational box.
|
||||
/// A mutable reference to a value in a generational box. This reference acts similarly to [`std::cell::RefMut`], but has extra debug information
|
||||
/// to track when all references to the value are created and dropped.
|
||||
///
|
||||
/// [`GenerationalRefMut`] implements [`DerefMut`] which means you can call methods on the inner value just like you would on a mutable reference
|
||||
/// to the inner value. If you need to get the inner reference directly, you can call [`GenerationalRefMut::deref_mut`].
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use generational_box::{Owner, UnsyncStorage, AnyStorage};
|
||||
/// let owner = UnsyncStorage::owner();
|
||||
/// let mut value = owner.insert(String::from("hello"));
|
||||
/// let mut mutable_reference = value.write();
|
||||
///
|
||||
/// // You call methods like `push_str` on the reference just like you would with the inner String
|
||||
/// mutable_reference.push_str("world");
|
||||
/// ```
|
||||
///
|
||||
/// ## Matching on GenerationalMut
|
||||
///
|
||||
/// You need to get the inner mutable reference with [`GenerationalRefMut::deref_mut`] before you match the inner value. If you try to match
|
||||
/// without calling [`GenerationalRefMut::deref_mut`], you will get an error like this:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// # use generational_box::{Owner, UnsyncStorage, AnyStorage};
|
||||
/// enum Colors {
|
||||
/// Red(u32),
|
||||
/// Green
|
||||
/// }
|
||||
/// let owner = UnsyncStorage::owner();
|
||||
/// let mut value = owner.insert(Colors::Red(0));
|
||||
/// let mut mutable_reference = value.write();
|
||||
///
|
||||
/// match mutable_reference {
|
||||
/// // Since we are matching on the `GenerationalRefMut` type instead of &mut Colors, we can't match on the enum directly
|
||||
/// Colors::Red(brightness) => *brightness += 1,
|
||||
/// Colors::Green => {}
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```text
|
||||
/// error[E0308]: mismatched types
|
||||
/// --> packages/generational-box/tests/basic.rs:25:9
|
||||
/// |
|
||||
/// 9 | match mutable_reference {
|
||||
/// | ----------------- this expression has type `GenerationalRefMut<RefMut<'_, fn(u32) -> Colors {Colors::Red}>>`
|
||||
/// 10 | // Since we are matching on the `GenerationalRefMut` type instead of &mut Colors, we can't match on the enum directly
|
||||
/// 11 | Colors::Red(brightness) => *brightness += 1,
|
||||
/// | ^^^^^^^^^^^^^^^^^^^^^^^ expected `GenerationalRefMut<RefMut<'_, ...>>`, found `Colors`
|
||||
/// |
|
||||
/// = note: expected struct `GenerationalRefMut<RefMut<'_, fn(u32) -> Colors {Colors::Red}>>`
|
||||
/// found enum `Colors`
|
||||
/// ```
|
||||
///
|
||||
/// Instead, you need to call deref mut on the reference to get the inner value **before** you match on it:
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::ops::DerefMut;
|
||||
/// # use generational_box::{AnyStorage, Owner, UnsyncStorage};
|
||||
/// enum Colors {
|
||||
/// Red(u32),
|
||||
/// Green
|
||||
/// }
|
||||
/// let owner = UnsyncStorage::owner();
|
||||
/// let mut value = owner.insert(Colors::Red(0));
|
||||
/// let mut mutable_reference = value.write();
|
||||
///
|
||||
/// // DerefMut converts the `GenerationalRefMut` into a `&mut Colors`
|
||||
/// match mutable_reference.deref_mut() {
|
||||
/// // Now we can match on the inner value
|
||||
/// Colors::Red(brightness) => *brightness += 1,
|
||||
/// Colors::Green => {}
|
||||
/// }
|
||||
/// ```
|
||||
pub struct GenerationalRefMut<W> {
|
||||
pub(crate) inner: W,
|
||||
pub(crate) borrow: GenerationalRefBorrowMutGuard,
|
||||
|
||||
@@ -511,10 +511,115 @@ impl<'de, T: serde::Deserialize<'de> + 'static, Store: Storage<SignalData<T>>>
|
||||
}
|
||||
}
|
||||
|
||||
/// A mutable reference to a signal's value.
|
||||
/// A mutable reference to a signal's value. This reference acts similarly to [`std::cell::RefMut`], but it has extra debug information
|
||||
/// and integrates with the reactive system to automatically update dependents.
|
||||
///
|
||||
/// T is the current type of the write
|
||||
/// S is the storage type of the signal
|
||||
/// [`Write`] implements [`DerefMut`] which means you can call methods on the inner value just like you would on a mutable reference
|
||||
/// to the inner value. If you need to get the inner reference directly, you can call [`Write::deref_mut`].
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use dioxus::prelude::*;
|
||||
/// fn app() -> Element {
|
||||
/// let mut value = use_signal(|| String::from("hello"));
|
||||
///
|
||||
/// rsx! {
|
||||
/// button {
|
||||
/// onclick: move |_| {
|
||||
/// let mut mutable_reference = value.write();
|
||||
///
|
||||
/// // You call methods like `push_str` on the reference just like you would with the inner String
|
||||
/// mutable_reference.push_str("world");
|
||||
/// },
|
||||
/// "Click to add world to the string"
|
||||
/// }
|
||||
/// div { "{value}" }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Matching on Write
|
||||
///
|
||||
/// You need to get the inner mutable reference with [`Write::deref_mut`] before you match the inner value. If you try to match
|
||||
/// without calling [`Write::deref_mut`], you will get an error like this:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// # use dioxus::prelude::*;
|
||||
/// #[derive(Debug)]
|
||||
/// enum Colors {
|
||||
/// Red(u32),
|
||||
/// Green
|
||||
/// }
|
||||
/// fn app() -> Element {
|
||||
/// let mut value = use_signal(|| Colors::Red(0));
|
||||
///
|
||||
/// rsx! {
|
||||
/// button {
|
||||
/// onclick: move |_| {
|
||||
/// let mut mutable_reference = value.write();
|
||||
///
|
||||
/// match mutable_reference {
|
||||
/// // Since we are matching on the `Write` type instead of &mut Colors, we can't match on the enum directly
|
||||
/// Colors::Red(brightness) => *brightness += 1,
|
||||
/// Colors::Green => {}
|
||||
/// }
|
||||
/// },
|
||||
/// "Click to add brightness to the red color"
|
||||
/// }
|
||||
/// div { "{value:?}" }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```text
|
||||
/// error[E0308]: mismatched types
|
||||
/// --> src/main.rs:18:21
|
||||
/// |
|
||||
/// 16 | match mutable_reference {
|
||||
/// | ----------------- this expression has type `dioxus::prelude::Write<'_, Colors>`
|
||||
/// 17 | // Since we are matching on the `Write` t...
|
||||
/// 18 | Colors::Red(brightness) => *brightness += 1,
|
||||
/// | ^^^^^^^^^^^^^^^^^^^^^^^ expected `Write<'_, Colors>`, found `Colors`
|
||||
/// |
|
||||
/// = note: expected struct `dioxus::prelude::Write<'_, Colors, >`
|
||||
/// found enum `Colors`
|
||||
/// ```
|
||||
///
|
||||
/// Instead, you need to call deref mut on the reference to get the inner value **before** you match on it:
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::ops::DerefMut;
|
||||
/// # use dioxus::prelude::*;
|
||||
/// #[derive(Debug)]
|
||||
/// enum Colors {
|
||||
/// Red(u32),
|
||||
/// Green
|
||||
/// }
|
||||
/// fn app() -> Element {
|
||||
/// let mut value = use_signal(|| Colors::Red(0));
|
||||
///
|
||||
/// rsx! {
|
||||
/// button {
|
||||
/// onclick: move |_| {
|
||||
/// let mut mutable_reference = value.write();
|
||||
///
|
||||
/// // DerefMut converts the `Write` into a `&mut Colors`
|
||||
/// match mutable_reference.deref_mut() {
|
||||
/// // Now we can match on the inner value
|
||||
/// Colors::Red(brightness) => *brightness += 1,
|
||||
/// Colors::Green => {}
|
||||
/// }
|
||||
/// },
|
||||
/// "Click to add brightness to the red color"
|
||||
/// }
|
||||
/// div { "{value:?}" }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Generics
|
||||
/// - T is the current type of the write
|
||||
/// - S is the storage type of the signal. This type determines if the signal is local to the current thread, or it can be shared across threads.
|
||||
pub struct Write<'a, T: ?Sized + 'static, S: AnyStorage = UnsyncStorage> {
|
||||
write: S::Mut<'a, T>,
|
||||
drop_signal: Box<dyn Any>,
|
||||
|
||||
Reference in new issue
Block a user