Skip to main content

hadris_iso/
io.rs

1use core::{
2    fmt,
3    ops::{Add, AddAssign},
4};
5
6pub use super::super::{Parsable, Read, ReadExt, Seek, Writable, Write};
7pub use hadris_io::{Error, ErrorKind, Result, SeekFrom, try_io_result_option};
8
9/// A Logical Sector, size has to be 2^n and > 2048
10#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
11pub struct LogicalSector(pub usize);
12
13impl Add<usize> for LogicalSector {
14    type Output = Self;
15
16    fn add(self, rhs: usize) -> Self::Output {
17        Self(self.0 + rhs)
18    }
19}
20
21impl AddAssign<usize> for LogicalSector {
22    fn add_assign(&mut self, rhs: usize) {
23        self.0 += rhs;
24    }
25}
26
27/// A Logical Sector, size has to be 2^n and > 512
28#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
29struct _LogicalBlock(pub usize);
30
31/// Represents IsoCursor.
32pub struct IsoCursor<DATA: Seek> {
33    /// The `data` field.
34    pub data: DATA,
35    /// The `sector_size` field.
36    pub sector_size: usize,
37}
38
39io_transform! {
40
41impl<DATA: Read + Seek> Read for IsoCursor<DATA> {
42    type Error = <DATA as Read>::Error;
43
44    async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
45        self.data.read(buf).await
46    }
47
48    async fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
49        self.data.read_exact(buf).await
50    }
51}
52
53impl<DATA: Seek> Seek for IsoCursor<DATA> {
54    type Error = DATA::Error;
55
56    async fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
57        self.data.seek(pos).await
58    }
59
60    async fn stream_position(&mut self) -> Result<u64, Self::Error> {
61        self.data.stream_position().await
62    }
63
64    async fn seek_relative(&mut self, offset: i64) -> Result<(), Self::Error> {
65        self.data.seek_relative(offset).await
66    }
67}
68
69impl<DATA: Seek> IsoCursor<DATA> {
70    /// Performs the `new` operation.
71    pub fn new(data: DATA, sector_size: usize) -> Self {
72        Self { data, sector_size }
73    }
74
75    /// Consumes the cursor and returns its underlying data source.
76    pub fn into_inner(self) -> DATA {
77        self.data
78    }
79
80    /// Performs the `seek_sector` operation.
81    pub async fn seek_sector(&mut self, sector: LogicalSector) -> Result<u64> {
82        self.seek(SeekFrom::Start(sector.0 as u64 * self.sector_size as u64))
83            .await
84            .map_err(Error::erase)
85    }
86}
87
88impl<DATA: Write + Seek> IsoCursor<DATA> {
89    /// Advance to the next sector boundary, zero-filling the gap.
90    ///
91    /// The gap is written rather than skipped with a seek: `Write + Seek`
92    /// targets are not guaranteed to read unwritten regions back as zeros
93    /// (reused buffers, block devices with stale data), and readers scan
94    /// some padding (e.g. the zero record-length terminator at the end of
95    /// a directory's sector span). Gaps are always smaller than one sector.
96    pub async fn pad_align_sector(&mut self) -> Result<LogicalSector> {
97        const ZEROES: [u8; 512] = [0u8; 512];
98        let stream_pos = self.stream_position().await.map_err(Error::erase)?;
99        let sector_size_minus_one = self.sector_size as u64 - 1;
100        let aligned_pos = (stream_pos + sector_size_minus_one) & !sector_size_minus_one;
101        let mut remaining = (aligned_pos - stream_pos) as usize;
102        while remaining > 0 {
103            let n = remaining.min(ZEROES.len());
104            self.write_all(&ZEROES[..n]).await.map_err(Error::erase)?;
105            remaining -= n;
106        }
107        Ok(LogicalSector(
108            (aligned_pos / self.sector_size as u64) as usize,
109        ))
110    }
111}
112
113impl<DATA: Write + Seek> Write for IsoCursor<DATA> {
114    type Error = <DATA as Write>::Error;
115
116    async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
117        self.data.write(buf).await
118    }
119
120    async fn flush(&mut self) -> Result<(), Self::Error> {
121        self.data.flush().await
122    }
123
124    async fn write_all(&mut self, buf: &[u8]) -> Result<()> {
125        self.data.write_all(buf).await
126    }
127}
128
129} // io_transform!
130
131impl<DATA: Seek> fmt::Debug for IsoCursor<DATA> {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        f.debug_struct("Cursor").finish()
134    }
135}