* 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 = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.71",
|
"syn 2.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ use std::fmt::Display;
|
|||||||
|
|
||||||
use crate::GenerationalLocation;
|
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)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
/// An error that can occur when trying to borrow a value.
|
/// An error that can occur when trying to borrow a value.
|
||||||
pub enum BorrowError {
|
pub enum BorrowError {
|
||||||
|
|||||||
@@ -175,8 +175,10 @@ impl Readable for UseFuture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
fn try_peek_unchecked(
|
||||||
self.state.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]
|
#[track_caller]
|
||||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
fn try_peek_unchecked(
|
||||||
self.value.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::UnsyncStorage;
|
||||||
|
use generational_box::{BorrowResult, GenerationalBoxId};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use dioxus_core::prelude::*;
|
use dioxus_core::prelude::*;
|
||||||
@@ -129,8 +129,8 @@ impl<T: 'static, S: Storage<T>> Readable for CopyValue<T, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||||
self.value.read()
|
self.value.try_read()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::{read::Readable, Memo, ReadableRef};
|
use crate::{read::Readable, Memo, ReadableRef};
|
||||||
use crate::{read_impls, GlobalKey};
|
use crate::{read_impls, GlobalKey};
|
||||||
use dioxus_core::prelude::ScopeId;
|
use dioxus_core::prelude::ScopeId;
|
||||||
use generational_box::UnsyncStorage;
|
use generational_box::{BorrowResult, UnsyncStorage};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use crate::Signal;
|
use crate::Signal;
|
||||||
@@ -75,8 +75,8 @@ impl<T: PartialEq + 'static> Readable for GlobalMemo<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||||
self.memo().peek_unchecked()
|
self.memo().try_peek_unchecked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::{read::Readable, ReadableRef};
|
|||||||
use crate::{write::Writable, GlobalKey};
|
use crate::{write::Writable, GlobalKey};
|
||||||
use crate::{WritableRef, Write};
|
use crate::{WritableRef, Write};
|
||||||
use dioxus_core::{prelude::ScopeId, Runtime};
|
use dioxus_core::{prelude::ScopeId, Runtime};
|
||||||
use generational_box::UnsyncStorage;
|
use generational_box::{BorrowResult, UnsyncStorage};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use super::get_global_context;
|
use super::get_global_context;
|
||||||
@@ -110,8 +110,8 @@ impl<T: 'static> Readable for GlobalSignal<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||||
self.signal().peek_unchecked()
|
self.signal().try_peek_unchecked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,10 @@
|
|||||||
/// self.value.try_read_unchecked()
|
/// self.value.try_read_unchecked()
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
/// fn try_peek_unchecked(
|
||||||
/// self.value.read_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()
|
/// self.value.try_read_unchecked()
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
/// fn try_peek_unchecked(
|
||||||
/// self.value.read_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()
|
/// self.value.try_read_unchecked()
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
/// fn try_peek_unchecked(
|
||||||
/// self.value.read_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()
|
/// self.value.try_read_unchecked()
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
/// fn try_peek_unchecked(
|
||||||
/// self.value.read_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 crate::{read::Readable, read_impls, ReadableRef};
|
||||||
use dioxus_core::prelude::*;
|
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.
|
/// 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<'static, 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<'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> {
|
impl<O: ?Sized, S: AnyStorage> Clone for MappedSignal<O, S> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
MappedSignal {
|
MappedSignal {
|
||||||
try_read: self.try_read.clone(),
|
try_read: self.try_read.clone(),
|
||||||
peek: self.peek.clone(),
|
try_peek: self.try_peek.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,9 +29,11 @@ where
|
|||||||
try_read: Rc<
|
try_read: Rc<
|
||||||
dyn Fn() -> Result<S::Ref<'static, O>, generational_box::BorrowError> + 'static,
|
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 {
|
) -> Self {
|
||||||
MappedSignal { try_read, peek }
|
MappedSignal { try_read, try_peek }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,8 +51,8 @@ where
|
|||||||
(self.try_read)()
|
(self.try_read)()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||||
(self.peek)()
|
(self.try_peek)()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +72,8 @@ where
|
|||||||
S: AnyStorage,
|
S: AnyStorage,
|
||||||
{
|
{
|
||||||
fn eq(&self, other: &Self) -> bool {
|
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 dioxus_core::prelude::*;
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use generational_box::{AnyStorage, UnsyncStorage};
|
use generational_box::{AnyStorage, BorrowResult, UnsyncStorage};
|
||||||
|
|
||||||
struct UpdateInformation<T> {
|
struct UpdateInformation<T> {
|
||||||
dirty: Arc<AtomicBool>,
|
dirty: Arc<AtomicBool>,
|
||||||
@@ -164,8 +164,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_unchecked(&self) -> ReadableRef<'static, Self> {
|
fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||||
self.inner.peek_unchecked()
|
self.inner.try_peek_unchecked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,10 +83,20 @@ pub trait Readable {
|
|||||||
dyn Fn() -> Result<ReadableRef<'static, Self, O>, generational_box::BorrowError>
|
dyn Fn() -> Result<ReadableRef<'static, Self, O>, generational_box::BorrowError>
|
||||||
+ 'static,
|
+ 'static,
|
||||||
>;
|
>;
|
||||||
let peek = Rc::new(move || {
|
let try_peek = Rc::new({
|
||||||
<Self::Storage as AnyStorage>::map(self.peek_unchecked(), |r| mapping(r))
|
let self_ = self.clone();
|
||||||
}) as Rc<dyn Fn() -> ReadableRef<'static, Self, O> + 'static>;
|
let mapping = mapping.clone();
|
||||||
MappedSignal::new(try_read, peek)
|
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.
|
/// 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)
|
.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.
|
/// 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.
|
/// 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()
|
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.**
|
/// Try to get a reference to the value without checking the lifetime. This will subscribe the current scope to the signal.
|
||||||
///
|
|
||||||
/// If the signal has been dropped, this will panic.
|
|
||||||
///
|
///
|
||||||
/// NOTE: This method is completely safe because borrow checking is done at runtime.
|
/// 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.
|
/// 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())
|
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.
|
/// Clone the inner value and return it. If the value has been dropped, this will panic.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cloned(&self) -> Self::Target
|
fn cloned(&self) -> Self::Target
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::ops::Deref;
|
|||||||
|
|
||||||
use crate::{default_impl, read_impls};
|
use crate::{default_impl, read_impls};
|
||||||
use dioxus_core::{prelude::IntoAttributeValue, ScopeId};
|
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.
|
/// A signal that can only be read from.
|
||||||
pub struct ReadOnlySignal<T: 'static, S: Storage<SignalData<T>> = UnsyncStorage> {
|
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.
|
/// If the signal has been dropped, this will panic.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn peek_unchecked(&self) -> S::Ref<'static, T> {
|
fn try_peek_unchecked(&self) -> BorrowResult<S::Ref<'static, T>> {
|
||||||
self.inner.peek_unchecked()
|
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::{read::*, write::*, CopyValue, GlobalMemo, GlobalSignal, ReadableRef};
|
||||||
use crate::{Memo, WritableRef};
|
use crate::{Memo, WritableRef};
|
||||||
use dioxus_core::prelude::*;
|
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::sync::Arc;
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
@@ -349,9 +349,7 @@ impl<T, S: Storage<SignalData<T>>> Readable for Signal<T, S> {
|
|||||||
type Storage = S;
|
type Storage = S;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn try_read_unchecked(
|
fn try_read_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||||
&self,
|
|
||||||
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
|
|
||||||
let inner = self.inner.try_read_unchecked()?;
|
let inner = self.inner.try_read_unchecked()?;
|
||||||
|
|
||||||
if let Some(reactive_context) = ReactiveContext::current() {
|
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.
|
/// If the signal has been dropped, this will panic.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self> {
|
fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
|
||||||
let inner = self.inner.try_read_unchecked().unwrap();
|
self.inner
|
||||||
S::map(inner, |v| &v.value)
|
.try_read_unchecked()
|
||||||
|
.map(|inner| S::map(inner, |v| &v.value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user