Fix cloned rsx double drop (#2839)
* Implement Rc generational pointers * Clean up error handling a bit * start adding tests * Simplify a few types * Separate Rc and normal generational boxes * Add tests for rc drop and read * Move over the pointer instead of the data in ReadOnlySignal props * Fix panic on ref drop and release mode builds * final rc signal cleanup * use rc generational boxes for event handlers as well * add a regression test for read only signal cloning * merge main --------- Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
1 parent
20d146d9bd
commit
baf5a95cae
19 files changed
+905
-250
No files matched your search
@@ -71,6 +71,19 @@ impl<T: 'static, S: Storage<T>> CopyValue<T, S> {
|
||||
Self::new_with_caller(value, std::panic::Location::caller())
|
||||
}
|
||||
|
||||
/// Create a new CopyValue without an owner. This will leak memory if you don't manually drop it.
|
||||
pub fn leak_with_caller(value: T, caller: &'static std::panic::Location<'static>) -> Self {
|
||||
Self {
|
||||
value: GenerationalBox::leak(value, caller),
|
||||
origin_scope: current_scope_id().expect("in a virtual dom"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Point to another copy value
|
||||
pub fn point_to(&mut self, other: Self) -> BorrowResult {
|
||||
self.value.point_to(other.value)
|
||||
}
|
||||
|
||||
pub(crate) fn new_with_caller(
|
||||
value: T,
|
||||
caller: &'static std::panic::Location<'static>,
|
||||
@@ -78,7 +91,7 @@ impl<T: 'static, S: Storage<T>> CopyValue<T, S> {
|
||||
let owner = current_owner();
|
||||
|
||||
Self {
|
||||
value: owner.insert_with_caller(value, caller),
|
||||
value: owner.insert_rc_with_caller(value, caller),
|
||||
origin_scope: current_scope_id().expect("in a virtual dom"),
|
||||
}
|
||||
}
|
||||
@@ -99,13 +112,13 @@ impl<T: 'static, S: Storage<T>> CopyValue<T, S> {
|
||||
let owner = scope.owner();
|
||||
|
||||
Self {
|
||||
value: owner.insert_with_caller(value, caller),
|
||||
value: owner.insert_rc_with_caller(value, caller),
|
||||
origin_scope: scope,
|
||||
}
|
||||
}
|
||||
|
||||
/// Manually drop the value in the CopyValue, invalidating the value in the process.
|
||||
pub fn manually_drop(&self) -> Option<T> {
|
||||
pub fn manually_drop(&self) {
|
||||
self.value.manually_drop()
|
||||
}
|
||||
|
||||
|
||||
@@ -42,25 +42,17 @@ impl<T: 'static, S: Storage<SignalData<T>>> ReadOnlySignal<T, S> {
|
||||
self.inner.id()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// This should only be used by the `rsx!` macro.
|
||||
pub fn __set(&mut self, value: T) {
|
||||
use crate::write::Writable;
|
||||
use warnings::Warning;
|
||||
// This is only called when converting T -> ReadOnlySignal<T> which will not cause loops
|
||||
crate::warnings::signal_write_in_component_body::allow(|| {
|
||||
crate::warnings::signal_read_and_write_in_reactive_scope::allow(|| {
|
||||
self.inner.set(value);
|
||||
});
|
||||
});
|
||||
/// Point to another signal
|
||||
pub fn point_to(&mut self, other: Self) -> BorrowResult {
|
||||
self.inner.point_to(other.inner)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// This should only be used by the `rsx!` macro.
|
||||
pub fn __take(&self) -> T {
|
||||
self.inner
|
||||
.manually_drop()
|
||||
.expect("Signal has already been dropped")
|
||||
/// This is only used by the `props` macro.
|
||||
/// Mark any readers of the signal as dirty
|
||||
pub fn mark_dirty(&mut self) {
|
||||
use crate::write::Writable;
|
||||
_ = self.inner.try_write();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,6 +182,19 @@ impl<T: 'static, S: Storage<SignalData<T>>> Signal<T, S> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new Signal without an owner. This will leak memory if you don't manually drop it.
|
||||
pub fn leak_with_caller(value: T, caller: &'static std::panic::Location<'static>) -> Self {
|
||||
Self {
|
||||
inner: CopyValue::leak_with_caller(
|
||||
SignalData {
|
||||
subscribers: Default::default(),
|
||||
value,
|
||||
},
|
||||
caller,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new signal with a custom owner scope. The signal will be dropped when the owner scope is dropped instead of the current scope.
|
||||
#[track_caller]
|
||||
#[tracing::instrument(skip(value))]
|
||||
@@ -208,9 +221,14 @@ impl<T: 'static, S: Storage<SignalData<T>>> Signal<T, S> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Point to another signal
|
||||
pub fn point_to(&mut self, other: Self) -> BorrowResult {
|
||||
self.inner.point_to(other.inner)
|
||||
}
|
||||
|
||||
/// Drop the value out of the signal, invalidating the signal in the process.
|
||||
pub fn manually_drop(&self) -> Option<T> {
|
||||
self.inner.manually_drop().map(|i| i.value)
|
||||
pub fn manually_drop(&self) {
|
||||
self.inner.manually_drop()
|
||||
}
|
||||
|
||||
/// Get the scope the signal was created in.
|
||||
|
||||
Reference in new issue
Block a user