* Fix #2612: adjust readable trait to allow try_peek Our implementation for Readable was inconsistent. We had a try_unchecked variant for read but not for peek. This resolves that by making a breaking change to the Readable interface. * fix doctests too
This commit is contained in:
1 parent
443b9a4af6
commit
e42b71b1ba
13 files changed
+102
-58
No files matched your search
Generated
+1
-1
@@ -10382,7 +10382,7 @@ source = "git+https://github.com/DioxusLabs/warnings#9889b96cccb6ac91a8af924cfee
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -4,6 +4,9 @@ use std::fmt::Display;
|
||||
|
||||
use crate::GenerationalLocation;
|
||||
|
||||
/// A result that can be returned from a borrow operation.
|
||||
pub type BorrowResult<T> = std::result::Result<T, BorrowError>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
/// An error that can occur when trying to borrow a value.
|
||||
pub enum BorrowError {
|
||||
|
||||
@@ -175,8 +175,10 @@ impl Readable for UseFuture {
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
self.state.peek_unchecked()
|
||||
fn try_peek_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
self.state.try_peek_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -441,8 +441,10 @@ impl<T> Readable for Resource<T> {
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
self.value.peek_unchecked()
|
||||
fn try_peek_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
self.value.try_peek_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use generational_box::GenerationalBoxId;
|
||||
use generational_box::UnsyncStorage;
|
||||
use generational_box::{BorrowResult, GenerationalBoxId};
|
||||
use std::ops::Deref;
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
@@ -129,8 +129,8 @@ impl<T: 'static, S: Storage<T>> Readable for CopyValue<T, S> {
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
self.value.read()
|
||||
fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||
self.value.try_read()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{read::Readable, Memo, ReadableRef};
|
||||
use crate::{read_impls, GlobalKey};
|
||||
use dioxus_core::prelude::ScopeId;
|
||||
use generational_box::UnsyncStorage;
|
||||
use generational_box::{BorrowResult, UnsyncStorage};
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::Signal;
|
||||
@@ -75,8 +75,8 @@ impl<T: PartialEq + 'static> Readable for GlobalMemo<T> {
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
self.memo().peek_unchecked()
|
||||
fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||
self.memo().try_peek_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::{read::Readable, ReadableRef};
|
||||
use crate::{write::Writable, GlobalKey};
|
||||
use crate::{WritableRef, Write};
|
||||
use dioxus_core::{prelude::ScopeId, Runtime};
|
||||
use generational_box::UnsyncStorage;
|
||||
use generational_box::{BorrowResult, UnsyncStorage};
|
||||
use std::ops::Deref;
|
||||
|
||||
use super::get_global_context;
|
||||
@@ -110,8 +110,8 @@ impl<T: 'static> Readable for GlobalSignal<T> {
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
self.signal().peek_unchecked()
|
||||
fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||
self.signal().try_peek_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,10 @@
|
||||
/// self.value.try_read_unchecked()
|
||||
/// }
|
||||
///
|
||||
/// fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
/// self.value.read_unchecked()
|
||||
/// fn try_peek_unchecked(
|
||||
/// &self,
|
||||
/// ) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
/// self.value.try_read_unchecked()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
@@ -85,8 +87,10 @@ macro_rules! default_impl {
|
||||
/// self.value.try_read_unchecked()
|
||||
/// }
|
||||
///
|
||||
/// fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
/// self.value.read_unchecked()
|
||||
/// fn try_peek_unchecked(
|
||||
/// &self,
|
||||
/// ) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
/// self.value.try_read_unchecked()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
@@ -156,8 +160,10 @@ macro_rules! read_impls {
|
||||
/// self.value.try_read_unchecked()
|
||||
/// }
|
||||
///
|
||||
/// fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
/// self.value.read_unchecked()
|
||||
/// fn try_peek_unchecked(
|
||||
/// &self,
|
||||
/// ) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
/// self.value.try_read_unchecked()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
@@ -230,8 +236,10 @@ macro_rules! fmt_impls {
|
||||
/// self.value.try_read_unchecked()
|
||||
/// }
|
||||
///
|
||||
/// fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
/// self.value.read_unchecked()
|
||||
/// fn try_peek_unchecked(
|
||||
/// &self,
|
||||
/// ) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
/// self.value.try_read_unchecked()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
|
||||
@@ -2,19 +2,19 @@ use std::{ops::Deref, rc::Rc};
|
||||
|
||||
use crate::{read::Readable, read_impls, ReadableRef};
|
||||
use dioxus_core::prelude::*;
|
||||
use generational_box::{AnyStorage, UnsyncStorage};
|
||||
use generational_box::{AnyStorage, BorrowResult, 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<'static, O>, generational_box::BorrowError> + 'static>,
|
||||
peek: Rc<dyn Fn() -> S::Ref<'static, O> + 'static>,
|
||||
try_peek: Rc<dyn Fn() -> Result<S::Ref<'static, O>, generational_box::BorrowError> + 'static>,
|
||||
}
|
||||
|
||||
impl<O: ?Sized, S: AnyStorage> Clone for MappedSignal<O, S> {
|
||||
fn clone(&self) -> Self {
|
||||
MappedSignal {
|
||||
try_read: self.try_read.clone(),
|
||||
peek: self.peek.clone(),
|
||||
try_peek: self.try_peek.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,9 +29,11 @@ where
|
||||
try_read: Rc<
|
||||
dyn Fn() -> Result<S::Ref<'static, O>, generational_box::BorrowError> + 'static,
|
||||
>,
|
||||
peek: Rc<dyn Fn() -> S::Ref<'static, O> + 'static>,
|
||||
try_peek: Rc<
|
||||
dyn Fn() -> Result<S::Ref<'static, O>, generational_box::BorrowError> + 'static,
|
||||
>,
|
||||
) -> Self {
|
||||
MappedSignal { try_read, peek }
|
||||
MappedSignal { try_read, try_peek }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +51,8 @@ where
|
||||
(self.try_read)()
|
||||
}
|
||||
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
(self.peek)()
|
||||
fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||
(self.try_peek)()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +72,8 @@ where
|
||||
S: AnyStorage,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
std::ptr::eq(&self.peek, &other.peek) && std::ptr::eq(&self.try_read, &other.try_read)
|
||||
std::ptr::eq(&self.try_peek, &other.try_peek)
|
||||
&& std::ptr::eq(&self.try_read, &other.try_read)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use std::{
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
use futures_util::StreamExt;
|
||||
use generational_box::{AnyStorage, UnsyncStorage};
|
||||
use generational_box::{AnyStorage, BorrowResult, UnsyncStorage};
|
||||
|
||||
struct UpdateInformation<T> {
|
||||
dirty: Arc<AtomicBool>,
|
||||
@@ -164,8 +164,8 @@ where
|
||||
///
|
||||
/// If the signal has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
self.inner.peek_unchecked()
|
||||
fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||
self.inner.try_peek_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,10 +83,20 @@ pub trait Readable {
|
||||
dyn Fn() -> Result<ReadableRef<'static, Self, O>, generational_box::BorrowError>
|
||||
+ '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)
|
||||
let try_peek = Rc::new({
|
||||
let self_ = self.clone();
|
||||
let mapping = mapping.clone();
|
||||
move || {
|
||||
self_
|
||||
.try_peek_unchecked()
|
||||
.map(|ref_| <Self::Storage as AnyStorage>::map(ref_, |r| mapping(r)))
|
||||
}
|
||||
})
|
||||
as Rc<
|
||||
dyn Fn() -> Result<ReadableRef<'static, Self, O>, generational_box::BorrowError>
|
||||
+ 'static,
|
||||
>;
|
||||
MappedSignal::new(try_read, try_peek)
|
||||
}
|
||||
|
||||
/// Get the current value of the state. If this is a signal, this will subscribe the current scope to the signal.
|
||||
@@ -104,13 +114,6 @@ pub trait Readable {
|
||||
.map(Self::Storage::downcast_lifetime_ref)
|
||||
}
|
||||
|
||||
/// Try to get a reference to the value without checking the lifetime. This will subscribe the current scope to the signal.
|
||||
///
|
||||
/// 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>;
|
||||
|
||||
/// Get a reference to the value without checking the lifetime. This will subscribe the current scope to the signal.
|
||||
///
|
||||
/// NOTE: This method is completely safe because borrow checking is done at runtime.
|
||||
@@ -119,12 +122,12 @@ pub trait Readable {
|
||||
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.
|
||||
/// Try to get a reference to the value without checking the lifetime. This will subscribe the current scope to the signal.
|
||||
///
|
||||
/// NOTE: This method is completely safe because borrow checking is done at runtime.
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self>;
|
||||
fn try_read_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError>;
|
||||
|
||||
/// Get the current value of the state without subscribing to updates. If the value has been dropped, this will panic.
|
||||
///
|
||||
@@ -164,6 +167,30 @@ pub trait Readable {
|
||||
Self::Storage::downcast_lifetime_ref(self.peek_unchecked())
|
||||
}
|
||||
|
||||
/// Try to peek the current value of the signal without subscribing to updates. If the value has
|
||||
/// been dropped, this will return an error.
|
||||
#[track_caller]
|
||||
fn try_peek(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
|
||||
self.try_peek_unchecked()
|
||||
.map(Self::Storage::downcast_lifetime_ref)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[track_caller]
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
self.try_peek_unchecked().unwrap()
|
||||
}
|
||||
|
||||
/// Try to peek the current value of the signal without subscribing to updates. If the value has
|
||||
/// been dropped, this will return an error.
|
||||
///
|
||||
/// NOTE: This method is completely safe because borrow checking is done at runtime.
|
||||
fn try_peek_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError>;
|
||||
|
||||
/// Clone the inner value and return it. If the value has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
fn cloned(&self) -> Self::Target
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::ops::Deref;
|
||||
|
||||
use crate::{default_impl, read_impls};
|
||||
use dioxus_core::{prelude::IntoAttributeValue, ScopeId};
|
||||
use generational_box::{Storage, UnsyncStorage};
|
||||
use generational_box::{BorrowResult, Storage, UnsyncStorage};
|
||||
|
||||
/// A signal that can only be read from.
|
||||
pub struct ReadOnlySignal<T: 'static, S: Storage<SignalData<T>> = UnsyncStorage> {
|
||||
@@ -79,8 +79,8 @@ impl<T, S: Storage<SignalData<T>>> Readable for ReadOnlySignal<T, S> {
|
||||
///
|
||||
/// If the signal has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
fn peek_unchecked(&self) -> S::Ref<'static, T> {
|
||||
self.inner.peek_unchecked()
|
||||
fn try_peek_unchecked(&self) -> BorrowResult<S::Ref<'static, T>> {
|
||||
self.inner.try_peek_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::{default_impl, fmt_impls, write_impls};
|
||||
use crate::{read::*, write::*, CopyValue, GlobalMemo, GlobalSignal, ReadableRef};
|
||||
use crate::{Memo, WritableRef};
|
||||
use dioxus_core::prelude::*;
|
||||
use generational_box::{AnyStorage, Storage, SyncStorage, UnsyncStorage};
|
||||
use generational_box::{AnyStorage, BorrowResult, Storage, SyncStorage, UnsyncStorage};
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
any::Any,
|
||||
@@ -349,9 +349,7 @@ impl<T, S: Storage<SignalData<T>>> Readable for Signal<T, S> {
|
||||
type Storage = S;
|
||||
|
||||
#[track_caller]
|
||||
fn try_read_unchecked(
|
||||
&self,
|
||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
||||
fn try_read_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||
let inner = self.inner.try_read_unchecked()?;
|
||||
|
||||
if let Some(reactive_context) = ReactiveContext::current() {
|
||||
@@ -366,9 +364,10 @@ impl<T, S: Storage<SignalData<T>>> Readable for Signal<T, S> {
|
||||
///
|
||||
/// If the signal has been dropped, this will panic.
|
||||
#[track_caller]
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
||||
let inner = self.inner.try_read_unchecked().unwrap();
|
||||
S::map(inner, |v| &v.value)
|
||||
fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||
self.inner
|
||||
.try_read_unchecked()
|
||||
.map(|inner| S::map(inner, |v| &v.value))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user