Skip to main content

macbinary/
reader.rs

1use std::io::{self, SeekFrom};
2
3pub struct Reader<R> {
4    inner: R,
5    start: u64,
6    end: u64,
7}
8
9impl<R: io::Read + io::Seek> Reader<R> {
10    pub fn try_new(mut inner: R, start: u64, end: u64) -> io::Result<Self> {
11        assert!(start <= end);
12        inner.seek(SeekFrom::Start(start))?;
13
14        Ok(Self { inner, start, end })
15    }
16}
17
18impl<R: io::Read + io::Seek> io::Read for Reader<R> {
19    #[inline]
20    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
21        let mut position = self.inner.stream_position()?;
22
23        // Try to correct faulty position
24        if position < self.start {
25            position = self.inner.seek(SeekFrom::Start(self.start))?;
26        }
27
28        // Report error if position could not be corrected
29        if position < self.start {
30            return Err(io::Error::new(
31                io::ErrorKind::Unsupported,
32                "Can not read before start of substream",
33            ));
34        }
35
36        // No more bytes available
37        if position >= self.end {
38            return Ok(0);
39        }
40
41        let available_bytes = self.end - position;
42
43        // Enough bytes should be available
44        if available_bytes >= buf.len() as u64 {
45            return self.inner.read(buf);
46        }
47
48        // Cap reading at end of substream
49        self.inner.read(&mut buf[0..(available_bytes as usize)])
50    }
51}
52
53impl<R: io::Seek> io::Seek for Reader<R> {
54    #[inline]
55    fn stream_len(&mut self) -> io::Result<u64> {
56        Ok(self.end - self.start)
57    }
58
59    #[inline]
60    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
61        match pos {
62            SeekFrom::Start(offset) => {
63                let result = self.inner.seek(SeekFrom::Start(self.start + offset))?;
64                if self.start <= result {
65                    return Ok(result - self.start);
66                }
67
68                Ok(self.end)
69            }
70            SeekFrom::End(end) => {
71                let target = self.end as i64 + end;
72                if target < 0 {
73                    return Err(io::Error::new(
74                        io::ErrorKind::InvalidInput,
75                        "Can not seek before start of the stream",
76                    ));
77                }
78                self.seek(SeekFrom::Start(target as u64))
79            }
80            SeekFrom::Current(relative) => {
81                let current = self.stream_position()?;
82                let new = current as i64 + relative;
83                if new < 0 {
84                    return Err(io::Error::new(
85                        io::ErrorKind::InvalidInput,
86                        "Can not seek before start of the stream",
87                    ));
88                }
89
90                self.seek(SeekFrom::Start(new as u64))
91            }
92        }
93    }
94
95    #[inline]
96    fn stream_position(&mut self) -> io::Result<u64> {
97        let pos = self.inner.stream_position()?;
98        if self.start <= pos {
99            return Ok(pos - self.start);
100        }
101
102        Err(io::Error::new(
103            io::ErrorKind::InvalidInput,
104            "Can not seek before start of the stream",
105        ))
106    }
107}
108
109#[cfg(test)]
110mod test {
111    use std::io::{self, Read};
112
113    use crate::Reader;
114
115    #[test]
116    fn empty() {
117        let mut buffer = [0xAB; 12];
118
119        let inner = io::Cursor::new(b"");
120        let mut reader = Reader::try_new(inner, 0, 0).unwrap();
121        assert!(matches!(reader.read(&mut buffer), Ok(0)));
122
123        let inner = io::Cursor::new(b"");
124        let mut reader = Reader::try_new(inner, 0, 10).unwrap();
125        assert!(matches!(reader.read(&mut buffer), Ok(0)));
126
127        let inner = io::Cursor::new(b"");
128        let mut reader = Reader::try_new(inner, 5, 10).unwrap();
129        assert!(matches!(reader.read(&mut buffer), Ok(0)));
130    }
131
132    #[test]
133    fn simple() {
134        let mut buffer = [0xAB; 1];
135        let inner = io::Cursor::new(b"\x01\x02\x03\x04\x05");
136        let mut reader = Reader::try_new(inner, 1, 2).unwrap();
137        assert!(matches!(reader.read(&mut buffer), Ok(1)));
138        assert_eq!(buffer, [0x02]);
139
140        let mut buffer = [0xAB; 3];
141        let inner = io::Cursor::new(b"\x01\x02\x03\x04\x05");
142        let mut reader = Reader::try_new(inner, 2, 5).unwrap();
143        assert!(matches!(reader.read(&mut buffer), Ok(3)));
144        assert_eq!(buffer, [0x03, 0x04, 0x05]);
145    }
146
147    #[test]
148    fn capping() {
149        let mut buffer = [0xAB; 3];
150        let inner = io::Cursor::new(b"\x01\x02\x03\x04\x05");
151        let mut reader = Reader::try_new(inner, 1, 1).unwrap();
152        assert!(matches!(reader.read(&mut buffer), Ok(0)));
153
154        let mut buffer = [0xAB; 3];
155        let inner = io::Cursor::new(b"\x01\x02\x03\x04\x05");
156        let mut reader = Reader::try_new(inner, 1, 2).unwrap();
157        assert!(matches!(reader.read(&mut buffer), Ok(1)));
158        assert_eq!(buffer, [0x02, 0xAB, 0xAB]);
159
160        let mut buffer = [0xAB; 3];
161        let inner = io::Cursor::new(b"\x01\x02\x03\x04\x05");
162        let mut reader = Reader::try_new(inner, 1, 3).unwrap();
163        assert!(matches!(reader.read(&mut buffer), Ok(2)));
164        assert_eq!(buffer, [0x02, 0x03, 0xAB]);
165    }
166}