use anyhow::anyhow; use eframe::egui::Ui; pub struct Type { name: &'static str, new: fn(settings: ron::Value) -> anyhow::Result>, settings_ui: fn(settings: ron::Value) -> anyhow::Result>, default_settings: fn() -> String, } impl Type { pub const fn new(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> { (self.new)(settings) } pub fn settings_ui(&self, settings: ron::Value) -> anyhow::Result> { (self.settings_ui)(settings) } pub fn default_settings(&self) -> String { (self.default_settings)() } pub fn get(name: &str) -> anyhow::Result<&'static Self> { inventory::iter:: .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 where Self: Sized; #[allow(clippy::new_ret_no_self)] fn new_dyn(settings: ron::Value) -> anyhow::Result> 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 { None } fn write_mem(&mut self, _address: u16, _data: u8) -> Option<()> { None } fn read_io(&mut self, _address: u8) -> Option { None } fn write_io(&mut self, _address: u8, _data: u8) -> Option<()> { None } fn settings_ui(_settings: ron::Value) -> anyhow::Result where Self: Sized; #[allow(clippy::settings_ui_ret_no_self)] fn settings_ui_dyn(settings: ron::Value) -> anyhow::Result> 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)); }; }