add scary-looking-but-safe dynamic downcast for a component_mut accessor
This commit is contained in:
parent
26ff040136
commit
268f1b4ff8
|
@ -1,5 +1,6 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use ferretro_base::retro::ffi::*;
|
use ferretro_base::retro::ffi::*;
|
||||||
|
use std::any::{Any, TypeId};
|
||||||
use std::os::raw::c_uint;
|
use std::os::raw::c_uint;
|
||||||
use std::path::{PathBuf, Path};
|
use std::path::{PathBuf, Path};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
@ -9,7 +10,8 @@ pub struct RetroComponentBase {
|
||||||
retro: LibretroWrapper,
|
retro: LibretroWrapper,
|
||||||
libretro_path: PathBuf,
|
libretro_path: PathBuf,
|
||||||
// TODO: control when things get added to this with lifetime constraints defined by implementers
|
// TODO: control when things get added to this with lifetime constraints defined by implementers
|
||||||
components: Vec<Box<dyn RetroComponent>>,
|
components: Vec<Pin<Box<dyn RetroComponent>>>,
|
||||||
|
component_ptrs: Vec<(TypeId, *mut ())>,
|
||||||
|
|
||||||
// replaying env calls for late-added components
|
// replaying env calls for late-added components
|
||||||
cached_rom_path: Option<PathBuf>,
|
cached_rom_path: Option<PathBuf>,
|
||||||
|
@ -25,6 +27,9 @@ pub struct RetroComponentBase {
|
||||||
cached_geometry: Option<GameGeometry>,
|
cached_geometry: Option<GameGeometry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct RetroComponentId(usize);
|
||||||
|
|
||||||
// TODO: replace with std::ops::ControlFlow when it becomes stable
|
// TODO: replace with std::ops::ControlFlow when it becomes stable
|
||||||
pub enum ControlFlow {
|
pub enum ControlFlow {
|
||||||
Continue,
|
Continue,
|
||||||
|
@ -35,7 +40,7 @@ pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub trait RetroComponent: RetroCallbacks {
|
pub trait RetroComponent: RetroCallbacks + Any {
|
||||||
fn pre_init(&mut self, retro: &mut LibretroWrapper) -> Result<()> { Ok(()) }
|
fn pre_init(&mut self, retro: &mut LibretroWrapper) -> Result<()> { Ok(()) }
|
||||||
fn post_init(&mut self, retro: &mut LibretroWrapper) -> Result<()> { Ok(()) }
|
fn post_init(&mut self, retro: &mut LibretroWrapper) -> Result<()> { Ok(()) }
|
||||||
fn pre_load_game(&mut self, retro: &mut LibretroWrapper, rom: &Path) -> Result<()> { Ok(()) }
|
fn pre_load_game(&mut self, retro: &mut LibretroWrapper, rom: &Path) -> Result<()> { Ok(()) }
|
||||||
|
@ -55,6 +60,7 @@ impl RetroComponentBase {
|
||||||
retro,
|
retro,
|
||||||
libretro_path: core_path.as_ref().to_path_buf(),
|
libretro_path: core_path.as_ref().to_path_buf(),
|
||||||
components: Vec::new(),
|
components: Vec::new(),
|
||||||
|
component_ptrs: Vec::new(),
|
||||||
cached_rom_path: None,
|
cached_rom_path: None,
|
||||||
cached_pixel_format: None,
|
cached_pixel_format: None,
|
||||||
cached_input_descriptors: None,
|
cached_input_descriptors: None,
|
||||||
|
@ -87,11 +93,13 @@ impl RetroComponentBase {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_component<T>(&mut self, comp: T) -> Option<()> // TODO: Result
|
pub fn register_component<T>(&mut self, comp: T) -> Result<RetroComponentId>
|
||||||
where T: RetroComponent
|
where T: RetroComponent + Any
|
||||||
{
|
{
|
||||||
// TODO: match comp.schedule { BeforeInit, BeforeLoad, BeforeFirstRun, Anytime }
|
// TODO: match comp.schedule { BeforeInit, BeforeLoad, BeforeFirstRun, Anytime }
|
||||||
let mut comp = Box::new(comp);
|
let comp_type = comp.type_id();
|
||||||
|
let mut comp = Box::pin(comp);
|
||||||
|
let comp_ptr = comp.as_mut().get_mut() as *mut T;
|
||||||
if let Some(cached) = &self.cached_pixel_format {
|
if let Some(cached) = &self.cached_pixel_format {
|
||||||
if let Some(false) = comp.set_pixel_format(*cached) {
|
if let Some(false) = comp.set_pixel_format(*cached) {
|
||||||
// TODO: error, and propagate this pattern downward
|
// TODO: error, and propagate this pattern downward
|
||||||
|
@ -126,12 +134,26 @@ impl RetroComponentBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(cached) = &self.cached_rom_path {
|
if let Some(cached) = &self.cached_rom_path {
|
||||||
comp.post_load_game(&mut self.retro, &cached);
|
comp.post_load_game(&mut self.retro, &cached)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.components.push(comp);
|
self.components.push(comp);
|
||||||
|
self.component_ptrs.push((comp_type, comp_ptr as *mut ()));
|
||||||
|
|
||||||
Some(())
|
Ok(RetroComponentId(self.components.len() - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn component_mut<T: RetroComponent>(&mut self, id: RetroComponentId) -> Result<&mut T> {
|
||||||
|
let (comp_type, comp_ptr) = self.component_ptrs.get(id.0)
|
||||||
|
.ok_or_else(|| format!("Invalid ID given to component_mut: {:?}", id))?;
|
||||||
|
if *comp_type == TypeId::of::<T>() {
|
||||||
|
Ok(unsafe { &mut *(*comp_ptr as *mut T) })
|
||||||
|
} else {
|
||||||
|
Err(format!(
|
||||||
|
"Invalid downcast for {:?}: {:?} != {:?}",
|
||||||
|
id, comp_type, TypeId::of::<T>()
|
||||||
|
).into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_game(&mut self, rom: impl AsRef<Path>) -> Result<()> {
|
pub fn load_game(&mut self, rom: impl AsRef<Path>) -> Result<()> {
|
||||||
|
|
|
@ -2,7 +2,7 @@ pub mod provided;
|
||||||
pub mod base;
|
pub mod base;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::base::{RetroComponent, RetroComponentBase};
|
pub use crate::base::{RetroComponent, RetroComponentBase, RetroComponentId};
|
||||||
pub use ferretro_base::retro::constants::*;
|
pub use ferretro_base::retro::constants::*;
|
||||||
pub use ferretro_base::retro::wrapped_types::*;
|
pub use ferretro_base::retro::wrapped_types::*;
|
||||||
pub use ferretro_base::retro::wrapper::{RetroCallbacks, LibretroWrapper, LibretroWrapperAccess};
|
pub use ferretro_base::retro::wrapper::{RetroCallbacks, LibretroWrapper, LibretroWrapperAccess};
|
||||||
|
|
Loading…
Reference in New Issue