From d58710e8ac8d8d03bec0669ba0d5e915a25afa43 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Sat, 16 Dec 2023 12:41:32 -0800 Subject: [PATCH] Move VirtualDom to a non-send resource --- src/lib.rs | 36 ++++++++++++++-------- src/tick.rs | 89 ++++++++++++++++++++--------------------------------- 2 files changed, 56 insertions(+), 69 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 43b37c2..2aa2ac1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,19 +6,17 @@ pub mod hooks; mod tick; use self::{ - apply_mutations::BevyTemplate, - deferred_system::DeferredSystemRegistry, - events::EventReaders, - hooks::EcsSubscriptions, - tick::{tick_dioxus_ui, VirtualDomUnsafe}, + apply_mutations::BevyTemplate, deferred_system::DeferredSystemRegistry, events::EventReaders, + hooks::EcsSubscriptions, tick::tick_dioxus_ui, }; use bevy::{ app::{App, Plugin, Update}, ecs::{bundle::Bundle, component::Component, entity::Entity}, + prelude::{Deref, DerefMut}, ui::node_bundles::NodeBundle, utils::{EntityHashMap, HashMap}, }; -use dioxus::core::{Element, ElementId, Scope}; +use dioxus::core::{Element, ElementId, Scope, VirtualDom}; pub use bevy_mod_picking; pub use dioxus; @@ -27,7 +25,8 @@ pub struct DioxusUiPlugin; impl Plugin for DioxusUiPlugin { fn build(&self, app: &mut App) { - app.init_resource::() + app.init_non_send_resource::() + .init_resource::() .init_resource::() .init_resource::() .add_systems(Update, tick_dioxus_ui); @@ -40,19 +39,30 @@ pub struct DioxusUiBundle { pub node_bundle: NodeBundle, } -#[derive(Component)] -pub struct DioxusUiRoot { - virtual_dom: VirtualDomUnsafe, +#[derive(Component, Deref, Clone, Copy)] +pub struct DioxusUiRoot(fn(Scope) -> Element); + +impl DioxusUiRoot { + pub fn new(root_component: fn(Scope) -> Element) -> Self { + Self(root_component) + } +} + +#[derive(Deref, DerefMut, Default)] +struct UiRoots(EntityHashMap); + +struct UiRoot { + virtual_dom: VirtualDom, element_id_to_bevy_ui_entity: HashMap, bevy_ui_entity_to_element_id: EntityHashMap, templates: HashMap, needs_rebuild: bool, } -impl DioxusUiRoot { - pub fn new(root_component: fn(Scope) -> Element) -> Self { +impl UiRoot { + fn new(root_component: fn(Scope) -> Element) -> Self { Self { - virtual_dom: VirtualDomUnsafe::new(root_component), + virtual_dom: VirtualDom::new(root_component), element_id_to_bevy_ui_entity: HashMap::new(), bevy_ui_entity_to_element_id: EntityHashMap::default(), templates: HashMap::new(), diff --git a/src/tick.rs b/src/tick.rs index a0c8774..70a7b5c 100644 --- a/src/tick.rs +++ b/src/tick.rs @@ -3,19 +3,16 @@ use crate::{ deferred_system::DeferredSystemRegistry, events::EventReaders, hooks::{EcsContext, EcsSubscriptions}, - DioxusUiRoot, + DioxusUiRoot, UiRoot, UiRoots, }; use bevy::{ ecs::{ entity::Entity, - query::With, world::{Mut, World}, }, hierarchy::Parent, - prelude::{Deref, DerefMut}, - utils::synccell::SyncCell, + utils::HashMap, }; -use dioxus::core::{Element, Scope, VirtualDom}; use std::{any::Any, mem, rc::Rc, sync::Arc}; pub fn tick_dioxus_ui(world: &mut World) { @@ -24,17 +21,32 @@ pub fn tick_dioxus_ui(world: &mut World) { let ui_events = world.resource_scope(|world, mut event_readers: Mut| { event_readers.get_dioxus_events(world.resource()) }); - let root_entities: Vec = world - .query_filtered::>() + + let root_entities: HashMap = world + .query::<(Entity, &DioxusUiRoot)>() .iter(world) + .map(|(entity, ui_root)| (entity, *ui_root)) .collect(); - for root_entity in root_entities { - dispatch_ui_events(&ui_events, root_entity, world); + world + .non_send_resource_mut::() + .retain(|root_entity, _| root_entities.contains_key(root_entity)); - schedule_ui_renders_from_ecs_subscriptions(root_entity, world); + for (root_entity, ui_root) in root_entities { + let mut ui_root = world + .non_send_resource_mut::() + .remove(&root_entity) + .unwrap_or_else(|| UiRoot::new(*ui_root)); - render_ui(root_entity, world); + dispatch_ui_events(&ui_events, &mut ui_root, world); + + schedule_ui_renders_from_ecs_subscriptions(&mut ui_root, world); + + render_ui(root_entity, &mut ui_root, world); + + world + .non_send_resource_mut::() + .insert(root_entity, ui_root); } } @@ -56,14 +68,9 @@ fn run_deferred_systems(world: &mut World) { fn dispatch_ui_events( events: &Vec<(Entity, &str, Rc)>, - root_entity: Entity, - world: &mut World, + ui_root: &mut UiRoot, + world: &World, ) { - let mut ui_root = world - .entity_mut(root_entity) - .take::() - .unwrap(); - for (mut target, name, data) in events { let mut target_element_id = ui_root.bevy_ui_entity_to_element_id.get(&target).copied(); while target_element_id.is_none() { @@ -71,26 +78,14 @@ fn dispatch_ui_events( target_element_id = ui_root.bevy_ui_entity_to_element_id.get(&target).copied(); } - ui_root.virtual_dom.get().handle_event( - name, - Rc::clone(data), - target_element_id.unwrap(), - true, - ); + ui_root + .virtual_dom + .handle_event(name, Rc::clone(data), target_element_id.unwrap(), true); } - - world.entity_mut(root_entity).insert(ui_root); } -fn schedule_ui_renders_from_ecs_subscriptions(root_entity: Entity, world: &mut World) { - let schedule_update = world - .get_mut::(root_entity) - .unwrap() - .virtual_dom - .get() - .base_scope() - .schedule_update_any(); - +fn schedule_ui_renders_from_ecs_subscriptions(ui_root: &mut UiRoot, world: &World) { + let schedule_update = ui_root.virtual_dom.base_scope().schedule_update_any(); let ecs_subscriptions = world.resource::(); for scope_id in &*ecs_subscriptions.world_and_queries { @@ -106,21 +101,15 @@ fn schedule_ui_renders_from_ecs_subscriptions(root_entity: Entity, world: &mut W } } -fn render_ui(root_entity: Entity, world: &mut World) { - let mut ui_root = world - .entity_mut(root_entity) - .take::() - .unwrap(); - +fn render_ui(root_entity: Entity, ui_root: &mut UiRoot, world: &mut World) { ui_root .virtual_dom - .get() .base_scope() .provide_context(EcsContext { world }); if ui_root.needs_rebuild { apply_mutations( - ui_root.virtual_dom.get().rebuild(), + ui_root.virtual_dom.rebuild(), &mut ui_root.element_id_to_bevy_ui_entity, &mut ui_root.bevy_ui_entity_to_element_id, &mut ui_root.templates, @@ -131,23 +120,11 @@ fn render_ui(root_entity: Entity, world: &mut World) { } apply_mutations( - ui_root.virtual_dom.get().render_immediate(), + ui_root.virtual_dom.render_immediate(), &mut ui_root.element_id_to_bevy_ui_entity, &mut ui_root.bevy_ui_entity_to_element_id, &mut ui_root.templates, root_entity, world, ); - - world.entity_mut(root_entity).insert(ui_root); -} - -#[derive(Deref, DerefMut)] -pub struct VirtualDomUnsafe(pub SyncCell); -unsafe impl Send for VirtualDomUnsafe {} - -impl VirtualDomUnsafe { - pub fn new(root_component: fn(Scope) -> Element) -> Self { - Self(SyncCell::new(VirtualDom::new(root_component))) - } }