Merge pull request #2022 from ealmloff/signal-lifetimes
Restore signal lifetimes; rename take to manually drop
This commit is contained in:
19 files changed
+315
-166
No files matched your search
+1
-1
@@ -80,7 +80,7 @@ fn BreedPic(breed: Signal<String>) -> Element {
|
|||||||
.await
|
.await
|
||||||
});
|
});
|
||||||
|
|
||||||
match fut.read().as_ref() {
|
match fut.read_unchecked().as_ref() {
|
||||||
Some(Ok(resp)) => rsx! {
|
Some(Ok(resp)) => rsx! {
|
||||||
button { onclick: move |_| fut.restart(), "Click to fetch another doggo" }
|
button { onclick: move |_| fut.restart(), "Click to fetch another doggo" }
|
||||||
img { max_width: "500px", max_height: "500px", src: "{resp.message}" }
|
img { max_width: "500px", max_height: "500px", src: "{resp.message}" }
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ fn Doggo() -> Element {
|
|||||||
.await
|
.await
|
||||||
});
|
});
|
||||||
|
|
||||||
match fut.read().as_ref() {
|
match fut.read_unchecked().as_ref() {
|
||||||
Some(Ok(resp)) => rsx! {
|
Some(Ok(resp)) => rsx! {
|
||||||
button { onclick: move |_| fut.restart(), "Click to fetch another doggo" }
|
button { onclick: move |_| fut.restart(), "Click to fetch another doggo" }
|
||||||
div { img { max_width: "500px", max_height: "500px", src: "{resp.message}" } }
|
div { img { max_width: "500px", max_height: "500px", src: "{resp.message}" } }
|
||||||
|
|||||||
@@ -25,14 +25,13 @@ fn use_inner_html(id: &'static str) -> Option<String> {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if let Some(html) = res.as_str() {
|
if let Some(html) = res.as_str() {
|
||||||
// serde_json::Value::String(html)
|
|
||||||
println!("html: {}", html);
|
println!("html: {}", html);
|
||||||
value.set(Some(html.to_string()));
|
value.set(Some(html.to_string()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
value.read().clone()
|
value()
|
||||||
}
|
}
|
||||||
|
|
||||||
const EXPECTED_HTML: &str = r#"<div style="width: 100px; height: 100px; color: rgb(0, 0, 0);" id="5"><input type="checkbox"><h1>text</h1><div><p>hello world</p></div></div>"#;
|
const EXPECTED_HTML: &str = r#"<div style="width: 100px; height: 100px; color: rgb(0, 0, 0);" id="5"><input type="checkbox"><h1>text</h1><div><p>hello world</p></div></div>"#;
|
||||||
|
|||||||
@@ -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.
|
/// Try to read the value. Returns None if the value is no longer valid.
|
||||||
#[track_caller]
|
#[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() {
|
if !self.validate() {
|
||||||
return Err(BorrowError::Dropped(ValueDroppedError {
|
return Err(BorrowError::Dropped(ValueDroppedError {
|
||||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
#[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.
|
/// Read the value. Panics if the value is no longer valid.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn read(&self) -> S::Ref<T> {
|
pub fn read(&self) -> S::Ref<'static, T> {
|
||||||
self.try_read().unwrap()
|
self.try_read().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to write the value. Returns None if the value is no longer valid.
|
/// Try to write the value. Returns None if the value is no longer valid.
|
||||||
#[track_caller]
|
#[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() {
|
if !self.validate() {
|
||||||
return Err(BorrowMutError::Dropped(ValueDroppedError {
|
return Err(BorrowMutError::Dropped(ValueDroppedError {
|
||||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
#[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.
|
/// Write the value. Panics if the value is no longer valid.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn write(&self) -> S::Mut<T> {
|
pub fn write(&self) -> S::Mut<'static, T> {
|
||||||
self.try_write().unwrap()
|
self.try_write().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,8 +186,8 @@ impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take the value out of the generational box and invalidate the generational box. This will return the value if the value was taken.
|
/// Drop the value out of the generational box and invalidate the generational box. This will return the value if the value was taken.
|
||||||
pub fn take(&self) -> Option<T> {
|
pub fn manually_drop(&self) -> Option<T> {
|
||||||
if self.validate() {
|
if self.validate() {
|
||||||
Storage::take(&self.raw.0.data)
|
Storage::take(&self.raw.0.data)
|
||||||
} else {
|
} else {
|
||||||
@@ -210,13 +210,13 @@ pub trait Storage<Data = ()>: AnyStorage + 'static {
|
|||||||
fn try_read(
|
fn try_read(
|
||||||
&'static self,
|
&'static self,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefBorrowInfo,
|
#[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.
|
/// Try to write the value. Returns None if the value is no longer valid.
|
||||||
fn try_write(
|
fn try_write(
|
||||||
&'static self,
|
&'static self,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefMutBorrowInfo,
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefMutBorrowInfo,
|
||||||
) -> Result<Self::Mut<Data>, BorrowMutError>;
|
) -> Result<Self::Mut<'static, Data>, BorrowMutError>;
|
||||||
|
|
||||||
/// Set the value
|
/// Set the value
|
||||||
fn set(&'static self, value: Data);
|
fn set(&'static self, value: Data);
|
||||||
@@ -228,35 +228,49 @@ pub trait Storage<Data = ()>: AnyStorage + 'static {
|
|||||||
/// A trait for any storage backing type.
|
/// A trait for any storage backing type.
|
||||||
pub trait AnyStorage: Default {
|
pub trait AnyStorage: Default {
|
||||||
/// The reference this storage type returns.
|
/// 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.
|
/// 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. Rust will typically infer this cast with a concrete type, but it cannot with a generic type.
|
||||||
|
fn downcast_lifetime_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 Mut. Rust will typically infer this cast with a concrete type, but it cannot with a generic type.
|
||||||
|
fn downcast_lifetime_mut<'a: 'b, 'b, T: ?Sized + 'static>(
|
||||||
|
mut_: Self::Mut<'a, T>,
|
||||||
|
) -> Self::Mut<'b, T>;
|
||||||
|
|
||||||
/// Try to map the mutable ref.
|
/// Try to map the mutable ref.
|
||||||
fn try_map_mut<T: ?Sized, U: ?Sized + 'static>(
|
fn try_map_mut<T: ?Sized + 'static, U: ?Sized + 'static>(
|
||||||
mut_ref: Self::Mut<T>,
|
mut_ref: Self::Mut<'_, T>,
|
||||||
f: impl FnOnce(&mut T) -> Option<&mut U>,
|
f: impl FnOnce(&mut T) -> Option<&mut U>,
|
||||||
) -> Option<Self::Mut<U>>;
|
) -> Option<Self::Mut<'_, U>>;
|
||||||
|
|
||||||
/// Map the mutable ref.
|
/// Map the mutable ref.
|
||||||
fn map_mut<T: ?Sized, U: ?Sized + 'static>(
|
fn map_mut<T: ?Sized + 'static, U: ?Sized + 'static>(
|
||||||
mut_ref: Self::Mut<T>,
|
mut_ref: Self::Mut<'_, T>,
|
||||||
f: impl FnOnce(&mut T) -> &mut U,
|
f: impl FnOnce(&mut T) -> &mut U,
|
||||||
) -> Self::Mut<U> {
|
) -> Self::Mut<'_, U> {
|
||||||
Self::try_map_mut(mut_ref, |v| Some(f(v))).unwrap()
|
Self::try_map_mut(mut_ref, |v| Some(f(v))).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to map the ref.
|
/// Try to map the ref.
|
||||||
fn try_map<T: ?Sized, U: ?Sized + 'static>(
|
fn try_map<T: ?Sized, U: ?Sized + 'static>(
|
||||||
ref_: Self::Ref<T>,
|
ref_: Self::Ref<'_, T>,
|
||||||
f: impl FnOnce(&T) -> Option<&U>,
|
f: impl FnOnce(&T) -> Option<&U>,
|
||||||
) -> Option<Self::Ref<U>>;
|
) -> Option<Self::Ref<'_, U>>;
|
||||||
|
|
||||||
/// Map the ref.
|
/// Map the ref.
|
||||||
fn map<T: ?Sized, U: ?Sized + 'static>(
|
fn map<T: ?Sized, U: ?Sized + 'static>(
|
||||||
ref_: Self::Ref<T>,
|
ref_: Self::Ref<'_, T>,
|
||||||
f: impl FnOnce(&T) -> &U,
|
f: impl FnOnce(&T) -> &U,
|
||||||
) -> Self::Ref<U> {
|
) -> Self::Ref<'_, U> {
|
||||||
Self::try_map(ref_, |v| Some(f(v))).unwrap()
|
Self::try_map(ref_, |v| Some(f(v))).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,13 +20,25 @@ fn sync_runtime() -> &'static Arc<Mutex<Vec<MemoryLocation<SyncStorage>>>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AnyStorage for SyncStorage {
|
impl AnyStorage for SyncStorage {
|
||||||
type Ref<R: ?Sized + 'static> = GenerationalRef<MappedRwLockReadGuard<'static, R>>;
|
type Ref<'a, R: ?Sized + 'static> = GenerationalRef<MappedRwLockReadGuard<'a, R>>;
|
||||||
type Mut<W: ?Sized + 'static> = GenerationalRefMut<MappedRwLockWriteGuard<'static, W>>;
|
type Mut<'a, W: ?Sized + 'static> = GenerationalRefMut<MappedRwLockWriteGuard<'a, W>>;
|
||||||
|
|
||||||
fn try_map<I: ?Sized, U: ?Sized + 'static>(
|
fn downcast_lifetime_ref<'a: 'b, 'b, T: ?Sized + 'static>(
|
||||||
ref_: Self::Ref<I>,
|
ref_: Self::Ref<'a, T>,
|
||||||
|
) -> Self::Ref<'b, T> {
|
||||||
|
ref_
|
||||||
|
}
|
||||||
|
|
||||||
|
fn downcast_lifetime_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>,
|
f: impl FnOnce(&I) -> Option<&U>,
|
||||||
) -> Option<Self::Ref<U>> {
|
) -> Option<Self::Ref<'_, U>> {
|
||||||
let GenerationalRef {
|
let GenerationalRef {
|
||||||
inner,
|
inner,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
@@ -46,10 +58,10 @@ impl AnyStorage for SyncStorage {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_map_mut<I: ?Sized, U: ?Sized + 'static>(
|
fn try_map_mut<I: ?Sized + 'static, U: ?Sized + 'static>(
|
||||||
mut_ref: Self::Mut<I>,
|
mut_ref: Self::Mut<'_, I>,
|
||||||
f: impl FnOnce(&mut I) -> Option<&mut U>,
|
f: impl FnOnce(&mut I) -> Option<&mut U>,
|
||||||
) -> Option<Self::Mut<U>> {
|
) -> Option<Self::Mut<'_, U>> {
|
||||||
let GenerationalRefMut {
|
let GenerationalRefMut {
|
||||||
inner,
|
inner,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
@@ -101,7 +113,7 @@ impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
|
|||||||
&'static self,
|
&'static self,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
at: crate::GenerationalRefBorrowInfo,
|
at: crate::GenerationalRefBorrowInfo,
|
||||||
) -> Result<Self::Ref<T>, error::BorrowError> {
|
) -> Result<Self::Ref<'static, T>, error::BorrowError> {
|
||||||
let read = self.0.try_read();
|
let read = self.0.try_read();
|
||||||
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
@@ -132,7 +144,7 @@ impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
|
|||||||
&'static self,
|
&'static self,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
at: crate::GenerationalRefMutBorrowInfo,
|
at: crate::GenerationalRefMutBorrowInfo,
|
||||||
) -> Result<Self::Mut<T>, error::BorrowMutError> {
|
) -> Result<Self::Mut<'static, T>, error::BorrowMutError> {
|
||||||
let write = self.0.try_write();
|
let write = self.0.try_write();
|
||||||
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[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"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
at: crate::GenerationalRefBorrowInfo,
|
at: crate::GenerationalRefBorrowInfo,
|
||||||
) -> Result<Self::Ref<T>, error::BorrowError> {
|
) -> Result<Self::Ref<'static, T>, error::BorrowError> {
|
||||||
let borrow = self.0.try_borrow();
|
let borrow = self.0.try_borrow();
|
||||||
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
@@ -46,7 +46,7 @@ impl<T: 'static> Storage<T> for UnsyncStorage {
|
|||||||
&'static self,
|
&'static self,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
at: crate::GenerationalRefMutBorrowInfo,
|
at: crate::GenerationalRefMutBorrowInfo,
|
||||||
) -> Result<Self::Mut<T>, error::BorrowMutError> {
|
) -> Result<Self::Mut<'static, T>, error::BorrowMutError> {
|
||||||
let borrow = self.0.try_borrow_mut();
|
let borrow = self.0.try_borrow_mut();
|
||||||
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
@@ -89,13 +89,25 @@ thread_local! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AnyStorage for UnsyncStorage {
|
impl AnyStorage for UnsyncStorage {
|
||||||
type Ref<R: ?Sized + 'static> = GenerationalRef<Ref<'static, R>>;
|
type Ref<'a, R: ?Sized + 'static> = GenerationalRef<Ref<'a, R>>;
|
||||||
type Mut<W: ?Sized + 'static> = GenerationalRefMut<RefMut<'static, W>>;
|
type Mut<'a, W: ?Sized + 'static> = GenerationalRefMut<RefMut<'a, W>>;
|
||||||
|
|
||||||
fn try_map<I: ?Sized, U: ?Sized + 'static>(
|
fn downcast_lifetime_ref<'a: 'b, 'b, T: ?Sized + 'static>(
|
||||||
_self: Self::Ref<I>,
|
ref_: Self::Ref<'a, T>,
|
||||||
|
) -> Self::Ref<'b, T> {
|
||||||
|
ref_
|
||||||
|
}
|
||||||
|
|
||||||
|
fn downcast_lifetime_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>,
|
f: impl FnOnce(&I) -> Option<&U>,
|
||||||
) -> Option<Self::Ref<U>> {
|
) -> Option<Self::Ref<'_, U>> {
|
||||||
let GenerationalRef {
|
let GenerationalRef {
|
||||||
inner,
|
inner,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
@@ -109,10 +121,10 @@ impl AnyStorage for UnsyncStorage {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_map_mut<I: ?Sized, U: ?Sized + 'static>(
|
fn try_map_mut<I: ?Sized + 'static, U: ?Sized + 'static>(
|
||||||
mut_ref: Self::Mut<I>,
|
mut_ref: Self::Mut<'_, I>,
|
||||||
f: impl FnOnce(&mut I) -> Option<&mut U>,
|
f: impl FnOnce(&mut I) -> Option<&mut U>,
|
||||||
) -> Option<Self::Mut<U>> {
|
) -> Option<Self::Mut<'_, U>> {
|
||||||
let GenerationalRefMut {
|
let GenerationalRefMut {
|
||||||
inner,
|
inner,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ fn Route3(dynamic: String) -> Element {
|
|||||||
oninput: move |evt| {
|
oninput: move |evt| {
|
||||||
*current_route_str.write() = evt.value();
|
*current_route_str.write() = evt.value();
|
||||||
},
|
},
|
||||||
value: "{current_route_str.read()}"
|
value: "{current_route_str}"
|
||||||
}
|
}
|
||||||
"dynamic: {dynamic}"
|
"dynamic: {dynamic}"
|
||||||
Link { to: Route::Route2 { user_id: 8888 }, "hello world link" }
|
Link { to: Route::Route2 { user_id: 8888 }, "hello world link" }
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ impl RouterContext {
|
|||||||
/// Will fail silently if there is no previous location to go to.
|
/// Will fail silently if there is no previous location to go to.
|
||||||
pub fn go_back(&self) {
|
pub fn go_back(&self) {
|
||||||
{
|
{
|
||||||
self.inner.clone().write().history.go_back();
|
self.inner.write_unchecked().history.go_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.change_route();
|
self.change_route();
|
||||||
@@ -168,7 +168,7 @@ impl RouterContext {
|
|||||||
/// Will fail silently if there is no next location to go to.
|
/// Will fail silently if there is no next location to go to.
|
||||||
pub fn go_forward(&self) {
|
pub fn go_forward(&self) {
|
||||||
{
|
{
|
||||||
self.inner.clone().write().history.go_forward();
|
self.inner.write_unchecked().history.go_forward();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.change_route();
|
self.change_route();
|
||||||
@@ -179,7 +179,7 @@ impl RouterContext {
|
|||||||
target: NavigationTarget<Rc<dyn Any>>,
|
target: NavigationTarget<Rc<dyn Any>>,
|
||||||
) -> Option<ExternalNavigationFailure> {
|
) -> Option<ExternalNavigationFailure> {
|
||||||
{
|
{
|
||||||
let mut write = self.inner.clone().write();
|
let mut write = self.inner.write_unchecked();
|
||||||
match target {
|
match target {
|
||||||
NavigationTarget::Internal(p) => write.history.push(p),
|
NavigationTarget::Internal(p) => write.history.push(p),
|
||||||
NavigationTarget::External(e) => return write.external(e),
|
NavigationTarget::External(e) => return write.external(e),
|
||||||
@@ -195,7 +195,7 @@ impl RouterContext {
|
|||||||
pub fn push(&self, target: impl Into<IntoRoutable>) -> Option<ExternalNavigationFailure> {
|
pub fn push(&self, target: impl Into<IntoRoutable>) -> Option<ExternalNavigationFailure> {
|
||||||
let target = self.resolve_into_routable(target.into());
|
let target = self.resolve_into_routable(target.into());
|
||||||
{
|
{
|
||||||
let mut write = self.inner.clone().write();
|
let mut write = self.inner.write_unchecked();
|
||||||
match target {
|
match target {
|
||||||
NavigationTarget::Internal(p) => write.history.push(p),
|
NavigationTarget::Internal(p) => write.history.push(p),
|
||||||
NavigationTarget::External(e) => return write.external(e),
|
NavigationTarget::External(e) => return write.external(e),
|
||||||
@@ -212,7 +212,7 @@ impl RouterContext {
|
|||||||
let target = self.resolve_into_routable(target.into());
|
let target = self.resolve_into_routable(target.into());
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = self.inner.clone().write();
|
let mut state = self.inner.write_unchecked();
|
||||||
match target {
|
match target {
|
||||||
NavigationTarget::Internal(p) => state.history.replace(p),
|
NavigationTarget::Internal(p) => state.history.replace(p),
|
||||||
NavigationTarget::External(e) => return state.external(e),
|
NavigationTarget::External(e) => return state.external(e),
|
||||||
@@ -276,14 +276,14 @@ impl RouterContext {
|
|||||||
|
|
||||||
/// Clear any unresolved errors
|
/// Clear any unresolved errors
|
||||||
pub fn clear_error(&self) {
|
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.unresolved_error = None;
|
||||||
|
|
||||||
write_inner.update_subscribers();
|
write_inner.update_subscribers();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn render_error(&self) -> Element {
|
pub(crate) fn render_error(&self) -> Element {
|
||||||
let inner_read = self.inner.clone().write();
|
let inner_read = self.inner.write_unchecked();
|
||||||
inner_read
|
inner_read
|
||||||
.unresolved_error
|
.unresolved_error
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -297,7 +297,7 @@ impl RouterContext {
|
|||||||
let callback = callback.clone();
|
let callback = callback.clone();
|
||||||
drop(self_read);
|
drop(self_read);
|
||||||
if let Some(new) = callback(myself) {
|
if let Some(new) = callback(myself) {
|
||||||
let mut self_write = self.inner.clone().write();
|
let mut self_write = self.inner.write_unchecked();
|
||||||
match new {
|
match new {
|
||||||
NavigationTarget::Internal(p) => self_write.history.replace(p),
|
NavigationTarget::Internal(p) => self_write.history.replace(p),
|
||||||
NavigationTarget::External(e) => return self_write.external(e),
|
NavigationTarget::External(e) => return self_write.external(e),
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ fn app() -> Element {
|
|||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn Read() -> Element {
|
fn Read() -> Element {
|
||||||
let mut signal = use_signal_sync(|| 0);
|
let signal = use_signal_sync(|| 0);
|
||||||
|
|
||||||
let _write = signal.write();
|
let _write = signal.write_unchecked();
|
||||||
let _read = signal.read();
|
let _read = signal.read();
|
||||||
|
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@@ -40,10 +40,10 @@ fn Read() -> Element {
|
|||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn ReadMut() -> Element {
|
fn ReadMut() -> Element {
|
||||||
let mut signal = use_signal_sync(|| 0);
|
let signal = use_signal_sync(|| 0);
|
||||||
|
|
||||||
let _read = signal.read();
|
let _read = signal.read();
|
||||||
let _write = signal.write();
|
let _write = signal.write_unchecked();
|
||||||
|
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use generational_box::{GenerationalBox, Owner, Storage};
|
|||||||
|
|
||||||
use crate::ReadableRef;
|
use crate::ReadableRef;
|
||||||
use crate::Writable;
|
use crate::Writable;
|
||||||
|
use crate::WritableRef;
|
||||||
use crate::{ReactiveContext, Readable};
|
use crate::{ReactiveContext, Readable};
|
||||||
|
|
||||||
/// Run a closure with the given owner.
|
/// Run a closure with the given owner.
|
||||||
@@ -189,11 +190,9 @@ impl<T: 'static, S: Storage<T>> CopyValue<T, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take the value out of the CopyValue, invalidating the value in the process.
|
/// Manually drop the value in the CopyValue, invalidating the value in the process.
|
||||||
pub fn take(&self) -> T {
|
pub fn manually_drop(&self) -> Option<T> {
|
||||||
self.value
|
self.value.manually_drop()
|
||||||
.take()
|
|
||||||
.expect("value is already dropped or borrowed")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the scope this value was created in.
|
/// Get the scope this value was created in.
|
||||||
@@ -211,40 +210,45 @@ impl<T: 'static, S: Storage<T>> Readable for CopyValue<T, S> {
|
|||||||
type Target = T;
|
type Target = T;
|
||||||
type Storage = S;
|
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()
|
self.value.try_read()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek(&self) -> ReadableRef<Self> {
|
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||||
self.value.read()
|
self.value.read()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static, S: Storage<T>> Writable for CopyValue<T, S> {
|
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>(
|
fn map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> &mut U>(
|
||||||
mut_: Self::Mut<I>,
|
mut_: Self::Mut<'_, I>,
|
||||||
f: F,
|
f: F,
|
||||||
) -> Self::Mut<U> {
|
) -> Self::Mut<'_, U> {
|
||||||
S::map_mut(mut_, f)
|
S::map_mut(mut_, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> Option<&mut U>>(
|
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,
|
f: F,
|
||||||
) -> Option<Self::Mut<U>> {
|
) -> Option<Self::Mut<'_, U>> {
|
||||||
S::try_map_mut(mut_, f)
|
S::try_map_mut(mut_, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
fn downcast_lifetime_mut<'a: 'b, 'b, R: ?Sized + 'static>(
|
||||||
fn try_write(&mut self) -> Result<Self::Mut<T>, generational_box::BorrowMutError> {
|
mut_: Self::Mut<'a, R>,
|
||||||
self.value.try_write()
|
) -> Self::Mut<'b, R> {
|
||||||
|
S::downcast_lifetime_mut(mut_)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn write(&mut self) -> Self::Mut<T> {
|
fn try_write_unchecked(
|
||||||
self.value.write()
|
&self,
|
||||||
|
) -> Result<WritableRef<'static, Self>, generational_box::BorrowMutError> {
|
||||||
|
self.value.try_write()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
|||||||
@@ -56,13 +56,15 @@ impl<T: PartialEq + 'static> Readable for GlobalMemo<T> {
|
|||||||
type Storage = UnsyncStorage;
|
type Storage = UnsyncStorage;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
fn try_read_unchecked(
|
||||||
self.memo().try_read()
|
&self,
|
||||||
|
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||||
|
self.memo().try_read_unchecked()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn peek(&self) -> ReadableRef<Self> {
|
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||||
self.memo().peek()
|
self.memo().peek_unchecked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::write::Writable;
|
use crate::write::Writable;
|
||||||
use crate::Write;
|
|
||||||
use crate::{read::Readable, ReadableRef};
|
use crate::{read::Readable, ReadableRef};
|
||||||
|
use crate::{WritableRef, Write};
|
||||||
use dioxus_core::prelude::{IntoAttributeValue, ScopeId};
|
use dioxus_core::prelude::{IntoAttributeValue, ScopeId};
|
||||||
use generational_box::UnsyncStorage;
|
use generational_box::UnsyncStorage;
|
||||||
use std::{mem::MaybeUninit, ops::Deref};
|
use std::{mem::MaybeUninit, ops::Deref};
|
||||||
@@ -44,8 +44,8 @@ impl<T: 'static> GlobalSignal<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write this value
|
/// Write this value
|
||||||
pub fn write(&self) -> Write<T, UnsyncStorage> {
|
pub fn write(&self) -> Write<'static, T, UnsyncStorage> {
|
||||||
self.signal().write()
|
self.signal().try_write_unchecked().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the scope the signal was created in.
|
/// Get the scope the signal was created in.
|
||||||
@@ -71,23 +71,25 @@ impl<T: 'static> Readable for GlobalSignal<T> {
|
|||||||
type Storage = UnsyncStorage;
|
type Storage = UnsyncStorage;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
fn try_read_unchecked(
|
||||||
self.signal().try_read()
|
&self,
|
||||||
|
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||||
|
self.signal().try_read_unchecked()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn peek(&self) -> ReadableRef<Self> {
|
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||||
self.signal().peek()
|
self.signal().peek_unchecked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> Writable for GlobalSignal<T> {
|
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>(
|
fn map_mut<I: ?Sized, U: ?Sized + 'static, F: FnOnce(&mut I) -> &mut U>(
|
||||||
ref_: Self::Mut<I>,
|
ref_: Self::Mut<'_, I>,
|
||||||
f: F,
|
f: F,
|
||||||
) -> Self::Mut<U> {
|
) -> Self::Mut<'_, U> {
|
||||||
Write::map(ref_, f)
|
Write::map(ref_, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,15 +98,23 @@ impl<T: 'static> Writable for GlobalSignal<T> {
|
|||||||
U: ?Sized + 'static,
|
U: ?Sized + 'static,
|
||||||
F: FnOnce(&mut I) -> Option<&mut U>,
|
F: FnOnce(&mut I) -> Option<&mut U>,
|
||||||
>(
|
>(
|
||||||
ref_: Self::Mut<I>,
|
ref_: Self::Mut<'_, I>,
|
||||||
f: F,
|
f: F,
|
||||||
) -> Option<Self::Mut<U>> {
|
) -> Option<Self::Mut<'_, U>> {
|
||||||
Write::filter_map(ref_, f)
|
Write::filter_map(ref_, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn downcast_lifetime_mut<'a: 'b, 'b, R: ?Sized + 'static>(
|
||||||
|
mut_: Self::Mut<'a, R>,
|
||||||
|
) -> Self::Mut<'b, R> {
|
||||||
|
Write::downcast_lifetime(mut_)
|
||||||
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn try_write(&mut self) -> Result<Self::Mut<T>, generational_box::BorrowMutError> {
|
fn try_write_unchecked(
|
||||||
self.signal().try_write()
|
&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.
|
/// A read only signal that has been mapped to a new type.
|
||||||
pub struct MappedSignal<O: ?Sized + 'static, S: AnyStorage = UnsyncStorage> {
|
pub struct MappedSignal<O: ?Sized + 'static, S: AnyStorage = UnsyncStorage> {
|
||||||
try_read: Rc<dyn Fn() -> Result<S::Ref<O>, generational_box::BorrowError> + 'static>,
|
try_read: Rc<dyn Fn() -> Result<S::Ref<'static, O>, generational_box::BorrowError> + 'static>,
|
||||||
peek: Rc<dyn Fn() -> S::Ref<O> + 'static>,
|
peek: Rc<dyn Fn() -> S::Ref<'static, O> + 'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<O: ?Sized, S: AnyStorage> Clone for MappedSignal<O, S> {
|
impl<O: ?Sized, S: AnyStorage> Clone for MappedSignal<O, S> {
|
||||||
@@ -26,8 +26,10 @@ where
|
|||||||
{
|
{
|
||||||
/// Create a new mapped signal.
|
/// Create a new mapped signal.
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
try_read: Rc<dyn Fn() -> Result<S::Ref<O>, generational_box::BorrowError> + 'static>,
|
try_read: Rc<
|
||||||
peek: Rc<dyn Fn() -> S::Ref<O> + 'static>,
|
dyn Fn() -> Result<S::Ref<'static, O>, generational_box::BorrowError> + 'static,
|
||||||
|
>,
|
||||||
|
peek: Rc<dyn Fn() -> S::Ref<'static, O> + 'static>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
MappedSignal { try_read, peek }
|
MappedSignal { try_read, peek }
|
||||||
}
|
}
|
||||||
@@ -41,11 +43,13 @@ where
|
|||||||
type Target = O;
|
type Target = O;
|
||||||
type Storage = S;
|
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)()
|
(self.try_read)()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek(&self) -> ReadableRef<Self> {
|
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||||
(self.peek)()
|
(self.peek)()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,8 +163,10 @@ where
|
|||||||
type Storage = UnsyncStorage;
|
type Storage = UnsyncStorage;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
fn try_read_unchecked(
|
||||||
let read = self.inner.try_read();
|
&self,
|
||||||
|
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||||
|
let read = self.inner.try_read_unchecked();
|
||||||
match read {
|
match read {
|
||||||
Ok(r) => {
|
Ok(r) => {
|
||||||
let needs_update = self
|
let needs_update = self
|
||||||
@@ -175,7 +177,7 @@ where
|
|||||||
if needs_update {
|
if needs_update {
|
||||||
drop(r);
|
drop(r);
|
||||||
self.recompute();
|
self.recompute();
|
||||||
self.inner.try_read()
|
self.inner.try_read_unchecked()
|
||||||
} else {
|
} else {
|
||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
@@ -188,8 +190,8 @@ where
|
|||||||
///
|
///
|
||||||
/// If the signal has been dropped, this will panic.
|
/// If the signal has been dropped, this will panic.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn peek(&self) -> ReadableRef<Self> {
|
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||||
self.inner.peek()
|
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
|
/// Returns true if the context was marked as dirty, or false if the context has been dropped
|
||||||
pub fn mark_dirty(&self) -> bool {
|
pub fn mark_dirty(&self) -> bool {
|
||||||
let mut copy = self.inner;
|
if let Ok(mut self_write) = self.inner.try_write_unchecked() {
|
||||||
if let Ok(mut self_write) = copy.try_write() {
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
tracing::trace!(
|
tracing::trace!(
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ use crate::MappedSignal;
|
|||||||
|
|
||||||
/// A reference to a value that can be read from.
|
/// A reference to a value that can be read from.
|
||||||
#[allow(type_alias_bounds)]
|
#[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.
|
/// 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 {
|
pub trait Readable {
|
||||||
@@ -27,15 +28,17 @@ pub trait Readable {
|
|||||||
let mapping = mapping.clone();
|
let mapping = mapping.clone();
|
||||||
move || {
|
move || {
|
||||||
self_
|
self_
|
||||||
.try_read()
|
.try_read_unchecked()
|
||||||
.map(|ref_| <Self::Storage as AnyStorage>::map(ref_, |r| mapping(r)))
|
.map(|ref_| <Self::Storage as AnyStorage>::map(ref_, |r| mapping(r)))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
as Rc<
|
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)))
|
let peek = Rc::new(move || {
|
||||||
as Rc<dyn Fn() -> ReadableRef<Self, O> + 'static>;
|
<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)
|
MappedSignal::new(try_read, peek)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,12 +50,39 @@ pub trait Readable {
|
|||||||
self.try_read().unwrap()
|
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]
|
#[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_lifetime_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.
|
/// 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_lifetime_ref(self.peek_unchecked())
|
||||||
|
}
|
||||||
|
|
||||||
/// Clone the inner value and return it. If the value has been dropped, this will panic.
|
/// Clone the inner value and return it. If the value has been dropped, this will panic.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
@@ -171,7 +201,7 @@ pub struct ReadableValueIterator<'a, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: 'static, R: Readable<Target = Vec<T>>> Iterator for 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> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let index = self.index;
|
let index = self.index;
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ impl<T: 'static, S: Storage<SignalData<T>>> ReadOnlySignal<T, S> {
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
/// This should only be used by the `rsx!` macro.
|
/// This should only be used by the `rsx!` macro.
|
||||||
pub fn __take(&self) -> T {
|
pub fn __take(&self) -> T {
|
||||||
self.inner.take()
|
self.inner
|
||||||
|
.manually_drop()
|
||||||
|
.expect("Signal has already been dropped")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,16 +61,18 @@ impl<T, S: Storage<SignalData<T>>> Readable for ReadOnlySignal<T, S> {
|
|||||||
type Storage = S;
|
type Storage = S;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
fn try_read_unchecked(
|
||||||
self.inner.try_read()
|
&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.**
|
/// 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.
|
/// If the signal has been dropped, this will panic.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn peek(&self) -> S::Ref<T> {
|
fn peek_unchecked(&self) -> S::Ref<'static, T> {
|
||||||
self.inner.peek()
|
self.inner.peek_unchecked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::Memo;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
read::Readable, write::Writable, CopyValue, GlobalMemo, GlobalSignal, ReactiveContext,
|
read::Readable, write::Writable, CopyValue, GlobalMemo, GlobalSignal, ReactiveContext,
|
||||||
ReadableRef,
|
ReadableRef,
|
||||||
};
|
};
|
||||||
|
use crate::{Memo, WritableRef};
|
||||||
use dioxus_core::{prelude::IntoAttributeValue, ScopeId};
|
use dioxus_core::{prelude::IntoAttributeValue, ScopeId};
|
||||||
use generational_box::{AnyStorage, Storage, SyncStorage, UnsyncStorage};
|
use generational_box::{AnyStorage, Storage, SyncStorage, UnsyncStorage};
|
||||||
use std::{
|
use std::{
|
||||||
@@ -136,9 +136,9 @@ impl<T: 'static, S: Storage<SignalData<T>>> Signal<T, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take the value out of the signal, invalidating the signal in the process.
|
/// Drop the value out of the signal, invalidating the signal in the process.
|
||||||
pub fn take(&self) -> T {
|
pub fn manually_drop(&self) -> Option<T> {
|
||||||
self.inner.take().value
|
self.inner.manually_drop().map(|i| i.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the scope the signal was created in.
|
/// Get the scope the signal was created in.
|
||||||
@@ -168,8 +168,10 @@ impl<T, S: Storage<SignalData<T>>> Readable for Signal<T, S> {
|
|||||||
type Storage = S;
|
type Storage = S;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
fn try_read_unchecked(
|
||||||
let inner = self.inner.try_read()?;
|
&self,
|
||||||
|
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||||
|
let inner = self.inner.try_read_unchecked()?;
|
||||||
|
|
||||||
if let Some(reactive_context) = ReactiveContext::current() {
|
if let Some(reactive_context) = ReactiveContext::current() {
|
||||||
tracing::trace!("Subscribing to the reactive context {}", reactive_context);
|
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.**
|
/// 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.
|
/// If the signal has been dropped, this will panic.
|
||||||
fn peek(&self) -> ReadableRef<Self> {
|
#[track_caller]
|
||||||
let inner = self.inner.read();
|
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||||
|
let inner = self.inner.try_read_unchecked().unwrap();
|
||||||
S::map(inner, |v| &v.value)
|
S::map(inner, |v| &v.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static, S: Storage<SignalData<T>>> Writable for Signal<T, S> {
|
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>(
|
fn map_mut<I: ?Sized, U: ?Sized + 'static, F: FnOnce(&mut I) -> &mut U>(
|
||||||
ref_: Self::Mut<I>,
|
ref_: Self::Mut<'_, I>,
|
||||||
f: F,
|
f: F,
|
||||||
) -> Self::Mut<U> {
|
) -> Self::Mut<'_, U> {
|
||||||
Write::map(ref_, f)
|
Write::map(ref_, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,15 +206,23 @@ impl<T: 'static, S: Storage<SignalData<T>>> Writable for Signal<T, S> {
|
|||||||
U: ?Sized + 'static,
|
U: ?Sized + 'static,
|
||||||
F: FnOnce(&mut I) -> Option<&mut U>,
|
F: FnOnce(&mut I) -> Option<&mut U>,
|
||||||
>(
|
>(
|
||||||
ref_: Self::Mut<I>,
|
ref_: Self::Mut<'_, I>,
|
||||||
f: F,
|
f: F,
|
||||||
) -> Option<Self::Mut<U>> {
|
) -> Option<Self::Mut<'_, U>> {
|
||||||
Write::filter_map(ref_, f)
|
Write::filter_map(ref_, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn downcast_lifetime_mut<'a: 'b, 'b, R: ?Sized + 'static>(
|
||||||
|
mut_: Self::Mut<'a, R>,
|
||||||
|
) -> Self::Mut<'b, R> {
|
||||||
|
Write::downcast_lifetime(mut_)
|
||||||
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn try_write(&mut self) -> Result<Self::Mut<T>, generational_box::BorrowMutError> {
|
fn try_write_unchecked(
|
||||||
self.inner.try_write().map(|inner| {
|
&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);
|
let borrow = S::map_mut(inner, |v| &mut v.value);
|
||||||
Write {
|
Write {
|
||||||
write: borrow,
|
write: borrow,
|
||||||
@@ -273,14 +284,14 @@ impl<'de, T: serde::Deserialize<'de> + 'static, Store: Storage<SignalData<T>>>
|
|||||||
///
|
///
|
||||||
/// T is the current type of the write
|
/// T is the current type of the write
|
||||||
/// S is the storage type of the signal
|
/// S is the storage type of the signal
|
||||||
pub struct Write<T: ?Sized + 'static, S: AnyStorage = UnsyncStorage> {
|
pub struct Write<'a, T: ?Sized + 'static, S: AnyStorage = UnsyncStorage> {
|
||||||
write: S::Mut<T>,
|
write: S::Mut<'a, T>,
|
||||||
drop_signal: Box<dyn Any>,
|
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.
|
/// 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 {
|
let Self {
|
||||||
write, drop_signal, ..
|
write, drop_signal, ..
|
||||||
} = myself;
|
} = myself;
|
||||||
@@ -294,16 +305,29 @@ impl<T: ?Sized + 'static, S: AnyStorage> Write<T, S> {
|
|||||||
pub fn filter_map<O: ?Sized>(
|
pub fn filter_map<O: ?Sized>(
|
||||||
myself: Self,
|
myself: Self,
|
||||||
f: impl FnOnce(&mut T) -> Option<&mut O>,
|
f: impl FnOnce(&mut T) -> Option<&mut O>,
|
||||||
) -> Option<Write<O, S>> {
|
) -> Option<Write<'a, O, S>> {
|
||||||
let Self {
|
let Self {
|
||||||
write, drop_signal, ..
|
write, drop_signal, ..
|
||||||
} = myself;
|
} = myself;
|
||||||
let write = S::try_map_mut(write, f);
|
let write = S::try_map_mut(write, f);
|
||||||
write.map(|write| Write { write, drop_signal })
|
write.map(|write| Write { write, drop_signal })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Downcast the lifetime of the mutable reference to the signal's value.
|
||||||
|
///
|
||||||
|
/// This function enforces the variance of the lifetime parameter `'a` in Mut. Rust will typically infer this cast with a concrete type, but it cannot with a generic type.
|
||||||
|
pub fn downcast_lifetime<'b>(mut_: Self) -> Write<'b, T, S>
|
||||||
|
where
|
||||||
|
'a: 'b,
|
||||||
|
{
|
||||||
|
Write {
|
||||||
|
write: S::downcast_lifetime_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;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@@ -311,7 +335,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 {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.write
|
&mut self.write
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,60 @@
|
|||||||
use std::ops::DerefMut;
|
use std::ops::{DerefMut, IndexMut};
|
||||||
use std::ops::IndexMut;
|
|
||||||
|
|
||||||
use crate::read::Readable;
|
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.
|
/// 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 {
|
pub trait Writable: Readable {
|
||||||
/// The type of the reference.
|
/// 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.
|
/// Map the reference to a new type.
|
||||||
fn map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> &mut U>(
|
fn map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> &mut U>(
|
||||||
ref_: Self::Mut<I>,
|
ref_: Self::Mut<'_, I>,
|
||||||
f: F,
|
f: F,
|
||||||
) -> Self::Mut<U>;
|
) -> Self::Mut<'_, U>;
|
||||||
|
|
||||||
/// Try to map the reference to a new type.
|
/// Try to map the reference to a new type.
|
||||||
fn try_map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> Option<&mut U>>(
|
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,
|
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_lifetime_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.
|
/// Get a mutable reference to the value. If the value has been dropped, this will panic.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn write(&mut self) -> Self::Mut<Self::Target> {
|
fn write(&mut self) -> WritableRef<'_, Self> {
|
||||||
self.try_write().unwrap()
|
self.try_write().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to get a mutable reference to the value. If the value has been dropped, this will panic.
|
/// Try to get a mutable reference to the value.
|
||||||
fn try_write(&mut self) -> Result<Self::Mut<Self::Target>, generational_box::BorrowMutError>;
|
#[track_caller]
|
||||||
|
fn try_write(&mut self) -> Result<WritableRef<'_, Self>, generational_box::BorrowMutError> {
|
||||||
|
self.try_write_unchecked().map(Self::downcast_lifetime_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.
|
/// Run a function with a mutable reference to the value. If the value has been dropped, this will panic.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
@@ -55,7 +82,10 @@ pub trait Writable: Readable {
|
|||||||
|
|
||||||
/// Index into the inner value and return a reference to the result.
|
/// Index into the inner value and return a reference to the result.
|
||||||
#[track_caller]
|
#[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
|
where
|
||||||
Self::Target: std::ops::IndexMut<I>,
|
Self::Target: std::ops::IndexMut<I>,
|
||||||
{
|
{
|
||||||
@@ -84,15 +114,14 @@ pub trait Writable: Readable {
|
|||||||
/// An extension trait for Writable<Option<T>> that provides some convenience methods.
|
/// An extension trait for Writable<Option<T>> that provides some convenience methods.
|
||||||
pub trait WritableOptionExt<T: 'static>: Writable<Target = Option<T>> {
|
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.
|
/// 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)
|
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.
|
||||||
fn get_or_insert_with(&mut self, default: impl FnOnce() -> T) -> Self::Mut<T> {
|
fn get_or_insert_with(&mut self, default: impl FnOnce() -> T) -> WritableRef<'_, Self, T> {
|
||||||
let borrow = self.read();
|
let is_none = self.read().is_none();
|
||||||
if borrow.is_none() {
|
if is_none {
|
||||||
drop(borrow);
|
|
||||||
self.with_mut(|v| *v = Some(default()));
|
self.with_mut(|v| *v = Some(default()));
|
||||||
Self::map_mut(self.write(), |v| v.as_mut().unwrap())
|
Self::map_mut(self.write(), |v| v.as_mut().unwrap())
|
||||||
} else {
|
} else {
|
||||||
@@ -102,7 +131,7 @@ pub trait WritableOptionExt<T: 'static>: Writable<Target = Option<T>> {
|
|||||||
|
|
||||||
/// Attempts to write the inner value of the Option.
|
/// Attempts to write the inner value of the Option.
|
||||||
#[track_caller]
|
#[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())
|
Self::try_map_mut(self.write(), |v: &mut Option<T>| v.as_mut())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,36 +207,40 @@ pub trait WritableVecExt<T: 'static>: Writable<Target = Vec<T>> {
|
|||||||
|
|
||||||
/// Try to mutably get an element from the vector.
|
/// Try to mutably get an element from the vector.
|
||||||
#[track_caller]
|
#[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))
|
Self::try_map_mut(self.write(), |v: &mut Vec<T>| v.get_mut(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an iterator over the values of the vector.
|
/// Gets an iterator over the values of the vector.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn iter_mut(&self) -> WritableValueIterator<Self>
|
fn iter_mut(&mut self) -> WritableValueIterator<'_, Self>
|
||||||
where
|
where
|
||||||
Self: Sized + Clone,
|
Self: Sized + Clone,
|
||||||
{
|
{
|
||||||
WritableValueIterator {
|
WritableValueIterator {
|
||||||
index: 0,
|
index: 0,
|
||||||
value: self.clone(),
|
value: self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator over the values of a `Writable<Vec<T>>`.
|
/// An iterator over the values of a `Writable<Vec<T>>`.
|
||||||
pub struct WritableValueIterator<R> {
|
pub struct WritableValueIterator<'a, R> {
|
||||||
index: usize,
|
index: usize,
|
||||||
value: R,
|
value: &'a mut R,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static, R: Writable<Target = Vec<T>>> Iterator for WritableValueIterator<R> {
|
impl<'a, T: 'static, R: Writable<Target = Vec<T>>> Iterator for WritableValueIterator<'a, R> {
|
||||||
type Item = R::Mut<T>;
|
type Item = WritableRef<'a, R, T>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let index = self.index;
|
let index = self.index;
|
||||||
self.index += 1;
|
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_lifetime_mut)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user