make OpenXR event handlers completely safe! (no more unsafe at all in there)

Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
Schmarni
2025-04-11 21:08:06 +02:00
parent 5c041e9565
commit 3a59ba1257
3 changed files with 29 additions and 45 deletions

View File

@@ -7,7 +7,7 @@ use crate::{
next_chain::{OxrNextChainStructBase, OxrNextChainStructProvider}, next_chain::{OxrNextChainStructBase, OxrNextChainStructProvider},
openxr::exts::OxrEnabledExtensions, openxr::exts::OxrEnabledExtensions,
openxr_session_available, openxr_session_available,
poll_events::{OxrEvent, OxrEventHandlerExt}, poll_events::{OxrEventHandlerExt, OxrEventIn},
session::{OxrSessionCreateNextChain, OxrSessionCreateNextProvider}, session::{OxrSessionCreateNextChain, OxrSessionCreateNextProvider},
}; };
@@ -25,9 +25,8 @@ impl Plugin for OxrOverlayPlugin {
} }
} }
fn handle_overlay_event(event: In<OxrEvent>, mut writer: EventWriter<OxrOverlaySessionEvent>) { fn handle_overlay_event(event: OxrEventIn, mut writer: EventWriter<OxrOverlaySessionEvent>) {
// this unwrap will never panic since we are in a valid scope if let Event::MainSessionVisibilityChangedEXTX(event) = *event {
if let Event::MainSessionVisibilityChangedEXTX(event) = unsafe { event.get() }.unwrap() {
writer.send(OxrOverlaySessionEvent::MainSessionVisibilityChanged { writer.send(OxrOverlaySessionEvent::MainSessionVisibilityChanged {
visible: event.visible(), visible: event.visible(),
flags: event.flags(), flags: event.flags(),

View File

@@ -27,7 +27,7 @@ use crate::session::OxrSessionCreateNextChain;
use crate::types::*; use crate::types::*;
use super::exts::OxrEnabledExtensions; use super::exts::OxrEnabledExtensions;
use super::poll_events::OxrEvent; use super::poll_events::OxrEventIn;
use super::poll_events::OxrEventHandlerExt; use super::poll_events::OxrEventHandlerExt;
pub fn session_started(started: Option<Res<OxrSessionStarted>>) -> bool { pub fn session_started(started: Option<Res<OxrSessionStarted>>) -> bool {
@@ -297,14 +297,13 @@ impl OxrInitPlugin {
pub struct OxrInteractionProfileChanged; pub struct OxrInteractionProfileChanged;
pub fn handle_events( pub fn handle_events(
event: In<OxrEvent>, event: OxrEventIn,
mut status: ResMut<XrState>, mut status: ResMut<XrState>,
mut changed_event: EventWriter<XrStateChanged>, mut changed_event: EventWriter<XrStateChanged>,
mut interaction_profile_changed_event: EventWriter<OxrInteractionProfileChanged>, mut interaction_profile_changed_event: EventWriter<OxrInteractionProfileChanged>,
) { ) {
use openxr::Event::*; use openxr::Event::*;
// this unwrap will never panic since we are in a valid scope match *event {
match unsafe { event.get() }.unwrap() {
SessionStateChanged(state) => { SessionStateChanged(state) => {
use openxr::SessionState; use openxr::SessionState;

View File

@@ -1,5 +1,3 @@
use std::{cell::RefCell, mem, ops::Deref, rc::Rc};
use bevy::{ecs::system::SystemId, prelude::*}; use bevy::{ecs::system::SystemId, prelude::*};
use bevy_mod_xr::session::{XrFirst, XrHandleEvents}; use bevy_mod_xr::session::{XrFirst, XrHandleEvents};
use openxr::{Event, EventDataBuffer}; use openxr::{Event, EventDataBuffer};
@@ -27,63 +25,51 @@ pub fn poll_events(world: &mut World) {
.poll_event(&mut buffer) .poll_event(&mut buffer)
.expect("Failed to poll event") .expect("Failed to poll event")
{ {
let event = Rc::new(RefCell::new(Some(event))); for handler in handlers
for handler in handlers.handlers.iter() { .0
if let Err(err) = .iter()
world.run_system_with_input::<_, ()>(*handler, OxrEvent::new(event.clone())) .map(|v| SystemId::<OxrEventIn, ()>::from_entity(*v))
{ {
if let Err(err) = world.run_system_with_input(handler, event) {
error!("error when running oxr event handler: {err}"); error!("error when running oxr event handler: {err}");
}; };
} }
event.deref().take();
} }
world.insert_resource(handlers); world.insert_resource(handlers);
} }
use super::{openxr_session_available, resources::OxrInstance}; use super::{openxr_session_available, resources::OxrInstance};
#[derive(Resource, Debug, Default)] #[derive(Resource, Debug, Default)]
pub struct OxrEventHandlers { pub struct OxrEventHandlers(Vec<Entity>);
pub handlers: Vec<OxrEventHandler>,
}
pub type OxrEventHandler = SystemId<In<OxrEvent>, ()>;
pub struct OxrEvent {
event: Rc<RefCell<Option<Event<'static>>>>,
}
impl OxrEvent {
pub(crate) fn new(event: Rc<RefCell<Option<Event<'_>>>>) -> Self {
Self {
#[allow(clippy::missing_transmute_annotations)]
event: unsafe { mem::transmute(event) },
}
}
/// always returns [Some] if called in a valid scope
/// # Safety
/// The event is only valid for the duration of the poll event callback,
/// don't Store the [Event] anywhere!!
#[allow(clippy::needless_lifetimes)]
pub unsafe fn get<'a>(&'a self) -> Option<Event<'a>> {
*self.event.borrow()
}
}
pub trait OxrEventHandlerExt { pub trait OxrEventHandlerExt {
fn add_oxr_event_handler<M>( fn add_oxr_event_handler<M>(
&mut self, &mut self,
system: impl IntoSystem<In<OxrEvent>, (), M> + 'static, system: impl IntoSystem<OxrEventIn<'static>, (), M> + 'static,
) -> &mut Self; ) -> &mut Self;
} }
impl OxrEventHandlerExt for App { impl OxrEventHandlerExt for App {
fn add_oxr_event_handler<M>( fn add_oxr_event_handler<M>(
&mut self, &mut self,
system: impl IntoSystem<In<OxrEvent>, (), M> + 'static, system: impl IntoSystem<OxrEventIn<'static>, (), M> + 'static,
) -> &mut Self { ) -> &mut Self {
self.init_resource::<OxrEventHandlers>(); self.init_resource::<OxrEventHandlers>();
let id = self.register_system(system); let id = self.register_system(system);
self.world_mut() self.world_mut()
.resource_mut::<OxrEventHandlers>() .resource_mut::<OxrEventHandlers>()
.handlers .0
.push(id); .push(id.entity());
self self
} }
} }
#[derive(Deref)]
pub struct OxrEventIn<'a>(pub Event<'a>);
impl SystemInput for OxrEventIn<'_> {
type Param<'i> = OxrEventIn<'i>;
type Inner<'i> = Event<'i>;
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
OxrEventIn(this)
}
}