restore lifetime checking for signals

This commit is contained in:
Evan Almloff committed 2024-03-08 10:32:57 -06:00
1 parent 295c29db5d
commit 60a84956d1
16 files changed
+275 -148

No files matched your search

+38 -9
View File
@@ -6,7 +6,8 @@ use crate::MappedSignal;
/// A reference to a value that can be read from.
#[allow(type_alias_bounds)]
pub type ReadableRef<T: Readable, O = <T as Readable>::Target> = <T::Storage as AnyStorage>::Ref<O>;
pub type ReadableRef<'a, T: Readable, O = <T as Readable>::Target> =
<T::Storage as AnyStorage>::Ref<'a, O>;
/// A trait for states that can be read from like [`crate::Signal`], [`crate::GlobalSignal`], or [`crate::ReadOnlySignal`]. You may choose to accept this trait as a parameter instead of the concrete type to allow for more flexibility in your API. For example, instead of creating two functions, one that accepts a [`crate::Signal`] and one that accepts a [`crate::GlobalSignal`], you can create one function that accepts a [`Readable`] type.
pub trait Readable {
@@ -27,15 +28,17 @@ pub trait Readable {
let mapping = mapping.clone();
move || {
self_
.try_read()
.try_read_unchecked()
.map(|ref_| <Self::Storage as AnyStorage>::map(ref_, |r| mapping(r)))
}
})
as Rc<
dyn Fn() -> Result<ReadableRef<Self, O>, generational_box::BorrowError> + 'static,
dyn Fn() -> Result<ReadableRef<'static, Self, O>, generational_box::BorrowError>
+ 'static,
>;
let peek = Rc::new(move || <Self::Storage as AnyStorage>::map(self.peek(), |r| mapping(r)))
as Rc<dyn Fn() -> ReadableRef<Self, O> + 'static>;
let peek = Rc::new(move || {
<Self::Storage as AnyStorage>::map(self.peek_unchecked(), |r| mapping(r))
}) as Rc<dyn Fn() -> ReadableRef<'static, Self, O> + 'static>;
MappedSignal::new(try_read, peek)
}
@@ -47,12 +50,38 @@ pub trait Readable {
self.try_read().unwrap()
}
/// Try to get the current value of the state. If this is a signal, this will subscribe the current scope to the signal. If the value has been dropped, this will panic.
/// Try to get the current value of the state. If this is a signal, this will subscribe the current scope to the signal.
#[track_caller]
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError>;
fn try_read(&self) -> Result<ReadableRef<Self>, generational_box::BorrowError> {
self.try_read_unchecked().map(Self::Storage::downcast_ref)
}
/// Try to get a reference to the value without checking the lifetime.
///
/// NOTE: This method is completely safe because borrow checking is done at runtime.
fn try_read_unchecked(
&self,
) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError>;
/// Tet a reference to the value without checking the lifetime.
///
/// NOTE: This method is completely safe because borrow checking is done at runtime.
fn read_unchecked(&self) -> ReadableRef<'static, Self> {
self.try_read_unchecked().unwrap()
}
/// Get the current value of the signal without checking the lifetime. **Unlike read, this will not subscribe the current scope to the signal which can cause parts of your UI to not update.**
///
/// If the signal has been dropped, this will panic.
///
/// NOTE: This method is completely safe because borrow checking is done at runtime.
fn peek_unchecked(&self) -> ReadableRef<'static, Self>;
/// Get the current value of the state without subscribing to updates. If the value has been dropped, this will panic.
fn peek(&self) -> ReadableRef<Self>;
#[track_caller]
fn peek(&self) -> ReadableRef<Self> {
Self::Storage::downcast_ref(self.peek_unchecked())
}
/// Clone the inner value and return it. If the value has been dropped, this will panic.
#[track_caller]
@@ -171,7 +200,7 @@ pub struct ReadableValueIterator<'a, R> {
}
impl<'a, T: 'static, R: Readable<Target = Vec<T>>> Iterator for ReadableValueIterator<'a, R> {
type Item = ReadableRef<R, T>;
type Item = ReadableRef<'a, R, T>;
fn next(&mut self) -> Option<Self::Item> {
let index = self.index;