Initial commit: NES emulator with GTK4 desktop frontend
Some checks failed
CI / rust (push) Has been cancelled
Some checks failed
CI / rust (push) Has been cancelled
Full NES emulation: CPU, PPU, APU, 47 mappers, iNES/NES 2.0 parsing. GTK4 desktop client with HeaderBar, pixel-perfect Cairo rendering, drag-and-drop ROM loading, and keyboard shortcuts. 187 tests covering core emulation, mappers, and runtime.
This commit is contained in:
70
crates/nesemu-adapter-api/src/lib.rs
Normal file
70
crates/nesemu-adapter-api/src/lib.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub const BUTTONS_COUNT: usize = 8;
|
||||
pub type ButtonState = [bool; BUTTONS_COUNT];
|
||||
|
||||
pub trait InputSource {
|
||||
fn poll_buttons(&mut self) -> ButtonState;
|
||||
}
|
||||
|
||||
pub trait VideoSink {
|
||||
fn present_rgba(&mut self, frame: &[u8], width: u32, height: u32);
|
||||
}
|
||||
|
||||
pub trait AudioSink {
|
||||
fn push_samples(&mut self, samples: &[f32]);
|
||||
}
|
||||
|
||||
pub trait TimeSource {
|
||||
fn wait_next_frame(&mut self);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum StorageError {
|
||||
NotFound(String),
|
||||
Io(String),
|
||||
}
|
||||
|
||||
pub trait FileStore {
|
||||
fn read(&self, key: &str) -> Result<Vec<u8>, StorageError>;
|
||||
fn write(&mut self, key: &str, bytes: &[u8]) -> Result<(), StorageError>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MemoryStore {
|
||||
items: HashMap<String, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl FileStore for MemoryStore {
|
||||
fn read(&self, key: &str) -> Result<Vec<u8>, StorageError> {
|
||||
self.items
|
||||
.get(key)
|
||||
.cloned()
|
||||
.ok_or_else(|| StorageError::NotFound(key.to_string()))
|
||||
}
|
||||
|
||||
fn write(&mut self, key: &str, bytes: &[u8]) -> Result<(), StorageError> {
|
||||
self.items.insert(key.to_string(), bytes.to_vec());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{FileStore, MemoryStore, StorageError};
|
||||
|
||||
#[test]
|
||||
fn memory_store_roundtrip() {
|
||||
let mut store = MemoryStore::default();
|
||||
store.write("slot1", &[1, 2, 3]).expect("write");
|
||||
assert_eq!(store.read("slot1").expect("read"), vec![1, 2, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn memory_store_not_found() {
|
||||
let store = MemoryStore::default();
|
||||
let err = store.read("missing").expect_err("must fail");
|
||||
assert!(matches!(err, StorageError::NotFound(_)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user