1use std::mem::MaybeUninit;
2use std::slice::from_raw_parts;
3
4use std::io::SeekFrom;
5use std::path::Path;
6#[cfg(not(feature = "async"))]
7use std::{fs, io::prelude::*};
8
9#[cfg(all(feature = "async", feature = "smol"))]
10use smol::fs;
11#[cfg(all(feature = "async", feature = "smol"))]
12use smol::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
13#[cfg(all(feature = "async", feature = "tokio"))]
14use tokio::fs;
15#[cfg(all(feature = "async", feature = "tokio"))]
16use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
17
18#[cfg(feature = "async")]
19use async_trait::async_trait;
20
21use crate::types::SectorID;
22
23const MAX_SECTOR_SIZE: usize = 4096;
24
25#[derive(Debug)]
26pub struct FileIO {
27 file: fs::File,
28 sector_size_shift: u8,
29 buffer: MaybeUninit<[u8; MAX_SECTOR_SIZE]>,
30}
31
32#[cfg_attr(not(feature = "async"), deasync::deasync)]
33impl FileIO {
34 pub async fn open<P: AsRef<Path>>(filepath: P) -> std::io::Result<Self> {
35 let mut options = match () {
36 #[cfg(feature = "async")]
37 () => fs::OpenOptions::new(),
38 #[cfg(not(feature = "async"))]
39 () => fs::File::options(),
40 };
41 let file = options.read(true).write(true).open(filepath).await?;
42 Ok(Self { file, sector_size_shift: 9, buffer: MaybeUninit::uninit() })
43 }
44}
45
46#[cfg_attr(feature = "async", async_trait)]
47#[cfg_attr(not(feature = "async"), deasync::deasync)]
48impl super::IO for FileIO {
49 type Error = std::io::Error;
50
51 fn set_sector_size_shift(&mut self, shift: u8) -> Result<(), Self::Error> {
52 self.sector_size_shift = shift;
53 Ok(())
54 }
55
56 async fn read<'a>(&'a mut self, sector: SectorID) -> Result<&'a [[u8; 512]], Self::Error> {
57 let sector_size: usize = 1 << self.sector_size_shift;
58 let seek = SeekFrom::Start(u64::from(sector) * sector_size as u64);
59
60 self.file.seek(seek).await?;
61 let buffer = unsafe { self.buffer.assume_init_mut() };
62 self.file.read_exact(&mut buffer[..sector_size]).await?;
63
64 Ok(unsafe { from_raw_parts(buffer.as_ptr() as *const _, sector_size / 512) })
65 }
66
67 async fn write(
68 &mut self,
69 sector: SectorID,
70 offset: usize,
71 buf: &[u8],
72 ) -> Result<(), Self::Error> {
73 let sector_size = 1 << self.sector_size_shift;
74 let seek = SeekFrom::Start(u64::from(sector) * sector_size + offset as u64);
75 self.file.seek(seek).await?;
76 self.file.write_all(buf).await.map(|_| ())
77 }
78
79 async fn flush(&mut self) -> Result<(), Self::Error> {
80 self.file.flush().await
81 }
82}