Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore signal lifetimes; rename take to manually drop #2022

Merged
merged 4 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/dog_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ fn BreedPic(breed: Signal<String>) -> Element {
.await
});

match fut.read().as_ref() {
match fut.read_unchecked().as_ref() {
Some(Ok(resp)) => rsx! {
button { onclick: move |_| fut.restart(), "Click to fetch another doggo" }
img { max_width: "500px", max_height: "500px", src: "{resp.message}" }
Expand Down
2 changes: 1 addition & 1 deletion examples/suspense.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ fn Doggo() -> Element {
.await
});

match fut.read().as_ref() {
match fut.read_unchecked().as_ref() {
Some(Ok(resp)) => rsx! {
button { onclick: move |_| fut.restart(), "Click to fetch another doggo" }
div { img { max_width: "500px", max_height: "500px", src: "{resp.message}" } }
Expand Down
3 changes: 1 addition & 2 deletions packages/desktop/headless_tests/rendering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,13 @@ fn use_inner_html(id: &'static str) -> Option<String> {
.unwrap();

if let Some(html) = res.as_str() {
// serde_json::Value::String(html)
println!("html: {}", html);
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>"#;
Expand Down
54 changes: 34 additions & 20 deletions packages/generational-box/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {

/// Try to read the value. Returns None if the value is no longer valid.
#[track_caller]
pub fn try_read(&self) -> Result<S::Ref<T>, BorrowError> {
pub fn try_read(&self) -> Result<S::Ref<'static, T>, BorrowError> {
if !self.validate() {
return Err(BorrowError::Dropped(ValueDroppedError {
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
Expand Down Expand Up @@ -129,13 +129,13 @@ impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {

/// Read the value. Panics if the value is no longer valid.
#[track_caller]
pub fn read(&self) -> S::Ref<T> {
pub fn read(&self) -> S::Ref<'static, T> {
self.try_read().unwrap()
}

/// Try to write the value. Returns None if the value is no longer valid.
#[track_caller]
pub fn try_write(&self) -> Result<S::Mut<T>, BorrowMutError> {
pub fn try_write(&self) -> Result<S::Mut<'static, T>, BorrowMutError> {
if !self.validate() {
return Err(BorrowMutError::Dropped(ValueDroppedError {
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
Expand All @@ -162,7 +162,7 @@ impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {

/// Write the value. Panics if the value is no longer valid.
#[track_caller]
pub fn write(&self) -> S::Mut<T> {
pub fn write(&self) -> S::Mut<'static, T> {
self.try_write().unwrap()
}

Expand All @@ -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.
pub fn take(&self) -> Option<T> {
/// 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 manually_drop(&self) -> Option<T> {
if self.validate() {
Storage::take(&self.raw.0.data)
} else {
Expand All @@ -210,13 +210,13 @@ pub trait Storage<Data = ()>: AnyStorage + 'static {
fn try_read(
&'static self,
#[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefBorrowInfo,
) -> Result<Self::Ref<Data>, BorrowError>;
) -> Result<Self::Ref<'static, Data>, BorrowError>;

/// Try to write the value. Returns None if the value is no longer valid.
fn try_write(
&'static self,
#[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefMutBorrowInfo,
) -> Result<Self::Mut<Data>, BorrowMutError>;
) -> Result<Self::Mut<'static, Data>, BorrowMutError>;

/// Set the value
fn set(&'static self, value: Data);
Expand All @@ -228,35 +228,49 @@ pub trait Storage<Data = ()>: AnyStorage + 'static {
/// A trait for any storage backing type.
pub trait AnyStorage: Default {
/// The reference this storage type returns.
type Ref<T: ?Sized + 'static>: Deref<Target = T> + 'static;
type Ref<'a, T: ?Sized + 'static>: Deref<Target = T>;
/// The mutable reference this storage type returns.
type Mut<T: ?Sized + 'static>: DerefMut<Target = T> + 'static;
type Mut<'a, T: ?Sized + 'static>: DerefMut<Target = T>;

/// Downcast a reference in a Ref to a more specific lifetime
///
/// This function enforces the variance of the lifetime parameter `'a` in Ref. 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.
fn try_map_mut<T: ?Sized, U: ?Sized + 'static>(
mut_ref: Self::Mut<T>,
fn try_map_mut<T: ?Sized + 'static, U: ?Sized + 'static>(
mut_ref: Self::Mut<'_, T>,
f: impl FnOnce(&mut T) -> Option<&mut U>,
) -> Option<Self::Mut<U>>;
) -> Option<Self::Mut<'_, U>>;

/// Map the mutable ref.
fn map_mut<T: ?Sized, U: ?Sized + 'static>(
mut_ref: Self::Mut<T>,
fn map_mut<T: ?Sized + 'static, U: ?Sized + 'static>(
mut_ref: Self::Mut<'_, T>,
f: impl FnOnce(&mut T) -> &mut U,
) -> Self::Mut<U> {
) -> Self::Mut<'_, U> {
Self::try_map_mut(mut_ref, |v| Some(f(v))).unwrap()
}

/// Try to map the ref.
fn try_map<T: ?Sized, U: ?Sized + 'static>(
ref_: Self::Ref<T>,
ref_: Self::Ref<'_, T>,
f: impl FnOnce(&T) -> Option<&U>,
) -> Option<Self::Ref<U>>;
) -> Option<Self::Ref<'_, U>>;

/// Map the ref.
fn map<T: ?Sized, U: ?Sized + 'static>(
ref_: Self::Ref<T>,
ref_: Self::Ref<'_, T>,
f: impl FnOnce(&T) -> &U,
) -> Self::Ref<U> {
) -> Self::Ref<'_, U> {
Self::try_map(ref_, |v| Some(f(v))).unwrap()
}

Expand Down
32 changes: 22 additions & 10 deletions packages/generational-box/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,25 @@ fn sync_runtime() -> &'static Arc<Mutex<Vec<MemoryLocation<SyncStorage>>>> {
}

impl AnyStorage for SyncStorage {
type Ref<R: ?Sized + 'static> = GenerationalRef<MappedRwLockReadGuard<'static, R>>;
type Mut<W: ?Sized + 'static> = GenerationalRefMut<MappedRwLockWriteGuard<'static, W>>;
type Ref<'a, R: ?Sized + 'static> = GenerationalRef<MappedRwLockReadGuard<'a, R>>;
type Mut<'a, W: ?Sized + 'static> = GenerationalRefMut<MappedRwLockWriteGuard<'a, W>>;

fn try_map<I: ?Sized, U: ?Sized + 'static>(
ref_: Self::Ref<I>,
fn downcast_lifetime_ref<'a: 'b, 'b, T: ?Sized + 'static>(
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>,
) -> Option<Self::Ref<U>> {
) -> Option<Self::Ref<'_, U>> {
let GenerationalRef {
inner,
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
Expand All @@ -46,10 +58,10 @@ impl AnyStorage for SyncStorage {
})
}

fn try_map_mut<I: ?Sized, U: ?Sized + 'static>(
mut_ref: Self::Mut<I>,
fn try_map_mut<I: ?Sized + 'static, U: ?Sized + 'static>(
mut_ref: Self::Mut<'_, I>,
f: impl FnOnce(&mut I) -> Option<&mut U>,
) -> Option<Self::Mut<U>> {
) -> Option<Self::Mut<'_, U>> {
let GenerationalRefMut {
inner,
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
Expand Down Expand Up @@ -101,7 +113,7 @@ impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
&'static self,
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
at: crate::GenerationalRefBorrowInfo,
) -> Result<Self::Ref<T>, error::BorrowError> {
) -> Result<Self::Ref<'static, T>, error::BorrowError> {
let read = self.0.try_read();

#[cfg(any(debug_assertions, feature = "debug_ownership"))]
Expand Down Expand Up @@ -132,7 +144,7 @@ impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
&'static self,
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
at: crate::GenerationalRefMutBorrowInfo,
) -> Result<Self::Mut<T>, error::BorrowMutError> {
) -> Result<Self::Mut<'static, T>, error::BorrowMutError> {
let write = self.0.try_write();

#[cfg(any(debug_assertions, feature = "debug_ownership"))]
Expand Down
32 changes: 22 additions & 10 deletions packages/generational-box/src/unsync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ impl<T: 'static> Storage<T> for UnsyncStorage {

#[cfg(any(debug_assertions, feature = "debug_ownership"))]
at: crate::GenerationalRefBorrowInfo,
) -> Result<Self::Ref<T>, error::BorrowError> {
) -> Result<Self::Ref<'static, T>, error::BorrowError> {
let borrow = self.0.try_borrow();

#[cfg(any(debug_assertions, feature = "debug_ownership"))]
Expand Down Expand Up @@ -46,7 +46,7 @@ impl<T: 'static> Storage<T> for UnsyncStorage {
&'static self,
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
at: crate::GenerationalRefMutBorrowInfo,
) -> Result<Self::Mut<T>, error::BorrowMutError> {
) -> Result<Self::Mut<'static, T>, error::BorrowMutError> {
let borrow = self.0.try_borrow_mut();

#[cfg(any(debug_assertions, feature = "debug_ownership"))]
Expand Down Expand Up @@ -89,13 +89,25 @@ thread_local! {
}

impl AnyStorage for UnsyncStorage {
type Ref<R: ?Sized + 'static> = GenerationalRef<Ref<'static, R>>;
type Mut<W: ?Sized + 'static> = GenerationalRefMut<RefMut<'static, W>>;
type Ref<'a, R: ?Sized + 'static> = GenerationalRef<Ref<'a, R>>;
type Mut<'a, W: ?Sized + 'static> = GenerationalRefMut<RefMut<'a, W>>;

fn try_map<I: ?Sized, U: ?Sized + 'static>(
_self: Self::Ref<I>,
fn downcast_lifetime_ref<'a: 'b, 'b, T: ?Sized + 'static>(
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>,
) -> Option<Self::Ref<U>> {
) -> Option<Self::Ref<'_, U>> {
let GenerationalRef {
inner,
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
Expand All @@ -109,10 +121,10 @@ impl AnyStorage for UnsyncStorage {
})
}

fn try_map_mut<I: ?Sized, U: ?Sized + 'static>(
mut_ref: Self::Mut<I>,
fn try_map_mut<I: ?Sized + 'static, U: ?Sized + 'static>(
mut_ref: Self::Mut<'_, I>,
f: impl FnOnce(&mut I) -> Option<&mut U>,
) -> Option<Self::Mut<U>> {
) -> Option<Self::Mut<'_, U>> {
let GenerationalRefMut {
inner,
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
Expand Down
2 changes: 1 addition & 1 deletion packages/router/examples/simple_routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ fn Route3(dynamic: String) -> Element {
oninput: move |evt| {
*current_route_str.write() = evt.value();
},
value: "{current_route_str.read()}"
value: "{current_route_str}"
}
"dynamic: {dynamic}"
Link { to: Route::Route2 { user_id: 8888 }, "hello world link" }
Expand Down
16 changes: 8 additions & 8 deletions packages/router/src/contexts/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ impl RouterContext {
/// Will fail silently if there is no previous location to go to.
pub fn go_back(&self) {
{
self.inner.clone().write().history.go_back();
self.inner.write_unchecked().history.go_back();
}

self.change_route();
Expand All @@ -168,7 +168,7 @@ impl RouterContext {
/// Will fail silently if there is no next location to go to.
pub fn go_forward(&self) {
{
self.inner.clone().write().history.go_forward();
self.inner.write_unchecked().history.go_forward();
}

self.change_route();
Expand All @@ -179,7 +179,7 @@ impl RouterContext {
target: NavigationTarget<Rc<dyn Any>>,
) -> Option<ExternalNavigationFailure> {
{
let mut write = self.inner.clone().write();
let mut write = self.inner.write_unchecked();
match target {
NavigationTarget::Internal(p) => write.history.push(p),
NavigationTarget::External(e) => return write.external(e),
Expand All @@ -195,7 +195,7 @@ impl RouterContext {
pub fn push(&self, target: impl Into<IntoRoutable>) -> Option<ExternalNavigationFailure> {
let target = self.resolve_into_routable(target.into());
{
let mut write = self.inner.clone().write();
let mut write = self.inner.write_unchecked();
match target {
NavigationTarget::Internal(p) => write.history.push(p),
NavigationTarget::External(e) => return write.external(e),
Expand All @@ -212,7 +212,7 @@ impl RouterContext {
let target = self.resolve_into_routable(target.into());

{
let mut state = self.inner.clone().write();
let mut state = self.inner.write_unchecked();
match target {
NavigationTarget::Internal(p) => state.history.replace(p),
NavigationTarget::External(e) => return state.external(e),
Expand Down Expand Up @@ -276,14 +276,14 @@ impl RouterContext {

/// Clear any unresolved errors
pub fn clear_error(&self) {
let mut write_inner = self.inner.clone().write();
let mut write_inner = self.inner.write_unchecked();
write_inner.unresolved_error = None;

write_inner.update_subscribers();
}

pub(crate) fn render_error(&self) -> Element {
let inner_read = self.inner.clone().write();
let inner_read = self.inner.write_unchecked();
inner_read
.unresolved_error
.as_ref()
Expand All @@ -297,7 +297,7 @@ impl RouterContext {
let callback = callback.clone();
drop(self_read);
if let Some(new) = callback(myself) {
let mut self_write = self.inner.clone().write();
let mut self_write = self.inner.write_unchecked();
match new {
NavigationTarget::Internal(p) => self_write.history.replace(p),
NavigationTarget::External(e) => return self_write.external(e),
Expand Down
8 changes: 4 additions & 4 deletions packages/signals/examples/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,20 @@ fn app() -> Element {

#[component]
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();

unreachable!()
}

#[component]
fn ReadMut() -> Element {
let mut signal = use_signal_sync(|| 0);
let signal = use_signal_sync(|| 0);

let _read = signal.read();
let _write = signal.write();
let _write = signal.write_unchecked();

unreachable!()
}
Expand Down
Loading
Loading