Files
porcel8/src/util.rs

115 lines
3.3 KiB
Rust
Raw Normal View History

2025-02-20 07:56:25 +00:00
use crate::device::keyboard::KeyboardEvent;
use sdl2::video::WindowBuildError;
use sdl2::IntegerOrSdlError;
2024-03-05 18:37:57 +05:30
use std::sync::mpsc::SendError;
use std::sync::PoisonError;
2025-02-20 07:56:25 +00:00
use std::time::Duration;
pub type EmulatorResult<T> = Result<T, EmulatorError>;
2025-02-20 07:56:25 +00:00
/// CHIP-8 Device configuration
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct DeviceConfig {
is_new_chip8: bool,
halt_on_invalid: bool,
/// None if disabled, target instruction time otherwise
throttling_time: Option<Duration>,
}
impl DeviceConfig {
pub fn new(
is_new_chip8: bool,
halt_on_invalid: bool,
do_instruction_throttling: bool,
ips_throttling_rate: u64,
) -> DeviceConfig {
DeviceConfig {
is_new_chip8,
halt_on_invalid,
throttling_time: if do_instruction_throttling {
Some(Duration::from_micros(1_000_000 / ips_throttling_rate))
} else {
None
},
}
}
pub fn is_new_chip8(&self) -> bool {
self.is_new_chip8
}
pub fn should_halt_on_invalid(&self) -> bool {
self.halt_on_invalid
}
pub fn get_throttling_config(&self) -> Option<Duration> {
self.throttling_time
}
}
2024-03-05 09:33:53 +05:30
#[derive(Clone, Debug)]
pub enum EmulatorError {
SdlError(String),
IOError(String),
2025-02-20 07:56:25 +00:00
MutexInvalidState(String),
}
impl From<String> for EmulatorError {
fn from(value: String) -> Self {
Self::SdlError(value)
}
}
impl From<WindowBuildError> for EmulatorError {
fn from(value: WindowBuildError) -> Self {
Self::SdlError(value.to_string())
}
}
impl From<IntegerOrSdlError> for EmulatorError {
fn from(value: IntegerOrSdlError) -> Self {
match value {
2025-02-20 07:56:25 +00:00
IntegerOrSdlError::IntegerOverflows(x, y) => Self::SdlError(format!("{} - {}", x, y)),
IntegerOrSdlError::SdlError(str) => Self::SdlError(str),
}
}
}
2025-02-20 07:56:25 +00:00
impl From<std::io::Error> for EmulatorError {
fn from(value: std::io::Error) -> Self {
Self::IOError(value.to_string())
}
}
2025-02-20 07:56:25 +00:00
impl<T> From<PoisonError<T>> for EmulatorError {
fn from(value: PoisonError<T>) -> Self {
Self::MutexInvalidState(value.to_string())
}
2024-03-05 09:33:53 +05:30
}
2024-03-05 18:37:57 +05:30
2025-02-20 07:56:25 +00:00
impl From<SendError<KeyboardEvent>> for EmulatorError {
2024-03-05 18:37:57 +05:30
fn from(value: SendError<KeyboardEvent>) -> Self {
2025-02-20 07:56:25 +00:00
Self::IOError(format!(
"Failed to communicate keyboard event to main thread: {}",
value
))
}
}
#[cfg(test)]
mod tests{
use std::time::Duration;
use super::DeviceConfig;
#[test]
fn test_device_config_all_false(){
let device_config = DeviceConfig::new(false, false, false, 800);
assert_eq!(false,device_config.is_new_chip8());
assert_eq!(false,device_config.should_halt_on_invalid());
assert!(device_config.get_throttling_config().is_none());
}
#[test]
fn test_device_config_throttling_enabled_and_new_chip8(){
let device_config = DeviceConfig::new(true, false, true, 100);
const EXPECTED_INSTRUCTION_TIME_MS:u64 = 10;
assert_eq!(true,device_config.is_new_chip8());
assert_eq!(false,device_config.should_halt_on_invalid());
assert_eq!(Some(Duration::from_millis(EXPECTED_INSTRUCTION_TIME_MS)),device_config.get_throttling_config());
2024-03-05 18:37:57 +05:30
}
}