#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Rom {
nibbles: Vec<u8>,
}
impl Rom {
pub fn from_packed(bytes: &[u8]) -> Self {
let nibbles = bytes.iter().flat_map(|&b| [b & 0xF, b >> 4]).collect();
Self { nibbles }
}
pub fn from_nibbles(mut nibbles: Vec<u8>) -> Self {
for n in &mut nibbles {
*n &= 0xF;
}
Self { nibbles }
}
pub fn read(&self, addr: u32) -> u8 {
if self.nibbles.is_empty() {
return 0;
}
self.nibbles[addr as usize % self.nibbles.len()]
}
pub fn as_slice(&self) -> &[u8] {
&self.nibbles
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn packed_low_nibble_first() {
let rom = Rom::from_packed(&[0x32, 0x96]);
assert_eq!(rom.as_slice(), &[2, 3, 6, 9]);
assert_eq!(rom.as_slice().len(), 4);
}
#[test]
fn reads_mirror() {
let rom = Rom::from_packed(&[0x32, 0x96]);
assert_eq!(rom.read(0), 2);
assert_eq!(rom.read(3), 9);
assert_eq!(rom.read(4), 2);
assert_eq!(rom.read(7), 9);
assert_eq!(rom.read(0xF_FFFF), 9);
}
#[test]
fn from_nibbles_masks() {
let rom = Rom::from_nibbles(vec![0x1F, 0xA0]);
assert_eq!(rom.as_slice(), &[0xF, 0x0]);
}
#[test]
fn empty_reads_zero() {
let rom = Rom::from_nibbles(Vec::new());
assert!(rom.as_slice().is_empty());
assert_eq!(rom.read(123), 0);
}
}