altair_emu/src/card.rs
2024-02-07 11:18:38 -06:00

101 lines
2.5 KiB
Rust

use anyhow::anyhow;
use eframe::egui::Ui;
pub struct Type {
name: &'static str,
new: fn(settings: ron::Value) -> anyhow::Result<Box<dyn Card>>,
settings_ui: fn(settings: ron::Value) -> anyhow::Result<Box<dyn SettingsUi>>,
default_settings: fn() -> String,
}
impl Type {
pub const fn new<T: Card + 'static>(name: &'static str) -> Self {
Self {
name,
new: T::new_dyn,
settings_ui: T::settings_ui_dyn,
default_settings: T::default_settings,
}
}
pub fn new_card(&self, settings: ron::Value) -> anyhow::Result<Box<dyn Card>> {
(self.new)(settings)
}
pub fn settings_ui(&self, settings: ron::Value) -> anyhow::Result<Box<dyn SettingsUi>> {
(self.settings_ui)(settings)
}
pub fn default_settings(&self) -> String {
(self.default_settings)()
}
pub fn get(name: &str) -> anyhow::Result<&'static Self> {
inventory::iter::<Type>
.into_iter()
.find(|card_type| card_type.name == name)
.ok_or_else(|| anyhow!("Invalid card type {}", name))
}
pub fn name(&self) -> &'static str {
self.name
}
}
inventory::collect!(Type);
pub trait Card {
fn new(_settings: ron::Value) -> anyhow::Result<Self>
where
Self: Sized;
#[allow(clippy::new_ret_no_self)]
fn new_dyn(settings: ron::Value) -> anyhow::Result<Box<dyn Card>>
where
Self: Sized + 'static,
{
let card = Self::new(settings)?;
Ok(Box::new(card))
}
fn default_settings() -> String
where
Self: Sized;
fn read_mem(&mut self, _address: u16) -> Option<u8> {
None
}
fn write_mem(&mut self, _address: u16, _data: u8) -> Option<()> {
None
}
fn read_io(&mut self, _address: u8) -> Option<u8> {
None
}
fn write_io(&mut self, _address: u8, _data: u8) -> Option<()> {
None
}
fn settings_ui(_settings: ron::Value) -> anyhow::Result<impl SettingsUi>
where
Self: Sized;
#[allow(clippy::settings_ui_ret_no_self)]
fn settings_ui_dyn(settings: ron::Value) -> anyhow::Result<Box<dyn SettingsUi>>
where
Self: Sized + 'static,
{
let settings_ui = Self::settings_ui(settings)?;
Ok(Box::new(settings_ui))
}
}
pub trait SettingsUi {
fn draw_ui(&mut self, ui: &mut Ui);
fn serialize_settings(&self) -> String;
}
#[macro_export]
macro_rules! register {
($typ: ty, $name: literal) => {
inventory::submit!($crate::card::Type::new::<$typ>($name));
};
}