Rework card trait and settings UI
This commit is contained in:
parent
23d4723a31
commit
f7d487951e
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -126,6 +126,7 @@ dependencies = [
|
|||||||
name = "altair_emu"
|
name = "altair_emu"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"bitflags 2.4.2",
|
"bitflags 2.4.2",
|
||||||
"device_query",
|
"device_query",
|
||||||
"eframe",
|
"eframe",
|
||||||
@ -134,7 +135,9 @@ dependencies = [
|
|||||||
"env_logger",
|
"env_logger",
|
||||||
"ihex",
|
"ihex",
|
||||||
"image",
|
"image",
|
||||||
|
"inventory",
|
||||||
"log",
|
"log",
|
||||||
|
"mopa",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rand",
|
"rand",
|
||||||
"rfd",
|
"rfd",
|
||||||
@ -171,6 +174,12 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
|
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.79"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arboard"
|
name = "arboard"
|
||||||
version = "3.2.0"
|
version = "3.2.0"
|
||||||
@ -1660,6 +1669,12 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inventory"
|
||||||
|
version = "0.3.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-lifetimes"
|
name = "io-lifetimes"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
@ -1870,6 +1885,12 @@ dependencies = [
|
|||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mopa"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a785740271256c230f57462d3b83e52f998433a7062fc18f96d5999474a9f915"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nanorand"
|
name = "nanorand"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anyhow = "1.0.79"
|
||||||
bitflags = "2.3.3"
|
bitflags = "2.3.3"
|
||||||
device_query = "1.1.3"
|
device_query = "1.1.3"
|
||||||
eframe = { version = "0.25.0", features = ["ron", "persistence"] }
|
eframe = { version = "0.25.0", features = ["ron", "persistence"] }
|
||||||
@ -14,7 +15,9 @@ enum_dispatch = "0.3.12"
|
|||||||
env_logger = "0.10.0"
|
env_logger = "0.10.0"
|
||||||
ihex = "3.0.0"
|
ihex = "3.0.0"
|
||||||
image = "0.24.6"
|
image = "0.24.6"
|
||||||
|
inventory = "0.3.15"
|
||||||
log = "0.4.19"
|
log = "0.4.19"
|
||||||
|
mopa = "0.2.2"
|
||||||
parking_lot = "0.12.1"
|
parking_lot = "0.12.1"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
rfd = "0.13.0"
|
rfd = "0.13.0"
|
||||||
|
94
src/card.rs
94
src/card.rs
@ -1,16 +1,70 @@
|
|||||||
use crate::ram::RamCard;
|
use anyhow::anyhow;
|
||||||
use eframe::egui;
|
use eframe::egui::Ui;
|
||||||
use enum_dispatch::enum_dispatch;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[enum_dispatch(CardEnum)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub enum CardEnum {
|
pub struct Config<'a> {
|
||||||
RamCard,
|
#[serde(rename = "type")]
|
||||||
|
typ: &'a str,
|
||||||
|
#[serde(flatten)]
|
||||||
|
settings: ron::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[enum_dispatch]
|
impl Config<'_> {
|
||||||
|
pub fn to_card(&self) -> anyhow::Result<Box<dyn Card>> {
|
||||||
|
inventory::iter::<Type>
|
||||||
|
.into_iter()
|
||||||
|
.find(|card_type| card_type.name == self.typ)
|
||||||
|
.ok_or_else(|| anyhow!("Invalid card type {}", self.typ))?
|
||||||
|
.new_card(self.settings.clone())
|
||||||
|
}
|
||||||
|
pub fn to_settings_ui(&self) -> anyhow::Result<Box<dyn SettingsUi>> {
|
||||||
|
inventory::iter::<Type>
|
||||||
|
.into_iter()
|
||||||
|
.find(|card_type| card_type.name == self.typ)
|
||||||
|
.ok_or_else(|| anyhow!("Invalid card type {}", self.typ))?
|
||||||
|
.settings_ui(self.settings.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_card(&self, settings: ron::Value) -> anyhow::Result<Box<dyn Card>> {
|
||||||
|
(self.new)(settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn settings_ui(&self, settings: ron::Value) -> anyhow::Result<Box<dyn SettingsUi>> {
|
||||||
|
(self.settings_ui)(settings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory::collect!(Type);
|
||||||
|
|
||||||
pub trait Card {
|
pub trait Card {
|
||||||
|
fn new(_settings: ron::Value) -> anyhow::Result<Self>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
#[allow(clippy::new_ret_no_self)]
|
#[allow(clippy::new_ret_no_self)]
|
||||||
fn new(_settings: ron::Value) -> CardEnum;
|
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 read_mem(&mut self, _address: u16) -> Option<u8> {
|
fn read_mem(&mut self, _address: u16) -> Option<u8> {
|
||||||
None
|
None
|
||||||
@ -24,6 +78,28 @@ pub trait Card {
|
|||||||
fn write_io(&mut self, _address: u8, _data: u8) -> Option<()> {
|
fn write_io(&mut self, _address: u8, _data: u8) -> Option<()> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn draw_settings_ui(&mut self, _ui: egui::Ui) {}
|
|
||||||
|
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;
|
fn serialize_settings(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! register {
|
||||||
|
($typ: ty, $name: literal) => {
|
||||||
|
inventory::submit!($crate::card::Type::new::<$typ>($name));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
65
src/ram.rs
65
src/ram.rs
@ -1,32 +1,81 @@
|
|||||||
|
use eframe::egui::{DragValue, Ui};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::card::{Card, CardEnum};
|
use crate::{card::{Card, SettingsUi}, register};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct RamCardSettings {
|
pub struct RamCardSettings {
|
||||||
size: u16,
|
size: u16,
|
||||||
start_addr: u16,
|
start_addr: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RamCard {
|
pub struct RamCard {
|
||||||
ram: Vec<u8>,
|
ram: Vec<u8>,
|
||||||
start_addr: u16,
|
start_addr: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Card for RamCard {
|
impl Card for RamCard {
|
||||||
fn new(settings: ron::Value) -> CardEnum {
|
fn new(settings: ron::Value) -> Result<RamCard, anyhow::Error> {
|
||||||
let settings: RamCardSettings = settings.into_rust().unwrap();
|
let settings: RamCardSettings = settings.into_rust().unwrap();
|
||||||
let ram = vec![0; settings.size as usize];
|
let ram = vec![0; settings.size as usize];
|
||||||
CardEnum::RamCard(Self {
|
Ok(Self {
|
||||||
ram,
|
ram,
|
||||||
start_addr: settings.start_addr,
|
start_addr: settings.start_addr,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_settings(&self) -> String {
|
fn read_mem(&mut self, address: u16) -> Option<u8> {
|
||||||
ron::to_string(&RamCardSettings {
|
if address < self.start_addr {
|
||||||
size: self.ram.len() as u16,
|
return None;
|
||||||
start_addr: self.start_addr,
|
}
|
||||||
|
let offset = (address - self.start_addr) as usize;
|
||||||
|
if offset >= self.ram.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(self.ram[offset])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_mem(&mut self, address: u16, data: u8) -> Option<()> {
|
||||||
|
if address < self.start_addr {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let offset = (address - self.start_addr) as usize;
|
||||||
|
if offset >= self.ram.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.ram[offset] = data;
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn settings_ui(settings: ron::Value) -> anyhow::Result<impl SettingsUi>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Ok(RamCardSettingsUi {
|
||||||
|
settings: settings.into_rust().unwrap(),
|
||||||
})
|
})
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RamCardSettingsUi {
|
||||||
|
settings: RamCardSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SettingsUi for RamCardSettingsUi {
|
||||||
|
fn draw_ui(&mut self, ui: &mut Ui) {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Size");
|
||||||
|
ui.add(DragValue::new(&mut self.settings.size).hexadecimal(4, false, true));
|
||||||
|
});
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Start address");
|
||||||
|
ui.add(DragValue::new(&mut self.settings.start_addr).hexadecimal(4, false, true));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_settings(&self) -> String {
|
||||||
|
ron::to_string(&self.settings).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register!(RamCard, "RAM card");
|
||||||
|
Loading…
Reference in New Issue
Block a user