1use std::io::{self, Read, Seek, SeekFrom};
23use std::sync::{Arc, Mutex};
24
25#[derive(Debug)]
32pub struct SectionReader<R> {
33 source: Arc<Mutex<R>>,
34 start: u64,
35 len: u64,
36 pos: u64,
37}
38
39impl<R> Clone for SectionReader<R> {
40 fn clone(&self) -> Self {
41 Self {
42 source: Arc::clone(&self.source),
43 start: self.start,
44 len: self.len,
45 pos: self.pos,
46 }
47 }
48}
49
50impl<R> SectionReader<R> {
51 pub fn new(source: Arc<Mutex<R>>, start: u64, len: u64) -> Self {
57 Self {
58 source,
59 start,
60 len,
61 pos: 0,
62 }
63 }
64
65 pub fn whole(source: Arc<Mutex<R>>, len: u64) -> Self {
67 Self::new(source, 0, len)
68 }
69
70 pub fn section(&self, offset: u64, len: u64) -> Option<Self> {
76 let end = offset.checked_add(len)?;
77 if end > self.len {
78 return None;
79 }
80 Some(Self {
81 source: Arc::clone(&self.source),
82 start: self.start.checked_add(offset)?,
83 len,
84 pos: 0,
85 })
86 }
87
88 pub fn len(&self) -> u64 {
90 self.len
91 }
92
93 pub fn is_empty(&self) -> bool {
95 self.len == 0
96 }
97
98 pub fn position(&self) -> u64 {
100 self.pos
101 }
102}
103
104impl<R: Read + Seek> SectionReader<R> {
105 pub fn read_all(&self) -> io::Result<Vec<u8>> {
118 let capacity = usize::try_from(self.len).map_err(|_| {
119 io::Error::new(
120 io::ErrorKind::InvalidData,
121 "section length exceeds addressable memory",
122 )
123 })?;
124 let mut buf = vec![0u8; capacity];
125 let mut cursor = Self {
128 source: Arc::clone(&self.source),
129 start: self.start,
130 len: self.len,
131 pos: 0,
132 };
133 cursor.read_exact(&mut buf)?;
134 Ok(buf)
135 }
136}
137
138impl<R: Read + Seek> Read for SectionReader<R> {
139 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
140 let remaining = self.len.saturating_sub(self.pos);
141 if remaining == 0 || buf.is_empty() {
142 return Ok(0);
143 }
144
145 let cap = usize::try_from(remaining).unwrap_or(usize::MAX);
148 let take = buf.len().min(cap);
149
150 let offset = self
151 .start
152 .checked_add(self.pos)
153 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "section offset overflow"))?;
154
155 let mut source = self
159 .source
160 .lock()
161 .unwrap_or_else(|poisoned| poisoned.into_inner());
162 source.seek(SeekFrom::Start(offset))?;
163 let read = source.read(&mut buf[..take])?;
164 drop(source);
165
166 self.pos = self.pos.saturating_add(
167 u64::try_from(read)
168 .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "read length overflow"))?,
169 );
170 Ok(read)
171 }
172}
173
174impl<R: Read + Seek> Seek for SectionReader<R> {
175 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
176 let target = match pos {
177 SeekFrom::Start(offset) => i128::from(offset),
178 SeekFrom::End(offset) => i128::from(self.len) + i128::from(offset),
179 SeekFrom::Current(offset) => i128::from(self.pos) + i128::from(offset),
180 };
181
182 if target < 0 {
183 return Err(io::Error::new(
184 io::ErrorKind::InvalidInput,
185 "cannot seek before the start of a section",
186 ));
187 }
188
189 self.pos = u64::try_from(target)
192 .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "seek position overflow"))?;
193 Ok(self.pos)
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use std::io::Cursor;
201
202 fn source(bytes: &[u8]) -> Arc<Mutex<Cursor<Vec<u8>>>> {
203 Arc::new(Mutex::new(Cursor::new(bytes.to_vec())))
204 }
205
206 #[test]
207 fn reads_only_within_the_window() {
208 let src = source(b"0123456789");
209 let mut window = SectionReader::new(src, 3, 4);
210
211 let mut buf = Vec::new();
212 window.read_to_end(&mut buf).expect("read within window");
213
214 assert_eq!(buf, b"3456");
215 }
216
217 #[test]
218 fn read_stops_at_the_window_end_not_the_source_end() {
219 let src = source(b"0123456789");
220 let window = SectionReader::new(src, 0, 4);
221
222 let mut buf = [0u8; 10];
223 let mut cursor = window;
224 let read = cursor.read(&mut buf).expect("bounded read");
225
226 assert_eq!(read, 4);
227 assert_eq!(&buf[..4], b"0123");
228 }
229
230 #[test]
231 fn positions_are_window_relative() {
232 let src = source(b"0123456789");
233 let mut window = SectionReader::new(src, 5, 5);
234
235 assert_eq!(window.seek(SeekFrom::Start(0)).expect("seek start"), 0);
236 let mut byte = [0u8; 1];
237 window.read_exact(&mut byte).expect("read first byte");
238 assert_eq!(&byte, b"5");
239
240 assert_eq!(window.seek(SeekFrom::End(-1)).expect("seek end"), 4);
241 window.read_exact(&mut byte).expect("read last byte");
242 assert_eq!(&byte, b"9");
243 }
244
245 #[test]
246 fn seeking_before_the_window_start_is_rejected() {
247 let src = source(b"0123456789");
248 let mut window = SectionReader::new(src, 5, 5);
249
250 let err = window
251 .seek(SeekFrom::Current(-1))
252 .expect_err("negative seek");
253
254 assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
255 }
256
257 #[test]
258 fn seeking_past_the_end_reads_nothing() {
259 let src = source(b"0123456789");
260 let mut window = SectionReader::new(src, 0, 4);
261
262 window.seek(SeekFrom::Start(99)).expect("seek past end");
263 let mut buf = [0u8; 4];
264
265 assert_eq!(window.read(&mut buf).expect("read past end"), 0);
266 }
267
268 #[test]
269 fn sections_nest_against_the_same_source() {
270 let src = source(b"0123456789");
271 let outer = SectionReader::new(src, 2, 6);
272
273 let inner = outer.section(1, 3).expect("nested window in bounds");
274
275 assert_eq!(inner.read_all().expect("read nested"), b"345");
276 }
277
278 #[test]
279 fn a_section_reaching_past_its_parent_is_rejected() {
280 let src = source(b"0123456789");
281 let outer = SectionReader::new(src, 2, 4);
282
283 assert!(outer.section(2, 3).is_none());
284 assert!(outer.section(0, 5).is_none());
285 assert!(outer.section(u64::MAX, 1).is_none());
286 }
287
288 #[test]
289 fn independent_cursors_share_one_handle_without_interfering() {
290 let src = source(b"0123456789");
293 let mut first = SectionReader::new(Arc::clone(&src), 0, 5);
294 let mut second = SectionReader::new(src, 5, 5);
295
296 let mut a = [0u8; 2];
297 let mut b = [0u8; 2];
298 first.read_exact(&mut a).expect("first window read");
299 second.read_exact(&mut b).expect("second window read");
300 assert_eq!(&a, b"01");
301 assert_eq!(&b, b"56");
302
303 first.read_exact(&mut a).expect("first window resumes");
304 second.read_exact(&mut b).expect("second window resumes");
305 assert_eq!(&a, b"23");
306 assert_eq!(&b, b"78");
307 }
308
309 #[test]
310 fn read_all_ignores_the_current_position() {
311 let src = source(b"0123456789");
312 let mut window = SectionReader::new(src, 0, 4);
313 window.seek(SeekFrom::Start(2)).expect("advance cursor");
314
315 assert_eq!(window.read_all().expect("read all"), b"0123");
316 }
317
318 #[test]
319 fn an_empty_window_reads_nothing() {
320 let src = source(b"0123456789");
321 let window = SectionReader::new(src, 4, 0);
322
323 assert!(window.is_empty());
324 assert_eq!(window.read_all().expect("read empty"), b"");
325 }
326}