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
@@ -652,8 +652,11 @@ mod struct_info {
|
||||
let new_value: &_ = &*new.#signal_fields.peek();
|
||||
(&old_value).compare(&&new_value)
|
||||
};
|
||||
// Make the old fields point to the new fields
|
||||
#signal_fields.point_to(new.#signal_fields).unwrap();
|
||||
if !field_eq {
|
||||
(#signal_fields).__set(new.#signal_fields.__take());
|
||||
// If the fields are not equal, mark the signal as dirty to rerun any subscribers
|
||||
(#signal_fields).mark_dirty();
|
||||
}
|
||||
// Move the old value back
|
||||
self.#signal_fields = #signal_fields;
|
||||
@@ -683,13 +686,13 @@ mod struct_info {
|
||||
quote! {
|
||||
// If the event handler is None, we don't need to update it
|
||||
if let (Some(old_handler), Some(new_handler)) = (self.#name.as_mut(), new.#name.as_ref()) {
|
||||
old_handler.__set(new_handler.__take());
|
||||
old_handler.__point_to(new_handler);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
// Update the event handlers
|
||||
self.#name.__set(new.#name.__take());
|
||||
self.#name.__point_to(&new.#name);
|
||||
}
|
||||
}
|
||||
}).collect();
|
||||
@@ -1447,7 +1450,7 @@ Finally, call `.build()` to create the instance of `{name}`.
|
||||
#[derive(Clone)]
|
||||
#vis struct #name #generics_with_bounds #where_clause {
|
||||
inner: #original_name #ty_generics,
|
||||
owner: Owner,
|
||||
owner: dioxus_core::internal::generational_box::Owner,
|
||||
}
|
||||
|
||||
impl #original_impl_generics PartialEq for #name #ty_generics #where_clause {
|
||||
|
||||
@@ -161,3 +161,52 @@ fn spreads_memorize_in_place() {
|
||||
assert!(props.memoize(&CompProps::builder().build()));
|
||||
assert_eq!(props.attributes, vec![]);
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/DioxusLabs/dioxus/issues/2331
|
||||
#[test]
|
||||
fn cloning_read_only_signal_components_work() {
|
||||
fn app() -> Element {
|
||||
if generation() < 5 {
|
||||
println!("Generating new props");
|
||||
needs_update();
|
||||
}
|
||||
|
||||
let read_only_signal_rsx = rsx! {
|
||||
TakesReadOnlySignalNonClone { sig: NonCloneable(generation() as i32) }
|
||||
TakesReadOnlySignalNum { sig: generation() as i32 }
|
||||
};
|
||||
|
||||
rsx! {
|
||||
{read_only_signal_rsx.clone()}
|
||||
{read_only_signal_rsx}
|
||||
}
|
||||
}
|
||||
|
||||
struct NonCloneable<T>(T);
|
||||
|
||||
#[component]
|
||||
fn TakesReadOnlySignalNum(sig: ReadOnlySignal<i32>) -> Element {
|
||||
rsx! {}
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn TakesReadOnlySignalNonClone(sig: ReadOnlySignal<NonCloneable<i32>>) -> Element {
|
||||
rsx! {}
|
||||
}
|
||||
|
||||
set_event_converter(Box::new(dioxus::html::SerializedHtmlEventConverter));
|
||||
let mut dom = VirtualDom::new(app);
|
||||
|
||||
let mutations = dom.rebuild_to_vec();
|
||||
println!("{:#?}", mutations);
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
for _ in 0..20 {
|
||||
let event = Event::new(
|
||||
Rc::new(PlatformEventData::new(Box::<SerializedMouseData>::default())) as Rc<dyn Any>,
|
||||
true,
|
||||
);
|
||||
dom.runtime().handle_event("click", event, ElementId(1));
|
||||
dom.render_immediate(&mut dioxus_core::NoOpMutations);
|
||||
}
|
||||
dom.render_immediate(&mut dioxus_core::NoOpMutations);
|
||||
}
|
||||
Reference in new issue
Block a user