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>> {
111 let capacity = usize::try_from(self.len).map_err(|_| {
112 io::Error::new(
113 io::ErrorKind::InvalidData,
114 "section length exceeds addressable memory",
115 )
116 })?;
117 let mut buf = vec![0u8; capacity];
118 let mut cursor = Self {
121 source: Arc::clone(&self.source),
122 start: self.start,
123 len: self.len,
124 pos: 0,
125 };
126 cursor.read_exact(&mut buf)?;
127 Ok(buf)
128 }
129}
130
131impl<R: Read + Seek> Read for SectionReader<R> {
132 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
133 let remaining = self.len.saturating_sub(self.pos);
134 if remaining == 0 || buf.is_empty() {
135 return Ok(0);
136 }
137
138 let cap = usize::try_from(remaining).unwrap_or(usize::MAX);
141 let take = buf.len().min(cap);
142
143 let offset = self
144 .start
145 .checked_add(self.pos)
146 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "section offset overflow"))?;
147
148 let mut source = self
152 .source
153 .lock()
154 .unwrap_or_else(|poisoned| poisoned.into_inner());
155 source.seek(SeekFrom::Start(offset))?;
156 let read = source.read(&mut buf[..take])?;
157 drop(source);
158
159 self.pos = self.pos.saturating_add(
160 u64::try_from(read)
161 .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "read length overflow"))?,
162 );
163 Ok(read)
164 }
165}
166
167impl<R: Read + Seek> Seek for SectionReader<R> {
168 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
169 let target = match pos {
170 SeekFrom::Start(offset) => i128::from(offset),
171 SeekFrom::End(offset) => i128::from(self.len) + i128::from(offset),
172 SeekFrom::Current(offset) => i128::from(self.pos) + i128::from(offset),
173 };
174
175 if target < 0 {
176 return Err(io::Error::new(
177 io::ErrorKind::InvalidInput,
178 "cannot seek before the start of a section",
179 ));
180 }
181
182 self.pos = u64::try_from(target)
185 .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "seek position overflow"))?;
186 Ok(self.pos)
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193 use std::io::Cursor;
194
195 fn source(bytes: &[u8]) -> Arc<Mutex<Cursor<Vec<u8>>>> {
196 Arc::new(Mutex::new(Cursor::new(bytes.to_vec())))
197 }
198
199 #[test]
200 fn reads_only_within_the_window() {
201 let src = source(b"0123456789");
202 let mut window = SectionReader::new(src, 3, 4);
203
204 let mut buf = Vec::new();
205 window.read_to_end(&mut buf).expect("read within window");
206
207 assert_eq!(buf, b"3456");
208 }
209
210 #[test]
211 fn read_stops_at_the_window_end_not_the_source_end() {
212 let src = source(b"0123456789");
213 let window = SectionReader::new(src, 0, 4);
214
215 let mut buf = [0u8; 10];
216 let mut cursor = window;
217 let read = cursor.read(&mut buf).expect("bounded read");
218
219 assert_eq!(read, 4);
220 assert_eq!(&buf[..4], b"0123");
221 }
222
223 #[test]
224 fn positions_are_window_relative() {
225 let src = source(b"0123456789");
226 let mut window = SectionReader::new(src, 5, 5);
227
228 assert_eq!(window.seek(SeekFrom::Start(0)).expect("seek start"), 0);
229 let mut byte = [0u8; 1];
230 window.read_exact(&mut byte).expect("read first byte");
231 assert_eq!(&byte, b"5");
232
233 assert_eq!(window.seek(SeekFrom::End(-1)).expect("seek end"), 4);
234 window.read_exact(&mut byte).expect("read last byte");
235 assert_eq!(&byte, b"9");
236 }
237
238 #[test]
239 fn seeking_before_the_window_start_is_rejected() {
240 let src = source(b"0123456789");
241 let mut window = SectionReader::new(src, 5, 5);
242
243 let err = window
244 .seek(SeekFrom::Current(-1))
245 .expect_err("negative seek");
246
247 assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
248 }
249
250 #[test]
251 fn seeking_past_the_end_reads_nothing() {
252 let src = source(b"0123456789");
253 let mut window = SectionReader::new(src, 0, 4);
254
255 window.seek(SeekFrom::Start(99)).expect("seek past end");
256 let mut buf = [0u8; 4];
257
258 assert_eq!(window.read(&mut buf).expect("read past end"), 0);
259 }
260
261 #[test]
262 fn sections_nest_against_the_same_source() {
263 let src = source(b"0123456789");
264 let outer = SectionReader::new(src, 2, 6);
265
266 let inner = outer.section(1, 3).expect("nested window in bounds");
267
268 assert_eq!(inner.read_all().expect("read nested"), b"345");
269 }
270
271 #[test]
272 fn a_section_reaching_past_its_parent_is_rejected() {
273 let src = source(b"0123456789");
274 let outer = SectionReader::new(src, 2, 4);
275
276 assert!(outer.section(2, 3).is_none());
277 assert!(outer.section(0, 5).is_none());
278 assert!(outer.section(u64::MAX, 1).is_none());
279 }
280
281 #[test]
282 fn independent_cursors_share_one_handle_without_interfering() {
283 let src = source(b"0123456789");
286 let mut first = SectionReader::new(Arc::clone(&src), 0, 5);
287 let mut second = SectionReader::new(src, 5, 5);
288
289 let mut a = [0u8; 2];
290 let mut b = [0u8; 2];
291 first.read_exact(&mut a).expect("first window read");
292 second.read_exact(&mut b).expect("second window read");
293 assert_eq!(&a, b"01");
294 assert_eq!(&b, b"56");
295
296 first.read_exact(&mut a).expect("first window resumes");
297 second.read_exact(&mut b).expect("second window resumes");
298 assert_eq!(&a, b"23");
299 assert_eq!(&b, b"78");
300 }
301
302 #[test]
303 fn read_all_ignores_the_current_position() {
304 let src = source(b"0123456789");
305 let mut window = SectionReader::new(src, 0, 4);
306 window.seek(SeekFrom::Start(2)).expect("advance cursor");
307
308 assert_eq!(window.read_all().expect("read all"), b"0123");
309 }
310
311 #[test]
312 fn an_empty_window_reads_nothing() {
313 let src = source(b"0123456789");
314 let window = SectionReader::new(src, 4, 0);
315
316 assert!(window.is_empty());
317 assert_eq!(window.read_all().expect("read empty"), b"");
318 }
319}