WIP
This commit is contained in:
parent
0e76c0284a
commit
98178e9ca9
6
src/apply_mutations.rs
Normal file
6
src/apply_mutations.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
use bevy::ecs::{entity::Entity, world::World};
|
||||||
|
use dioxus_core::Mutations;
|
||||||
|
|
||||||
|
pub fn apply_mutations(mutations: Mutations, root_entity: Entity, world: &mut World) {
|
||||||
|
todo!("Modify bevy_ui entities based on mutations");
|
||||||
|
}
|
||||||
44
src/deferred_system.rs
Normal file
44
src/deferred_system.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
use bevy::ecs::{
|
||||||
|
system::{IntoSystem, Resource, SystemId},
|
||||||
|
world::World,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DeferredSystem(pub(crate) Arc<DeferredSystemInner>);
|
||||||
|
|
||||||
|
pub(crate) struct DeferredSystemInner {
|
||||||
|
pub id: SystemId,
|
||||||
|
world: *mut World,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeferredSystem {
|
||||||
|
pub(crate) fn new<S>(system: S, world: &mut World) -> Self
|
||||||
|
where
|
||||||
|
S: IntoSystem<(), (), ()> + 'static,
|
||||||
|
{
|
||||||
|
Self(Arc::new(DeferredSystemInner {
|
||||||
|
id: world.register_system(system),
|
||||||
|
world,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn schedule(&self) {
|
||||||
|
unsafe { &mut *self.0.world }
|
||||||
|
.resource_mut::<DeferredSystemRunQueue>()
|
||||||
|
.0
|
||||||
|
.push(self.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for DeferredSystemInner {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { &mut *self.world }.remove_system(self.id).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for DeferredSystemInner {}
|
||||||
|
unsafe impl Sync for DeferredSystemInner {}
|
||||||
|
|
||||||
|
#[derive(Resource, Default)]
|
||||||
|
pub struct DeferredSystemRunQueue(pub Vec<DeferredSystem>);
|
||||||
42
src/hooks.rs
Normal file
42
src/hooks.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
use crate::{deferred_system::DeferredSystem, tick::EcsContext};
|
||||||
|
use bevy::ecs::{
|
||||||
|
system::{IntoSystem, Resource},
|
||||||
|
world::World,
|
||||||
|
};
|
||||||
|
use dioxus_core::ScopeState;
|
||||||
|
|
||||||
|
pub trait DioxusUiHooks {
|
||||||
|
fn use_world<'a>(&'a self) -> &'a World;
|
||||||
|
fn use_resource<'a, T: Resource>(&'a self) -> &'a T;
|
||||||
|
fn use_system<S>(&self, system: S) -> DeferredSystem
|
||||||
|
where
|
||||||
|
S: IntoSystem<(), (), ()> + 'static;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DioxusUiHooks for ScopeState {
|
||||||
|
fn use_world<'a>(&'a self) -> &'a World {
|
||||||
|
EcsContext::get_world(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_resource<'a, T: Resource>(&'a self) -> &'a T {
|
||||||
|
EcsContext::get_world(self).resource()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_system<S>(&self, system: S) -> DeferredSystem
|
||||||
|
where
|
||||||
|
S: IntoSystem<(), (), ()> + 'static,
|
||||||
|
{
|
||||||
|
self.use_hook(|| DeferredSystem::new(system, EcsContext::get_world(self)))
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// pub fn use_query<'a, Q, F>(cx: &'a ScopeState) -> QueryIter<'a, '_, Q, F>
|
||||||
|
// where
|
||||||
|
// Q: ReadOnlyWorldQuery,
|
||||||
|
// F: ReadOnlyWorldQuery,
|
||||||
|
// {
|
||||||
|
// let world = EcsContext::get_world(cx);
|
||||||
|
// world.query_filtered::<Q, F>().iter(&world)
|
||||||
|
// }
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
use super::DioxusUiRoot;
|
|
||||||
use bevy::{
|
|
||||||
ecs::{
|
|
||||||
entity::Entity,
|
|
||||||
system::{CommandQueue, Commands, Resource},
|
|
||||||
world::World,
|
|
||||||
},
|
|
||||||
prelude::{Deref, DerefMut},
|
|
||||||
utils::synccell::SyncCell,
|
|
||||||
};
|
|
||||||
use dioxus_core::{Element, Mutations, Scope, ScopeState, VirtualDom};
|
|
||||||
use std::{cell::RefCell, mem::transmute, rc::Rc};
|
|
||||||
|
|
||||||
pub fn tick_dioxus_ui(world: &mut World) {
|
|
||||||
let apply_mutations = |mutations: Mutations, root_entity: Entity| {
|
|
||||||
todo!("Modify bevy_ui entities based on mutations");
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut command_queue = CommandQueue::default();
|
|
||||||
let ecs_context = unsafe {
|
|
||||||
EcsContext {
|
|
||||||
world_read_only: transmute(&world),
|
|
||||||
commands: Rc::new(RefCell::new(Commands::new(
|
|
||||||
transmute(&mut command_queue),
|
|
||||||
transmute(&world),
|
|
||||||
))),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (root_entity, mut dioxus_ui_root) in
|
|
||||||
world.query::<(Entity, &mut DioxusUiRoot)>().iter_mut(world)
|
|
||||||
{
|
|
||||||
let DioxusUiRoot {
|
|
||||||
virtual_dom,
|
|
||||||
initial_build,
|
|
||||||
} = &mut *dioxus_ui_root;
|
|
||||||
let virtual_dom = virtual_dom.get();
|
|
||||||
|
|
||||||
virtual_dom
|
|
||||||
.base_scope()
|
|
||||||
.provide_context(ecs_context.clone());
|
|
||||||
|
|
||||||
if !*initial_build {
|
|
||||||
apply_mutations(virtual_dom.rebuild(), root_entity);
|
|
||||||
*initial_build = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Handle events from winit
|
|
||||||
// virtual_dom.handle_event(todo!(), todo!(), todo!(), todo!());
|
|
||||||
|
|
||||||
apply_mutations(virtual_dom.render_immediate(), root_entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
command_queue.apply(world);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct EcsContext {
|
|
||||||
world_read_only: &'static World,
|
|
||||||
commands: Rc<RefCell<Commands<'static, 'static>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn use_world<'a>(cx: &'a ScopeState) -> &'a World {
|
|
||||||
cx.consume_context::<EcsContext>()
|
|
||||||
.expect("Must be used from a dioxus component within a DioxusUiRoot bevy component")
|
|
||||||
.world_read_only
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn use_resource<'a, T: Resource>(cx: &'a ScopeState) -> &'a T {
|
|
||||||
cx.consume_context::<EcsContext>()
|
|
||||||
.expect("Must be used from a dioxus component within a DioxusUiRoot bevy component")
|
|
||||||
.world_read_only
|
|
||||||
.resource()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// pub fn use_query<'a, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery>(
|
|
||||||
// cx: &'a ScopeState,
|
|
||||||
// ) -> QueryIter<'a, '_, Q, F> {
|
|
||||||
// let world = &mut cx
|
|
||||||
// .consume_context::<EcsContext>()
|
|
||||||
// .expect("Must be used from a dioxus component within a DioxusUiRoot bevy component")
|
|
||||||
// .world_read_only;
|
|
||||||
// world.query_filtered::<Q, F>().iter(&world)
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn use_commands<'a>(cx: &'a ScopeState) -> Rc<RefCell<Commands<'a, 'a>>> {
|
|
||||||
unsafe {
|
|
||||||
transmute(Rc::clone(
|
|
||||||
&cx.consume_context::<EcsContext>()
|
|
||||||
.expect("Must be used from a dioxus component within a DioxusUiRoot bevy component")
|
|
||||||
.commands,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deref, DerefMut)]
|
|
||||||
pub struct VirtualDomUnsafe(pub SyncCell<VirtualDom>);
|
|
||||||
unsafe impl Send for VirtualDomUnsafe {}
|
|
||||||
|
|
||||||
impl VirtualDomUnsafe {
|
|
||||||
pub fn new(root_component: fn(Scope) -> Element) -> Self {
|
|
||||||
Self(SyncCell::new(VirtualDom::new(root_component)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
19
src/lib.rs
19
src/lib.rs
|
|
@ -1,33 +1,40 @@
|
||||||
mod implementation;
|
mod apply_mutations;
|
||||||
|
mod deferred_system;
|
||||||
|
mod hooks;
|
||||||
|
mod tick;
|
||||||
|
|
||||||
use self::implementation::{tick_dioxus_ui, VirtualDomUnsafe};
|
use self::{
|
||||||
|
deferred_system::DeferredSystemRunQueue,
|
||||||
|
tick::{tick_dioxus_ui, VirtualDomUnsafe},
|
||||||
|
};
|
||||||
use bevy::{
|
use bevy::{
|
||||||
app::{App, Plugin, Update},
|
app::{App, Plugin, Update},
|
||||||
ecs::component::Component,
|
ecs::component::Component,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::implementation::{use_commands, use_resource, use_world};
|
pub use self::hooks::DioxusUiHooks;
|
||||||
pub use dioxus_core::{Element, Scope};
|
pub use dioxus_core::{Element, Scope};
|
||||||
|
|
||||||
pub struct DioxusUiPlugin;
|
pub struct DioxusUiPlugin;
|
||||||
|
|
||||||
impl Plugin for DioxusUiPlugin {
|
impl Plugin for DioxusUiPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(Update, tick_dioxus_ui);
|
app.init_resource::<DeferredSystemRunQueue>()
|
||||||
|
.add_systems(Update, tick_dioxus_ui);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct DioxusUiRoot {
|
pub struct DioxusUiRoot {
|
||||||
virtual_dom: VirtualDomUnsafe,
|
virtual_dom: VirtualDomUnsafe,
|
||||||
initial_build: bool,
|
needs_rebuild: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DioxusUiRoot {
|
impl DioxusUiRoot {
|
||||||
pub fn new(root_component: fn(Scope) -> Element) -> Self {
|
pub fn new(root_component: fn(Scope) -> Element) -> Self {
|
||||||
Self {
|
Self {
|
||||||
virtual_dom: VirtualDomUnsafe::new(root_component),
|
virtual_dom: VirtualDomUnsafe::new(root_component),
|
||||||
initial_build: false,
|
needs_rebuild: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
76
src/tick.rs
Normal file
76
src/tick.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
use crate::{
|
||||||
|
apply_mutations::apply_mutations, deferred_system::DeferredSystemRunQueue, DioxusUiRoot,
|
||||||
|
};
|
||||||
|
use bevy::{
|
||||||
|
ecs::{entity::Entity, world::World},
|
||||||
|
prelude::{Deref, DerefMut},
|
||||||
|
utils::synccell::SyncCell,
|
||||||
|
};
|
||||||
|
use dioxus_core::{Element, Scope, ScopeState, VirtualDom};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
pub fn tick_dioxus_ui(world: &mut World) {
|
||||||
|
let world_ptr: *mut World = world;
|
||||||
|
let world_cell = world.as_unsafe_world_cell();
|
||||||
|
|
||||||
|
for (root_entity, mut dioxus_ui_root) in unsafe {
|
||||||
|
world_cell
|
||||||
|
.world_mut()
|
||||||
|
.query::<(Entity, &mut DioxusUiRoot)>()
|
||||||
|
.iter_mut(world_cell.world_mut())
|
||||||
|
} {
|
||||||
|
let DioxusUiRoot {
|
||||||
|
virtual_dom,
|
||||||
|
needs_rebuild,
|
||||||
|
} = &mut *dioxus_ui_root;
|
||||||
|
let virtual_dom = virtual_dom.get();
|
||||||
|
|
||||||
|
virtual_dom
|
||||||
|
.base_scope()
|
||||||
|
.provide_context(EcsContext { world: world_ptr });
|
||||||
|
|
||||||
|
if *needs_rebuild {
|
||||||
|
apply_mutations(virtual_dom.rebuild(), root_entity, unsafe {
|
||||||
|
world_cell.world_mut()
|
||||||
|
});
|
||||||
|
*needs_rebuild = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle events from winit
|
||||||
|
// virtual_dom.handle_event(todo!(), todo!(), todo!(), todo!());
|
||||||
|
|
||||||
|
apply_mutations(virtual_dom.render_immediate(), root_entity, unsafe {
|
||||||
|
world_cell.world_mut()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for system in mem::take(&mut world.resource_mut::<DeferredSystemRunQueue>().0) {
|
||||||
|
world.run_system(system.0.id).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct EcsContext {
|
||||||
|
world: *mut World,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EcsContext {
|
||||||
|
pub fn get_world(cx: &ScopeState) -> &mut World {
|
||||||
|
unsafe {
|
||||||
|
&mut *cx
|
||||||
|
.consume_context::<EcsContext>()
|
||||||
|
.expect("Must be used from a dioxus component within a DioxusUiRoot bevy component")
|
||||||
|
.world
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deref, DerefMut)]
|
||||||
|
pub struct VirtualDomUnsafe(pub SyncCell<VirtualDom>);
|
||||||
|
unsafe impl Send for VirtualDomUnsafe {}
|
||||||
|
|
||||||
|
impl VirtualDomUnsafe {
|
||||||
|
pub fn new(root_component: fn(Scope) -> Element) -> Self {
|
||||||
|
Self(SyncCell::new(VirtualDom::new(root_component)))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue