use std::io::prelude::*;
use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx};
pub static DISK_SOURCE: &[u8] = include_bytes!("../disk.img.gz");
#[derive(Debug)]
#[allow(dead_code)]
pub enum Error {
Io(std::io::Error),
Decode(flate2::DecompressError),
OutOfBounds(BlockIdx),
}
impl From<std::io::Error> for Error {
fn from(value: std::io::Error) -> Self {
Self::Io(value)
}
}
impl From<flate2::DecompressError> for Error {
fn from(value: flate2::DecompressError) -> Self {
Self::Decode(value)
}
}
pub struct RamDisk<T> {
contents: std::cell::RefCell<T>,
}
impl<T> RamDisk<T> {
fn new(contents: T) -> RamDisk<T> {
RamDisk {
contents: std::cell::RefCell::new(contents),
}
}
}
impl<T> BlockDevice for RamDisk<T>
where
T: AsMut<[u8]> + AsRef<[u8]>,
{
type Error = Error;
fn read(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> {
let borrow = self.contents.borrow();
let contents: &[u8] = borrow.as_ref();
let mut block_idx = start_block_idx;
for block in blocks.iter_mut() {
let start_offset = block_idx.0 as usize * embedded_sdmmc::Block::LEN;
let end_offset = start_offset + embedded_sdmmc::Block::LEN;
if end_offset > contents.len() {
return Err(Error::OutOfBounds(block_idx));
}
block
.as_mut_slice()
.copy_from_slice(&contents[start_offset..end_offset]);
block_idx.0 += 1;
}
Ok(())
}
fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> {
let mut borrow = self.contents.borrow_mut();
let contents: &mut [u8] = borrow.as_mut();
let mut block_idx = start_block_idx;
for block in blocks.iter() {
let start_offset = block_idx.0 as usize * embedded_sdmmc::Block::LEN;
let end_offset = start_offset + embedded_sdmmc::Block::LEN;
if end_offset > contents.len() {
return Err(Error::OutOfBounds(block_idx));
}
contents[start_offset..end_offset].copy_from_slice(block.as_slice());
block_idx.0 += 1;
}
Ok(())
}
fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
let borrow = self.contents.borrow();
let contents: &[u8] = borrow.as_ref();
let len_blocks = contents.len() / embedded_sdmmc::Block::LEN;
if len_blocks > u32::MAX as usize {
panic!("Test disk too large! Only 2**32 blocks allowed");
}
Ok(BlockCount(len_blocks as u32))
}
}
fn unpack_disk(gzip_bytes: &[u8]) -> Result<Vec<u8>, Error> {
let disk_cursor = std::io::Cursor::new(gzip_bytes);
let mut gz_decoder = flate2::read::GzDecoder::new(disk_cursor);
let mut output = Vec::with_capacity(512 * 1024 * 1024);
gz_decoder.read_to_end(&mut output)?;
Ok(output)
}
pub fn make_block_device(gzip_bytes: &[u8]) -> Result<RamDisk<Vec<u8>>, Error> {
let data = unpack_disk(gzip_bytes)?;
Ok(RamDisk::new(data))
}
pub struct TestTimeSource {
fixed: embedded_sdmmc::Timestamp,
}
impl embedded_sdmmc::TimeSource for TestTimeSource {
fn get_timestamp(&self) -> embedded_sdmmc::Timestamp {
self.fixed
}
}
pub fn make_time_source() -> TestTimeSource {
TestTimeSource {
fixed: embedded_sdmmc::Timestamp {
year_since_1970: 33,
zero_indexed_month: 3,
zero_indexed_day: 3,
hours: 13,
minutes: 30,
seconds: 5,
},
}
}
#[allow(unused)]
pub fn get_time_source_string() -> &'static str {
"2003-04-04 13:30:04"
}