restore lifetime checking for signals
This commit is contained in:
1 parent
295c29db5d
commit
60a84956d1
16 files changed
+275
-148
No files matched your search
+1
-1
@@ -80,7 +80,7 @@ fn BreedPic(breed: Signal<String>) -> Element {
|
||||
.await
|
||||
});
|
||||
|
||||
match fut.read().as_ref() {
|
||||
match fut.read_unchecked().as_ref() {
|
||||
Some(Ok(resp)) => rsx! {
|
||||
button { onclick: move |_| fut.restart(), "Click to fetch another doggo" }
|
||||
img { max_width: "500px", max_height: "500px", src: "{resp.message}" }
|
||||
|
||||
@@ -62,7 +62,7 @@ fn Doggo() -> Element {
|
||||
.await
|
||||
});
|
||||
|
||||
match fut.read().as_ref() {
|
||||
match fut.read_unchecked().as_ref() {
|
||||
Some(Ok(resp)) => rsx! {
|
||||
button { onclick: move |_| fut.restart(), "Click to fetch another doggo" }
|
||||
div { img { max_width: "500px", max_height: "500px", src: "{resp.message}" } }
|
||||
|
||||
@@ -98,7 +98,7 @@ impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {
|
||||
|
||||
/// Try to read the value. Returns None if the value is no longer valid.
|
||||
#[track_caller]
|
||||
pub fn try_read(&self) -> Result<S::Ref<T>, BorrowError> {
|
||||
pub fn try_read(&self) -> Result<S::Ref<'static, T>, BorrowError> {
|
||||
if !self.validate() {
|
||||
return Err(BorrowError::Dropped(ValueDroppedError {
|
||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||
@@ -129,13 +129,13 @@ impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {
|
||||
|
||||
/// Read the value. Panics if the value is no longer valid.
|
||||
#[track_caller]
|
||||
pub fn read(&self) -> S::Ref<T> {
|
||||
pub fn read(&self) -> S::Ref<'static, T> {
|
||||
self.try_read().unwrap()
|
||||
}
|
||||
|
||||
/// Try to write the value. Returns None if the value is no longer valid.
|
||||
#[track_caller]
|
||||
pub fn try_write(&self) -> Result<S::Mut<T>, BorrowMutError> {
|
||||
pub fn try_write(&self) -> Result<S::Mut<'static, T>, BorrowMutError> {
|
||||
if !self.validate() {
|
||||
return Err(BorrowMutError::Dropped(ValueDroppedError {
|
||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||
@@ -162,7 +162,7 @@ impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {
|
||||
|
||||
/// Write the value. Panics if the value is no longer valid.
|
||||
#[track_caller]
|
||||
pub fn write(&self) -> S::Mut<T> {
|
||||
pub fn write(&self) -> S::Mut<'static, T> {
|
||||
self.try_write().unwrap()
|
||||
}
|
||||
|
||||
@@ -210,13 +210,13 @@ pub trait Storage<Data = ()>: AnyStorage + 'static {
|
||||
fn try_read(
|
||||
&'static self,
|
||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefBorrowInfo,
|
||||
) -> Result<Self::Ref<Data>, BorrowError>;
|
||||
) -> Result<Self::Ref<'static, Data>, BorrowError>;
|
||||
|
||||
/// Try to write the value. Returns None if the value is no longer valid.
|
||||
fn try_write(
|
||||
&'static self,
|
||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefMutBorrowInfo,
|
||||
) -> Result<Self::Mut<Data>, BorrowMutError>;
|
||||
) -> Result<Self::Mut<'static, Data>, BorrowMutError>;
|
||||
|
||||
/// Set the value
|
||||
fn set(&'static self, value: Data);
|
||||
@@ -228,35 +228,45 @@ pub trait Storage<Data = ()>: AnyStorage + 'static {
|
||||
/// A trait for any storage backing type.
|
||||
pub trait AnyStorage: Default {
|
||||
/// The reference this storage type returns.
|
||||
type Ref<T: ?Sized + 'static>: Deref<Target = T> + 'static;
|
||||
type Ref<'a, T: ?Sized + 'static>: Deref<Target = T>;
|
||||
/// The mutable reference this storage type returns.
|
||||
type Mut<T: ?Sized + 'static>: DerefMut<Target = T> + 'static;
|
||||
type Mut<'a, T: ?Sized + 'static>: DerefMut<Target = T>;
|
||||
|
||||
/// Downcast a reference in a Ref to a more specific lifetime
|
||||
///
|
||||
/// This function enforces the variance of the lifetime parameter `'a` in Ref.
|
||||
fn downcast_ref<'a: 'b, 'b, T: ?Sized + 'static>(ref_: Self::Ref<'a, T>) -> Self::Ref<'b, T>;
|
||||
|
||||
/// Downcast a mutable reference in a RefMut to a more specific lifetime
|
||||
///
|
||||
/// This function enforces the variance of the lifetime parameter `'a` in Ref.
|
||||
fn downcast_mut<'a: 'b, 'b, T: ?Sized + 'static>(mut_: Self::Mut<'a, T>) -> Self::Mut<'b, T>;
|
||||
|
||||
/// Try to map the mutable ref.
|
||||
fn try_map_mut<T: ?Sized, U: ?Sized + 'static>(
|
||||
mut_ref: Self::Mut<T>,
|
||||
fn try_map_mut<T: ?Sized + 'static, U: ?Sized + 'static>(
|
||||
mut_ref: Self::Mut<'_, T>,
|
||||
f: impl FnOnce(&mut T) -> Option<&mut U>,
|
||||
) -> Option<Self::Mut<U>>;
|
||||
) -> Option<Self::Mut<'_, U>>;
|
||||
|
||||
/// Map the mutable ref.
|
||||
fn map_mut<T: ?Sized, U: ?Sized + 'static>(
|
||||
mut_ref: Self::Mut<T>,
|
||||
fn map_mut<T: ?Sized + 'static, U: ?Sized + 'static>(
|
||||
mut_ref: Self::Mut<'_, T>,
|
||||
f: impl FnOnce(&mut T) -> &mut U,
|
||||
) -> Self::Mut<U> {
|
||||
) -> Self::Mut<'_, U> {
|
||||
Self::try_map_mut(mut_ref, |v| Some(f(v))).unwrap()
|
||||
}
|
||||
|
||||
/// Try to map the ref.
|
||||
fn try_map<T: ?Sized, U: ?Sized + 'static>(
|
||||
ref_: Self::Ref<T>,
|
||||
ref_: Self::Ref<'_, T>,
|
||||
f: impl FnOnce(&T) -> Option<&U>,
|
||||
) -> Option<Self::Ref<U>>;
|
||||
) -> Option<Self::Ref<'_, U>>;
|
||||
|
||||
/// Map the ref.
|
||||
fn map<T: ?Sized, U: ?Sized + 'static>(
|
||||
ref_: Self::Ref<T>,
|
||||
ref_: Self::Ref<'_, T>,
|
||||
f: impl FnOnce(&T) -> &U,
|
||||
) -> Self::Ref<U> {
|
||||
) -> Self::Ref<'_, U> {
|
||||
Self::try_map(ref_, |v| Some(f(v))).unwrap()
|
||||
}
|
||||
|
||||
|
||||
@@ -20,13 +20,21 @@ fn sync_runtime() -> &'static Arc<Mutex<Vec<MemoryLocation<SyncStorage>>>> {
|
||||
}
|
||||
|
||||
impl AnyStorage for SyncStorage {
|
||||
type Ref<R: ?Sized + 'static> = GenerationalRef<MappedRwLockReadGuard<'static, R>>;
|
||||
type Mut<W: ?Sized + 'static> = GenerationalRefMut<MappedRwLockWriteGuard<'static, W>>;
|
||||
type Ref<'a, R: ?Sized + 'static> = GenerationalRef<MappedRwLockReadGuard<'a, R>>;
|
||||
type Mut<'a, W: ?Sized + 'static> = GenerationalRefMut<MappedRwLockWriteGuard<'a, W>>;
|
||||
|
||||
fn try_map<I: ?Sized, U: ?Sized + 'static>(
|
||||
ref_: Self::Ref<I>,
|
||||
fn downcast_ref<'a: 'b, 'b, T: ?Sized + 'static>(ref_: Self::Ref<'a, T>) -> Self::Ref<'b, T> {
|
||||
ref_
|
||||
}
|
||||
|
||||
fn downcast_mut<'a: 'b, 'b, T: ?Sized + 'static>(mut_: Self::Mut<'a, T>) -> Self::Mut<'b, T> {
|
||||
mut_
|
||||
}
|
||||
|
||||
fn try_map<I: ?Sized + 'static, U: ?Sized + 'static>(
|
||||
ref_: Self::Ref<'_, I>,
|
||||
f: impl FnOnce(&I) -> Option<&U>,
|
||||
) -> Option<Self::Ref<U>> {
|
||||
) -> Option<Self::Ref<'_, U>> {
|
||||
let GenerationalRef {
|
||||
inner,
|
||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||
@@ -46,10 +54,10 @@ impl AnyStorage for SyncStorage {
|
||||
})
|
||||
}
|
||||
|
||||
fn try_map_mut<I: ?Sized, U: ?Sized + 'static>(
|
||||
mut_ref: Self::Mut<I>,
|
||||
fn try_map_mut<I: ?Sized + 'static, U: ?Sized + 'static>(
|
||||
mut_ref: Self::Mut<'_, I>,
|
||||
f: impl FnOnce(&mut I) -> Option<&mut U>,
|
||||
) -> Option<Self::Mut<U>> {
|
||||
) -> Option<Self::Mut<'_, U>> {
|
||||
let GenerationalRefMut {
|
||||
inner,
|
||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||
@@ -101,7 +109,7 @@ impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
|
||||
&'static self,
|
||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||
at: crate::GenerationalRefBorrowInfo,
|
||||
) -> Result<Self::Ref<T>, error::BorrowError> {
|
||||
) -> Result<Self::Ref<'static, T>, error::BorrowError> {
|
||||
let read = self.0.try_read();
|
||||
|
||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||
@@ -132,7 +140,7 @@ impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
|
||||
&'static self,
|
||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||
at: crate::GenerationalRefMutBorrowInfo,
|
||||
) -> Result<Self::Mut<T>, error::BorrowMutError> {
|
||||
) -> Result<Self::Mut<'static, T>, error::BorrowMutError> {
|
||||
let write = self.0.try_write();
|
||||
|
||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||
|
||||
@@ -15,7 +15,7 @@ impl<T: 'static> Storage<T> for UnsyncStorage {
|
||||
|
||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||
at: crate::GenerationalRefBorrowInfo,
|
||||
) -> Result<Self::Ref<T>, error::BorrowError> {
|
||||
) -> Result<Self::Ref<'static, T>, error::BorrowError> {
|
||||
let borrow = self.0.try_borrow();
|
||||
|
||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||
@@ -46,7 +46,7 @@ impl<T: 'static> Storage<T> for UnsyncStorage {
|
||||
&'static self,
|
||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||
at: crate::GenerationalRefMutBorrowInfo,
|
||||
) -> Result<Self::Mut<T>, error::BorrowMutError> {
|
||||
) -> Result<Self::Mut<'static, T>, error::BorrowMutError> {
|
||||
let borrow = self.0.try_borrow_mut();
|
||||
|
||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||
@@ -89,13 +89,21 @@ thread_local! {
|
||||
}
|
||||
|
||||
impl AnyStorage for UnsyncStorage {
|
||||
type Ref<R: ?Sized + 'static> = GenerationalRef<Ref<'static, R>>;
|
||||
type Mut<W: ?Sized + 'static> = GenerationalRefMut<RefMut<'static, W>>;
|
||||
type Ref<'a, R: ?Sized + 'static> = GenerationalRef<Ref<'a, R>>;
|
||||
type Mut<'a, W: ?Sized + 'static> = GenerationalRefMut<RefMut<'a, W>>;
|
||||
|
||||
fn try_map<I: ?Sized, U: ?Sized + 'static>(
|
||||
_self: Self::Ref<I>,
|
||||
fn downcast_ref<'a: 'b, 'b, T: ?Sized + 'static>(ref_: Self::Ref<'a, T>) -> Self::Ref<'b, T> {
|
||||
ref_
|
||||
}
|
||||
|
||||
fn downcast_mut<'a: 'b, 'b, T: ?Sized + 'static>(mut_: Self::Mut<'a, T>) -> Self::Mut<'b, T> {
|
||||
mut_
|
||||
}
|
||||
|
||||
fn try_map<I: ?Sized + 'static, U: ?Sized + 'static>(
|
||||
_self: Self::Ref<'_, I>,
|
||||
f: impl FnOnce(&I) -> Option<&U>,
|
||||
) -> Option<Self::Ref<U>> {
|
||||
) -> Option<Self::Ref<'_, U>> {
|
||||
let GenerationalRef {
|
||||
inner,
|
||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||
@@ -109,10 +117,10 @@ impl AnyStorage for UnsyncStorage {
|
||||
})
|
||||
}
|
||||
|
||||
fn try_map_mut<I: ?Sized, U: ?Sized + 'static>(
|
||||
mut_ref: Self::Mut<I>,
|
||||
fn try_map_mut<I: ?Sized + 'static, U: ?Sized + 'static>(
|
||||
mut_ref: Self::Mut<'_, I>,
|
||||
f: impl FnOnce(&mut I) -> Option<&mut U>,
|
||||
) -> Option<Self::Mut<U>> {
|
||||
) -> Option<Self::Mut<'_, U>> {
|
||||
let GenerationalRefMut {
|
||||
inner,
|
||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||
|
||||
@@ -157,7 +157,7 @@ impl RouterContext {
|
||||
/// Will fail silently if there is no previous location to go to.
|
||||
pub fn go_back(&self) {
|
||||
{
|
||||
self.inner.clone().write().history.go_back();
|
||||
self.inner.write_unchecked().history.go_back();
|
||||
}
|
||||
|
||||
self.change_route();
|
||||
@@ -168,7 +168,7 @@ impl RouterContext {
|
||||
/// Will fail silently if there is no next location to go to.
|
||||
pub fn go_forward(&self) {
|
||||
{
|
||||
self.inner.clone().write().history.go_forward();
|
||||
self.inner.write_unchecked().history.go_forward();
|
||||
}
|
||||
|
||||
self.change_route();
|
||||
@@ -179,7 +179,7 @@ impl RouterContext {
|
||||
target: NavigationTarget<Rc<dyn Any>>,
|
||||
) -> Option<ExternalNavigationFailure> {
|
||||
{
|
||||
let mut write = self.inner.clone().write();
|
||||
let mut write = self.inner.write_unchecked();
|
||||
match target {
|
||||
NavigationTarget::Internal(p) => write.history.push(p),
|
||||
NavigationTarget::External(e) => return write.external(e),
|
||||
@@ -195,7 +195,7 @@ impl RouterContext {
|
||||
pub fn push(&self, target: impl Into<IntoRoutable>) -> Option<ExternalNavigationFailure> {
|
||||
let target = self.resolve_into_routable(target.into());
|
||||
{
|
||||
let mut write = self.inner.clone().write();
|
||||
let mut write = self.inner.write_unchecked();
|
||||
match target {
|
||||
NavigationTarget::Internal(p) => write.history.push(p),
|
||||
NavigationTarget::External(e) => return write.external(e),
|
||||
@@ -212,7 +212,7 @@ impl RouterContext {
|
||||
let target = self.resolve_into_routable(target.into());
|
||||
|
||||
{
|
||||
let mut state = self.inner.clone().write();
|
||||
let mut state = self.inner.write_unchecked();
|
||||
match target {
|
||||
NavigationTarget::Internal(p) => state.history.replace(p),
|
||||
NavigationTarget::External(e) => return state.external(e),
|
||||
@@ -276,14 +276,14 @@ impl RouterContext {
|
||||
|
||||
/// Clear any unresolved errors
|
||||
pub fn clear_error(&self) {
|
||||
let mut write_inner = self.inner.clone().write();
|
||||
let mut write_inner = self.inner.write_unchecked();
|
||||
write_inner.unresolved_error = None;
|
||||
|
||||
write_inner.update_subscribers();
|
||||
}
|
||||
|
||||
pub(crate) fn render_error(&self) -> Element {
|
||||
let inner_read = self.inner.clone().write();
|
||||
let inner_read = self.inner.write_unchecked();
|
||||
inner_read
|
||||
.unresolved_error
|
||||
.as_ref()
|
||||
@@ -297,7 +297,7 @@ impl RouterContext {
|
||||
let callback = callback.clone();
|
||||
drop(self_read);
|
||||
if let Some(new) = callback(myself) {
|
||||
let mut self_write = self.inner.clone().write();
|
||||
let mut self_write = self.inner.write_unchecked();
|
||||
match new {
|
||||
NavigationTarget::Internal(p) => self_write.history.replace(p),
|
||||
NavigationTarget::External(e) => return self_write.external(e),
|
||||
|
||||
@@ -15,6 +15,7 @@ use generational_box::{GenerationalBox, Owner, Storage};
|
||||
|
||||
use crate::ReadableRef;
|
||||
use crate::Writable;
|
||||
use crate::WritableRef;
|
||||
use crate::{ReactiveContext, Readable};
|
||||
|
||||
/// Run a closure with the given owner.
|
||||
@@ -211,40 +212,43 @@ impl<T: 'static, S: Storage<T>> Readable for CopyValue<T, S> {
|
||||
type Target = T;
|
||||
type Storage = S;
|
||||
|
||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
||||
fn try_read_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
self.value.try_read()
|
||||
}
|
||||
|
||||
fn peek(&self) -> ReadableRef<Self> {
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
self.value.read()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static, S: Storage<T>> Writable for CopyValue<T, S> {
|
||||
type Mut<R: ?Sized + 'static> = S::Mut<R>;
|
||||
type Mut<'a, R: ?Sized + 'static> = S::Mut<'a, R>;
|
||||
|
||||
fn map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> &mut U>(
|
||||
mut_: Self::Mut<I>,
|
||||
mut_: Self::Mut<'_, I>,
|
||||
f: F,
|
||||
) -> Self::Mut<U> {
|
||||
) -> Self::Mut<'_, U> {
|
||||
S::map_mut(mut_, f)
|
||||
}
|
||||
|
||||
fn try_map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> Option<&mut U>>(
|
||||
mut_: Self::Mut<I>,
|
||||
mut_: Self::Mut<'_, I>,
|
||||
f: F,
|
||||
) -> Option<Self::Mut<U>> {
|
||||
) -> Option<Self::Mut<'_, U>> {
|
||||
S::try_map_mut(mut_, f)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn try_write(&mut self) -> Result<Self::Mut<T>, generational_box::BorrowMutError> {
|
||||
self.value.try_write()
|
||||
fn downcast_mut<'a: 'b, 'b, R: ?Sized + 'static>(mut_: Self::Mut<'a, R>) -> Self::Mut<'b, R> {
|
||||
S::downcast_mut(mut_)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn write(&mut self) -> Self::Mut<T> {
|
||||
self.value.write()
|
||||
fn try_write_unchecked(
|
||||
&self,
|
||||
) -> Result<WritableRef<'static, Self>, generational_box::BorrowMutError> {
|
||||
self.value.try_write()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
||||
@@ -56,13 +56,15 @@ impl<T: PartialEq + 'static> Readable for GlobalMemo<T> {
|
||||
type Storage = UnsyncStorage;
|
||||
|
||||
#[track_caller]
|
||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
||||
self.memo().try_read()
|
||||
fn try_read_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
self.memo().try_read_unchecked()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn peek(&self) -> ReadableRef<Self> {
|
||||
self.memo().peek()
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
self.memo().peek_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::write::Writable;
|
||||
use crate::Write;
|
||||
use crate::{read::Readable, ReadableRef};
|
||||
use crate::{WritableRef, Write};
|
||||
use dioxus_core::prelude::{IntoAttributeValue, ScopeId};
|
||||
use generational_box::UnsyncStorage;
|
||||
use std::{mem::MaybeUninit, ops::Deref};
|
||||
@@ -44,8 +44,8 @@ impl<T: 'static> GlobalSignal<T> {
|
||||
}
|
||||
|
||||
/// Write this value
|
||||
pub fn write(&self) -> Write<T, UnsyncStorage> {
|
||||
self.signal().write()
|
||||
pub fn write(&self) -> Write<'static, T, UnsyncStorage> {
|
||||
self.signal().try_write_unchecked().unwrap()
|
||||
}
|
||||
|
||||
/// Get the scope the signal was created in.
|
||||
@@ -71,23 +71,25 @@ impl<T: 'static> Readable for GlobalSignal<T> {
|
||||
type Storage = UnsyncStorage;
|
||||
|
||||
#[track_caller]
|
||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
||||
self.signal().try_read()
|
||||
fn try_read_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
self.signal().try_read_unchecked()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn peek(&self) -> ReadableRef<Self> {
|
||||
self.signal().peek()
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
self.signal().peek_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Writable for GlobalSignal<T> {
|
||||
type Mut<R: ?Sized + 'static> = Write<R, UnsyncStorage>;
|
||||
type Mut<'a, R: ?Sized + 'static> = Write<'a, R, UnsyncStorage>;
|
||||
|
||||
fn map_mut<I: ?Sized, U: ?Sized + 'static, F: FnOnce(&mut I) -> &mut U>(
|
||||
ref_: Self::Mut<I>,
|
||||
ref_: Self::Mut<'_, I>,
|
||||
f: F,
|
||||
) -> Self::Mut<U> {
|
||||
) -> Self::Mut<'_, U> {
|
||||
Write::map(ref_, f)
|
||||
}
|
||||
|
||||
@@ -96,15 +98,21 @@ impl<T: 'static> Writable for GlobalSignal<T> {
|
||||
U: ?Sized + 'static,
|
||||
F: FnOnce(&mut I) -> Option<&mut U>,
|
||||
>(
|
||||
ref_: Self::Mut<I>,
|
||||
ref_: Self::Mut<'_, I>,
|
||||
f: F,
|
||||
) -> Option<Self::Mut<U>> {
|
||||
) -> Option<Self::Mut<'_, U>> {
|
||||
Write::filter_map(ref_, f)
|
||||
}
|
||||
|
||||
fn downcast_mut<'a: 'b, 'b, R: ?Sized + 'static>(mut_: Self::Mut<'a, R>) -> Self::Mut<'b, R> {
|
||||
Write::downcast_lifetime(mut_)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn try_write(&mut self) -> Result<Self::Mut<T>, generational_box::BorrowMutError> {
|
||||
self.signal().try_write()
|
||||
fn try_write_unchecked(
|
||||
&self,
|
||||
) -> Result<WritableRef<'static, Self>, generational_box::BorrowMutError> {
|
||||
self.signal().try_write_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ use generational_box::{AnyStorage, UnsyncStorage};
|
||||
|
||||
/// A read only signal that has been mapped to a new type.
|
||||
pub struct MappedSignal<O: ?Sized + 'static, S: AnyStorage = UnsyncStorage> {
|
||||
try_read: Rc<dyn Fn() -> Result<S::Ref<O>, generational_box::BorrowError> + 'static>,
|
||||
peek: Rc<dyn Fn() -> S::Ref<O> + 'static>,
|
||||
try_read: Rc<dyn Fn() -> Result<S::Ref<'static, O>, generational_box::BorrowError> + 'static>,
|
||||
peek: Rc<dyn Fn() -> S::Ref<'static, O> + 'static>,
|
||||
}
|
||||
|
||||
impl<O: ?Sized, S: AnyStorage> Clone for MappedSignal<O, S> {
|
||||
@@ -26,8 +26,10 @@ where
|
||||
{
|
||||
/// Create a new mapped signal.
|
||||
pub(crate) fn new(
|
||||
try_read: Rc<dyn Fn() -> Result<S::Ref<O>, generational_box::BorrowError> + 'static>,
|
||||
peek: Rc<dyn Fn() -> S::Ref<O> + 'static>,
|
||||
try_read: Rc<
|
||||
dyn Fn() -> Result<S::Ref<'static, O>, generational_box::BorrowError> + 'static,
|
||||
>,
|
||||
peek: Rc<dyn Fn() -> S::Ref<'static, O> + 'static>,
|
||||
) -> Self {
|
||||
MappedSignal { try_read, peek }
|
||||
}
|
||||
@@ -41,11 +43,13 @@ where
|
||||
type Target = O;
|
||||
type Storage = S;
|
||||
|
||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
||||
fn try_read_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
(self.try_read)()
|
||||
}
|
||||
|
||||
fn peek(&self) -> ReadableRef<Self> {
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
(self.peek)()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,8 +163,10 @@ where
|
||||
type Storage = UnsyncStorage;
|
||||
|
||||
#[track_caller]
|
||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
||||
let read = self.inner.try_read();
|
||||
fn try_read_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
let read = self.inner.try_read_unchecked();
|
||||
match read {
|
||||
Ok(r) => {
|
||||
let needs_update = self
|
||||
@@ -175,7 +177,7 @@ where
|
||||
if needs_update {
|
||||
drop(r);
|
||||
self.recompute();
|
||||
self.inner.try_read()
|
||||
self.inner.try_read_unchecked()
|
||||
} else {
|
||||
Ok(r)
|
||||
}
|
||||
@@ -188,8 +190,8 @@ where
|
||||
///
|
||||
/// If the signal has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
fn peek(&self) -> ReadableRef<Self> {
|
||||
self.inner.peek()
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
self.inner.peek_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -128,8 +128,7 @@ impl ReactiveContext {
|
||||
///
|
||||
/// Returns true if the context was marked as dirty, or false if the context has been dropped
|
||||
pub fn mark_dirty(&self) -> bool {
|
||||
let mut copy = self.inner;
|
||||
if let Ok(mut self_write) = copy.try_write() {
|
||||
if let Ok(mut self_write) = self.inner.try_write_unchecked() {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
tracing::trace!(
|
||||
|
||||
@@ -6,7 +6,8 @@ use crate::MappedSignal;
|
||||
|
||||
/// A reference to a value that can be read from.
|
||||
#[allow(type_alias_bounds)]
|
||||
pub type ReadableRef<T: Readable, O = <T as Readable>::Target> = <T::Storage as AnyStorage>::Ref<O>;
|
||||
pub type ReadableRef<'a, T: Readable, O = <T as Readable>::Target> =
|
||||
<T::Storage as AnyStorage>::Ref<'a, O>;
|
||||
|
||||
/// A trait for states that can be read from like [`crate::Signal`], [`crate::GlobalSignal`], or [`crate::ReadOnlySignal`]. You may choose to accept this trait as a parameter instead of the concrete type to allow for more flexibility in your API. For example, instead of creating two functions, one that accepts a [`crate::Signal`] and one that accepts a [`crate::GlobalSignal`], you can create one function that accepts a [`Readable`] type.
|
||||
pub trait Readable {
|
||||
@@ -27,15 +28,17 @@ pub trait Readable {
|
||||
let mapping = mapping.clone();
|
||||
move || {
|
||||
self_
|
||||
.try_read()
|
||||
.try_read_unchecked()
|
||||
.map(|ref_| <Self::Storage as AnyStorage>::map(ref_, |r| mapping(r)))
|
||||
}
|
||||
})
|
||||
as Rc<
|
||||
dyn Fn() -> Result<ReadableRef<Self, O>, generational_box::BorrowError> + 'static,
|
||||
dyn Fn() -> Result<ReadableRef<'static, Self, O>, generational_box::BorrowError>
|
||||
+ 'static,
|
||||
>;
|
||||
let peek = Rc::new(move || <Self::Storage as AnyStorage>::map(self.peek(), |r| mapping(r)))
|
||||
as Rc<dyn Fn() -> ReadableRef<Self, O> + 'static>;
|
||||
let peek = Rc::new(move || {
|
||||
<Self::Storage as AnyStorage>::map(self.peek_unchecked(), |r| mapping(r))
|
||||
}) as Rc<dyn Fn() -> ReadableRef<'static, Self, O> + 'static>;
|
||||
MappedSignal::new(try_read, peek)
|
||||
}
|
||||
|
||||
@@ -47,12 +50,38 @@ pub trait Readable {
|
||||
self.try_read().unwrap()
|
||||
}
|
||||
|
||||
/// Try to get the current value of the state. If this is a signal, this will subscribe the current scope to the signal. If the value has been dropped, this will panic.
|
||||
/// Try to get the current value of the state. If this is a signal, this will subscribe the current scope to the signal.
|
||||
#[track_caller]
|
||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError>;
|
||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
||||
self.try_read_unchecked().map(Self::Storage::downcast_ref)
|
||||
}
|
||||
|
||||
/// Try to get a reference to the value without checking the lifetime.
|
||||
///
|
||||
/// NOTE: This method is completely safe because borrow checking is done at runtime.
|
||||
fn try_read_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError>;
|
||||
|
||||
/// Tet a reference to the value without checking the lifetime.
|
||||
///
|
||||
/// NOTE: This method is completely safe because borrow checking is done at runtime.
|
||||
fn read_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
self.try_read_unchecked().unwrap()
|
||||
}
|
||||
|
||||
/// Get the current value of the signal without checking the lifetime. **Unlike read, this will not subscribe the current scope to the signal which can cause parts of your UI to not update.**
|
||||
///
|
||||
/// If the signal has been dropped, this will panic.
|
||||
///
|
||||
/// NOTE: This method is completely safe because borrow checking is done at runtime.
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self>;
|
||||
|
||||
/// Get the current value of the state without subscribing to updates. If the value has been dropped, this will panic.
|
||||
fn peek(&self) -> ReadableRef<Self>;
|
||||
#[track_caller]
|
||||
fn peek(&self) -> ReadableRef<Self> {
|
||||
Self::Storage::downcast_ref(self.peek_unchecked())
|
||||
}
|
||||
|
||||
/// Clone the inner value and return it. If the value has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
@@ -171,7 +200,7 @@ pub struct ReadableValueIterator<'a, R> {
|
||||
}
|
||||
|
||||
impl<'a, T: 'static, R: Readable<Target = Vec<T>>> Iterator for ReadableValueIterator<'a, R> {
|
||||
type Item = ReadableRef<R, T>;
|
||||
type Item = ReadableRef<'a, R, T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let index = self.index;
|
||||
|
||||
@@ -59,16 +59,18 @@ impl<T, S: Storage<SignalData<T>>> Readable for ReadOnlySignal<T, S> {
|
||||
type Storage = S;
|
||||
|
||||
#[track_caller]
|
||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
||||
self.inner.try_read()
|
||||
fn try_read_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
self.inner.try_read_unchecked()
|
||||
}
|
||||
|
||||
/// Get the current value of the signal. **Unlike read, this will not subscribe the current scope to the signal which can cause parts of your UI to not update.**
|
||||
///
|
||||
/// If the signal has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
fn peek(&self) -> S::Ref<T> {
|
||||
self.inner.peek()
|
||||
fn peek_unchecked(&self) -> S::Ref<'static, T> {
|
||||
self.inner.peek_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::Memo;
|
||||
use crate::{
|
||||
read::Readable, write::Writable, CopyValue, GlobalMemo, GlobalSignal, ReactiveContext,
|
||||
ReadableRef,
|
||||
};
|
||||
use crate::{Memo, WritableRef};
|
||||
use dioxus_core::{prelude::IntoAttributeValue, ScopeId};
|
||||
use generational_box::{AnyStorage, Storage, SyncStorage, UnsyncStorage};
|
||||
use std::{
|
||||
@@ -168,8 +168,10 @@ impl<T, S: Storage<SignalData<T>>> Readable for Signal<T, S> {
|
||||
type Storage = S;
|
||||
|
||||
#[track_caller]
|
||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
||||
let inner = self.inner.try_read()?;
|
||||
fn try_read_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
let inner = self.inner.try_read_unchecked()?;
|
||||
|
||||
if let Some(reactive_context) = ReactiveContext::current() {
|
||||
tracing::trace!("Subscribing to the reactive context {}", reactive_context);
|
||||
@@ -182,19 +184,20 @@ impl<T, S: Storage<SignalData<T>>> Readable for Signal<T, S> {
|
||||
/// Get the current value of the signal. **Unlike read, this will not subscribe the current scope to the signal which can cause parts of your UI to not update.**
|
||||
///
|
||||
/// If the signal has been dropped, this will panic.
|
||||
fn peek(&self) -> ReadableRef<Self> {
|
||||
let inner = self.inner.read();
|
||||
#[track_caller]
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
let inner = self.inner.try_read_unchecked().unwrap();
|
||||
S::map(inner, |v| &v.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static, S: Storage<SignalData<T>>> Writable for Signal<T, S> {
|
||||
type Mut<R: ?Sized + 'static> = Write<R, S>;
|
||||
type Mut<'a, R: ?Sized + 'static> = Write<'a, R, S>;
|
||||
|
||||
fn map_mut<I: ?Sized, U: ?Sized + 'static, F: FnOnce(&mut I) -> &mut U>(
|
||||
ref_: Self::Mut<I>,
|
||||
ref_: Self::Mut<'_, I>,
|
||||
f: F,
|
||||
) -> Self::Mut<U> {
|
||||
) -> Self::Mut<'_, U> {
|
||||
Write::map(ref_, f)
|
||||
}
|
||||
|
||||
@@ -203,15 +206,21 @@ impl<T: 'static, S: Storage<SignalData<T>>> Writable for Signal<T, S> {
|
||||
U: ?Sized + 'static,
|
||||
F: FnOnce(&mut I) -> Option<&mut U>,
|
||||
>(
|
||||
ref_: Self::Mut<I>,
|
||||
ref_: Self::Mut<'_, I>,
|
||||
f: F,
|
||||
) -> Option<Self::Mut<U>> {
|
||||
) -> Option<Self::Mut<'_, U>> {
|
||||
Write::filter_map(ref_, f)
|
||||
}
|
||||
|
||||
fn downcast_mut<'a: 'b, 'b, R: ?Sized + 'static>(mut_: Self::Mut<'a, R>) -> Self::Mut<'b, R> {
|
||||
Write::downcast_lifetime(mut_)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn try_write(&mut self) -> Result<Self::Mut<T>, generational_box::BorrowMutError> {
|
||||
self.inner.try_write().map(|inner| {
|
||||
fn try_write_unchecked(
|
||||
&self,
|
||||
) -> Result<WritableRef<'static, Self>, generational_box::BorrowMutError> {
|
||||
self.inner.try_write_unchecked().map(|inner| {
|
||||
let borrow = S::map_mut(inner, |v| &mut v.value);
|
||||
Write {
|
||||
write: borrow,
|
||||
@@ -273,14 +282,14 @@ impl<'de, T: serde::Deserialize<'de> + 'static, Store: Storage<SignalData<T>>>
|
||||
///
|
||||
/// T is the current type of the write
|
||||
/// S is the storage type of the signal
|
||||
pub struct Write<T: ?Sized + 'static, S: AnyStorage = UnsyncStorage> {
|
||||
write: S::Mut<T>,
|
||||
pub struct Write<'a, T: ?Sized + 'static, S: AnyStorage = UnsyncStorage> {
|
||||
write: S::Mut<'a, T>,
|
||||
drop_signal: Box<dyn Any>,
|
||||
}
|
||||
|
||||
impl<T: ?Sized + 'static, S: AnyStorage> Write<T, S> {
|
||||
impl<'a, T: ?Sized + 'static, S: AnyStorage> Write<'a, T, S> {
|
||||
/// Map the mutable reference to the signal's value to a new type.
|
||||
pub fn map<O: ?Sized>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<O, S> {
|
||||
pub fn map<O: ?Sized>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<'a, O, S> {
|
||||
let Self {
|
||||
write, drop_signal, ..
|
||||
} = myself;
|
||||
@@ -294,16 +303,27 @@ impl<T: ?Sized + 'static, S: AnyStorage> Write<T, S> {
|
||||
pub fn filter_map<O: ?Sized>(
|
||||
myself: Self,
|
||||
f: impl FnOnce(&mut T) -> Option<&mut O>,
|
||||
) -> Option<Write<O, S>> {
|
||||
) -> Option<Write<'a, O, S>> {
|
||||
let Self {
|
||||
write, drop_signal, ..
|
||||
} = myself;
|
||||
let write = S::try_map_mut(write, f);
|
||||
write.map(|write| Write { write, drop_signal })
|
||||
}
|
||||
|
||||
/// Downcast the lifetime of the mutable reference to the signal's value.
|
||||
pub fn downcast_lifetime<'b>(mut_: Self) -> Write<'b, T, S>
|
||||
where
|
||||
'a: 'b,
|
||||
{
|
||||
Write {
|
||||
write: S::downcast_mut(mut_.write),
|
||||
drop_signal: mut_.drop_signal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + 'static, S: AnyStorage> Deref for Write<T, S> {
|
||||
impl<T: ?Sized + 'static, S: AnyStorage> Deref for Write<'_, T, S> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@@ -311,7 +331,7 @@ impl<T: ?Sized + 'static, S: AnyStorage> Deref for Write<T, S> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized, S: AnyStorage> DerefMut for Write<T, S> {
|
||||
impl<T: ?Sized, S: AnyStorage> DerefMut for Write<'_, T, S> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.write
|
||||
}
|
||||
|
||||
@@ -1,33 +1,58 @@
|
||||
use std::ops::DerefMut;
|
||||
use std::ops::IndexMut;
|
||||
use std::ops::{DerefMut, IndexMut};
|
||||
|
||||
use crate::read::Readable;
|
||||
|
||||
/// A reference to a value that can be read from.
|
||||
#[allow(type_alias_bounds)]
|
||||
pub type WritableRef<'a, T: Writable, O = <T as Readable>::Target> = T::Mut<'a, O>;
|
||||
|
||||
/// A trait for states that can be read from like [`crate::Signal`], or [`crate::GlobalSignal`]. You may choose to accept this trait as a parameter instead of the concrete type to allow for more flexibility in your API. For example, instead of creating two functions, one that accepts a [`crate::Signal`] and one that accepts a [`crate::GlobalSignal`], you can create one function that accepts a [`Writable`] type.
|
||||
pub trait Writable: Readable {
|
||||
/// The type of the reference.
|
||||
type Mut<R: ?Sized + 'static>: DerefMut<Target = R> + 'static;
|
||||
type Mut<'a, R: ?Sized + 'static>: DerefMut<Target = R>;
|
||||
|
||||
/// Map the reference to a new type.
|
||||
fn map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> &mut U>(
|
||||
ref_: Self::Mut<I>,
|
||||
ref_: Self::Mut<'_, I>,
|
||||
f: F,
|
||||
) -> Self::Mut<U>;
|
||||
) -> Self::Mut<'_, U>;
|
||||
|
||||
/// Try to map the reference to a new type.
|
||||
fn try_map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> Option<&mut U>>(
|
||||
ref_: Self::Mut<I>,
|
||||
ref_: Self::Mut<'_, I>,
|
||||
f: F,
|
||||
) -> Option<Self::Mut<U>>;
|
||||
) -> Option<Self::Mut<'_, U>>;
|
||||
|
||||
/// Downcast a mutable reference in a RefMut to a more specific lifetime
|
||||
///
|
||||
/// This function enforces the variance of the lifetime parameter `'a` in Ref.
|
||||
fn downcast_mut<'a: 'b, 'b, T: ?Sized + 'static>(mut_: Self::Mut<'a, T>) -> Self::Mut<'b, T>;
|
||||
|
||||
/// Get a mutable reference to the value. If the value has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
fn write(&mut self) -> Self::Mut<Self::Target> {
|
||||
fn write(&mut self) -> WritableRef<'_, Self> {
|
||||
self.try_write().unwrap()
|
||||
}
|
||||
|
||||
/// Try to get a mutable reference to the value. If the value has been dropped, this will panic.
|
||||
fn try_write(&mut self) -> Result<Self::Mut<Self::Target>, generational_box::BorrowMutError>;
|
||||
/// Try to get a mutable reference to the value.
|
||||
#[track_caller]
|
||||
fn try_write(&mut self) -> Result<WritableRef<'_, Self>, generational_box::BorrowMutError> {
|
||||
self.try_write_unchecked().map(Self::downcast_mut)
|
||||
}
|
||||
|
||||
/// Try to get a mutable reference to the value without checking the lifetime.
|
||||
///
|
||||
/// NOTE: This method is completely safe because borrow checking is done at runtime.
|
||||
fn try_write_unchecked(
|
||||
&self,
|
||||
) -> Result<WritableRef<'static, Self>, generational_box::BorrowMutError>;
|
||||
|
||||
/// Tet a mutable reference to the value without checking the lifetime.
|
||||
///
|
||||
/// NOTE: This method is completely safe because borrow checking is done at runtime.
|
||||
fn write_unchecked(&self) -> WritableRef<'static, Self> {
|
||||
self.try_write_unchecked().unwrap()
|
||||
}
|
||||
|
||||
/// Run a function with a mutable reference to the value. If the value has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
@@ -55,7 +80,10 @@ pub trait Writable: Readable {
|
||||
|
||||
/// Index into the inner value and return a reference to the result.
|
||||
#[track_caller]
|
||||
fn index_mut<I>(&mut self, index: I) -> Self::Mut<<Self::Target as std::ops::Index<I>>::Output>
|
||||
fn index_mut<I>(
|
||||
&mut self,
|
||||
index: I,
|
||||
) -> WritableRef<'_, Self, <Self::Target as std::ops::Index<I>>::Output>
|
||||
where
|
||||
Self::Target: std::ops::IndexMut<I>,
|
||||
{
|
||||
@@ -84,15 +112,14 @@ pub trait Writable: Readable {
|
||||
/// An extension trait for Writable<Option<T>> that provides some convenience methods.
|
||||
pub trait WritableOptionExt<T: 'static>: Writable<Target = Option<T>> {
|
||||
/// Gets the value out of the Option, or inserts the given value if the Option is empty.
|
||||
fn get_or_insert(&mut self, default: T) -> Self::Mut<T> {
|
||||
fn get_or_insert(&mut self, default: T) -> WritableRef<'_, Self, 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.
|
||||
fn get_or_insert_with(&mut self, default: impl FnOnce() -> T) -> Self::Mut<T> {
|
||||
let borrow = self.read();
|
||||
if borrow.is_none() {
|
||||
drop(borrow);
|
||||
fn get_or_insert_with(&mut self, default: impl FnOnce() -> T) -> WritableRef<'_, Self, T> {
|
||||
let is_none = self.read().is_none();
|
||||
if is_none {
|
||||
self.with_mut(|v| *v = Some(default()));
|
||||
Self::map_mut(self.write(), |v| v.as_mut().unwrap())
|
||||
} else {
|
||||
@@ -102,7 +129,7 @@ pub trait WritableOptionExt<T: 'static>: Writable<Target = Option<T>> {
|
||||
|
||||
/// Attempts to write the inner value of the Option.
|
||||
#[track_caller]
|
||||
fn as_mut(&mut self) -> Option<Self::Mut<T>> {
|
||||
fn as_mut(&mut self) -> Option<WritableRef<'_, Self, T>> {
|
||||
Self::try_map_mut(self.write(), |v: &mut Option<T>| v.as_mut())
|
||||
}
|
||||
}
|
||||
@@ -178,36 +205,40 @@ pub trait WritableVecExt<T: 'static>: Writable<Target = Vec<T>> {
|
||||
|
||||
/// Try to mutably get an element from the vector.
|
||||
#[track_caller]
|
||||
fn get_mut(&mut self, index: usize) -> Option<Self::Mut<T>> {
|
||||
fn get_mut(&mut self, index: usize) -> Option<WritableRef<'_, Self, T>> {
|
||||
Self::try_map_mut(self.write(), |v: &mut Vec<T>| v.get_mut(index))
|
||||
}
|
||||
|
||||
/// Gets an iterator over the values of the vector.
|
||||
#[track_caller]
|
||||
fn iter_mut(&self) -> WritableValueIterator<Self>
|
||||
fn iter_mut(&mut self) -> WritableValueIterator<'_, Self>
|
||||
where
|
||||
Self: Sized + Clone,
|
||||
{
|
||||
WritableValueIterator {
|
||||
index: 0,
|
||||
value: self.clone(),
|
||||
value: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the values of a `Writable<Vec<T>>`.
|
||||
pub struct WritableValueIterator<R> {
|
||||
pub struct WritableValueIterator<'a, R> {
|
||||
index: usize,
|
||||
value: R,
|
||||
value: &'a mut R,
|
||||
}
|
||||
|
||||
impl<T: 'static, R: Writable<Target = Vec<T>>> Iterator for WritableValueIterator<R> {
|
||||
type Item = R::Mut<T>;
|
||||
impl<'a, T: 'static, R: Writable<Target = Vec<T>>> Iterator for WritableValueIterator<'a, R> {
|
||||
type Item = WritableRef<'a, R, T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let index = self.index;
|
||||
self.index += 1;
|
||||
self.value.get_mut(index)
|
||||
R::try_map_mut(
|
||||
self.value.try_write_unchecked().unwrap(),
|
||||
|v: &mut Vec<T>| v.get_mut(index),
|
||||
)
|
||||
.map(R::downcast_mut)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user