use crate::common::BLOCK_SIZE;
use super::{EXAMPLE_EXFAT_IMAGE, print};
use aligned::{A4, Aligned};
use block_device_driver::{blocks_to_slice, blocks_to_slice_mut};
use exfat_slim::blocking::BlockDevice;
use flate2::read::GzDecoder;
use std::{
fs,
io::Read,
sync::{Arc, Mutex},
};
#[derive(Clone, Debug)]
pub struct InMemoryBlockDevice {
inner: Arc<Mutex<Inner>>,
}
impl InMemoryBlockDevice {
pub fn new() -> Self {
let inner = Arc::new(Mutex::new(Inner::new()));
Self { inner }
}
}
impl BlockDevice<BLOCK_SIZE> for InMemoryBlockDevice {
type Error = String;
type Align = A4;
fn read(
&mut self,
sector_id: u32,
block: &mut [Aligned<Self::Align, [u8; BLOCK_SIZE]>],
) -> Result<(), Self::Error> {
let mut g = self.inner.lock().unwrap();
g.read_sector(sector_id, block)
}
fn write(
&mut self,
sector_id: u32,
block: &[Aligned<Self::Align, [u8; BLOCK_SIZE]>],
) -> Result<(), Self::Error> {
let mut g = self.inner.lock().unwrap();
g.write_sector(sector_id, block)
}
fn size(&mut self) -> Result<u64, Self::Error> {
todo!()
}
}
#[derive(Debug)]
pub struct Inner {
pub image: Vec<u8>,
pub sector_offset: u32,
pub data_block: [u8; BLOCK_SIZE],
last_sector: Option<u32>,
}
impl Inner {
pub fn new() -> Self {
let buf = fs::read(EXAMPLE_EXFAT_IMAGE).unwrap();
let mut reader = GzDecoder::new(buf.as_slice());
let mut image = Vec::new();
reader.read_to_end(&mut image).unwrap();
Self {
image,
sector_offset: 0,
data_block: [0; BLOCK_SIZE],
last_sector: None,
}
}
pub fn read_sector(
&mut self,
sector_id: u32,
block: &mut [Aligned<A4, [u8; BLOCK_SIZE]>],
) -> Result<(), String> {
let sector_id_with_offset = sector_id + self.sector_offset;
match self.last_sector.as_ref() {
Some(x) if *x == sector_id_with_offset => {
print("READ", sector_id_with_offset, sector_id, true)
}
_ => {
print("READ", sector_id_with_offset, sector_id, false);
self.last_sector = Some(sector_id_with_offset);
}
}
let pos = sector_id_with_offset as usize * BLOCK_SIZE;
let slice = blocks_to_slice_mut(block);
slice.copy_from_slice(&self.image[pos..pos + BLOCK_SIZE]);
Ok(())
}
pub fn write_sector(
&mut self,
sector_id: u32,
block: &[Aligned<A4, [u8; BLOCK_SIZE]>],
) -> Result<(), String> {
let sector_id_with_offset = sector_id + self.sector_offset;
print("WRITE", sector_id_with_offset, sector_id, false);
let start = sector_id_with_offset as usize * BLOCK_SIZE;
let end = start + BLOCK_SIZE;
let max_len = self.image.len();
if end <= max_len {
let slice = blocks_to_slice(block);
self.image[start..end].copy_from_slice(slice);
self.last_sector = None;
Ok(())
} else {
let error = format!(
"attempt to write past end of image of len {}: {}",
max_len, end
);
Err(error)
}
}
}