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::{
|
||||
app::{App, Plugin, Update},
|
||||
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 struct DioxusUiPlugin;
|
||||
|
||||
impl Plugin for DioxusUiPlugin {
|
||||
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)]
|
||||
pub struct DioxusUiRoot {
|
||||
virtual_dom: VirtualDomUnsafe,
|
||||
initial_build: bool,
|
||||
needs_rebuild: bool,
|
||||
}
|
||||
|
||||
impl DioxusUiRoot {
|
||||
pub fn new(root_component: fn(Scope) -> Element) -> Self {
|
||||
Self {
|
||||
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