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 if position < self.start {
25 position = self.inner.seek(SeekFrom::Start(self.start))?;
26 }
27
28 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 if position >= self.end {
38 return Ok(0);
39 }
40
41 let available_bytes = self.end - position;
42
43 if available_bytes >= buf.len() as u64 {
45 return self.inner.read(buf);
46 }
47
48 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}