1#![deny(missing_docs)]
6
7#[cfg(feature = "mmap")]
8use memmap2::{MmapMut, MmapOptions};
9use std::fs::File;
10use std::io::{Read, Seek, SeekFrom, Write};
11
12use rlvgl_core::fs::{BlockDevice, FsError};
13
14pub struct SimBlockDevice {
16 file: File,
18 #[cfg(feature = "mmap")]
20 mmap: Option<MmapMut>,
21 block_size: usize,
23 num_blocks: u64,
25}
26
27impl SimBlockDevice {
28 pub fn new(file: File, block_size: usize) -> Result<Self, FsError> {
32 let len = file.metadata().map_err(|_| FsError::Device)?.len();
33 if block_size == 0 || len % block_size as u64 != 0 {
34 return Err(FsError::InvalidPath);
35 }
36 #[cfg(feature = "mmap")]
37 let mmap = unsafe { MmapOptions::new().map_mut(&file).ok() };
38 Ok(Self {
39 file,
40 #[cfg(feature = "mmap")]
41 mmap,
42 block_size,
43 num_blocks: len / block_size as u64,
44 })
45 }
46}
47
48impl BlockDevice for SimBlockDevice {
49 fn read_blocks(&mut self, lba: u64, buf: &mut [u8]) -> Result<(), FsError> {
50 let offset = lba
51 .checked_mul(self.block_size as u64)
52 .ok_or(FsError::Device)?;
53 #[cfg(feature = "mmap")]
54 if let Some(mmap) = self.mmap.as_ref() {
55 let start = offset as usize;
56 let end = start.checked_add(buf.len()).ok_or(FsError::Device)?;
57 buf.copy_from_slice(&mmap[start..end]);
58 return Ok(());
59 }
60 self.file
61 .seek(SeekFrom::Start(offset))
62 .map_err(|_| FsError::Device)?;
63 self.file.read_exact(buf).map_err(|_| FsError::Device)
64 }
65
66 fn write_blocks(&mut self, lba: u64, buf: &[u8]) -> Result<(), FsError> {
67 let offset = lba
68 .checked_mul(self.block_size as u64)
69 .ok_or(FsError::Device)?;
70 #[cfg(feature = "mmap")]
71 if let Some(mmap) = self.mmap.as_mut() {
72 let start = offset as usize;
73 let end = start.checked_add(buf.len()).ok_or(FsError::Device)?;
74 mmap[start..end].copy_from_slice(buf);
75 return Ok(());
76 }
77 self.file
78 .seek(SeekFrom::Start(offset))
79 .map_err(|_| FsError::Device)?;
80 self.file.write_all(buf).map_err(|_| FsError::Device)
81 }
82
83 fn block_size(&self) -> usize {
84 self.block_size
85 }
86
87 fn num_blocks(&self) -> u64 {
88 self.num_blocks
89 }
90
91 fn flush(&mut self) -> Result<(), FsError> {
92 #[cfg(feature = "mmap")]
93 if let Some(mmap) = self.mmap.as_mut() {
94 mmap.flush().map_err(|_| FsError::Device)?;
95 }
96 self.file.flush().map_err(|_| FsError::Device)
97 }
98}