1use std::fs::File;
5use std::io::{self, Read, Seek, SeekFrom};
6use std::path::Path;
7use std::sync::Mutex;
8
9use crate::error::{io_err, VfsResult};
10use crate::source::{DynSource, ImageSource, SourceId};
11
12pub struct SubRange {
17 parent: DynSource,
18 base: u64,
19 len: u64,
20}
21
22impl SubRange {
23 #[must_use]
26 pub fn new(parent: DynSource, base: u64, len: u64) -> Self {
27 let available = parent.len().saturating_sub(base);
28 Self {
29 parent,
30 base,
31 len: len.min(available),
32 }
33 }
34}
35
36impl ImageSource for SubRange {
37 fn len(&self) -> u64 {
38 self.len
39 }
40
41 fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult<usize> {
42 if offset >= self.len {
43 return Ok(0);
44 }
45 let remaining = self.len - offset;
46 let want = (buf.len() as u64).min(remaining) as usize;
47 let Some(dst) = buf.get_mut(..want) else {
48 return Ok(0); };
50 let abs = self.base.saturating_add(offset);
51 self.parent.read_at(abs, dst)
52 }
53
54 fn source_id(&self) -> SourceId {
55 self.parent.source_id()
57 }
58}
59
60pub struct FileSource {
64 file: File,
65 len: u64,
66}
67
68impl FileSource {
69 pub fn open(path: impl AsRef<Path>) -> VfsResult<Self> {
71 let file = File::open(path).map_err(io_err("open"))?;
72 Self::from_file(file)
73 }
74
75 pub fn from_file(file: File) -> VfsResult<Self> {
77 let len = file.metadata().map_err(io_err("metadata"))?.len();
78 Ok(Self { file, len })
79 }
80}
81
82impl ImageSource for FileSource {
83 fn len(&self) -> u64 {
84 self.len
85 }
86
87 fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult<usize> {
88 if offset >= self.len {
89 return Ok(0);
90 }
91 #[cfg(unix)]
94 {
95 use std::os::unix::fs::FileExt;
96 self.file.read_at(buf, offset).map_err(io_err("read_at"))
97 }
98 #[cfg(windows)]
99 {
100 use std::os::windows::fs::FileExt;
101 self.file
102 .seek_read(buf, offset)
103 .map_err(io_err("seek_read"))
104 }
105 #[cfg(not(any(unix, windows)))]
106 {
107 let _ = buf;
108 Err(crate::error::VfsError::Unsupported {
109 layer: "FileSource",
110 scheme: "positioned read".to_string(),
111 })
112 }
113 }
114}
115
116pub struct SourceCursor {
120 src: DynSource,
121 base: u64,
122 len: u64,
123 pos: u64,
124}
125
126impl SourceCursor {
127 #[must_use]
130 pub fn new(src: DynSource, base: u64, len: u64) -> Self {
131 let available = src.len().saturating_sub(base);
132 Self {
133 src,
134 base,
135 len: len.min(available),
136 pos: 0,
137 }
138 }
139}
140
141impl Read for SourceCursor {
142 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
143 if self.pos >= self.len {
144 return Ok(0);
145 }
146 let remaining = self.len - self.pos;
147 let want = (buf.len() as u64).min(remaining) as usize;
148 let Some(dst) = buf.get_mut(..want) else {
149 return Ok(0); };
151 let abs = self.base.saturating_add(self.pos);
152 let n = self.src.read_at(abs, dst).map_err(io::Error::other)?;
153 self.pos = self.pos.saturating_add(n as u64);
154 Ok(n)
155 }
156}
157
158impl Seek for SourceCursor {
159 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
160 let target: i128 = match pos {
162 SeekFrom::Start(o) => i128::from(o),
163 SeekFrom::End(o) => i128::from(self.len) + i128::from(o),
164 SeekFrom::Current(o) => i128::from(self.pos) + i128::from(o),
165 };
166 if target < 0 {
167 return Err(io::Error::new(
168 io::ErrorKind::InvalidInput,
169 "seek before start of window",
170 ));
171 }
172 self.pos = target.min(i128::from(u64::MAX)) as u64;
173 Ok(self.pos)
174 }
175}
176
177pub struct SeekPoolSource<R: Read + Seek + Send> {
183 pool: Vec<Mutex<R>>,
184 len: u64,
185}
186
187impl<R: Read + Seek + Send> SeekPoolSource<R> {
188 #[must_use]
190 pub fn new(readers: Vec<R>, len: u64) -> Self {
191 Self {
192 pool: readers.into_iter().map(Mutex::new).collect(),
193 len,
194 }
195 }
196
197 #[must_use]
199 pub fn single(reader: R, len: u64) -> Self {
200 Self::new(vec![reader], len)
201 }
202
203 fn checkout(&self) -> Option<std::sync::MutexGuard<'_, R>> {
204 for m in &self.pool {
205 if let Ok(g) = m.try_lock() {
206 return Some(g);
207 }
208 }
209 self.pool
212 .first()
213 .map(|m| m.lock().unwrap_or_else(std::sync::PoisonError::into_inner))
214 }
215}
216
217impl<R: Read + Seek + Send> ImageSource for SeekPoolSource<R> {
218 fn len(&self) -> u64 {
219 self.len
220 }
221
222 fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult<usize> {
223 if offset >= self.len {
224 return Ok(0);
225 }
226 let Some(mut guard) = self.checkout() else {
227 return Ok(0); };
229 guard
230 .seek(SeekFrom::Start(offset))
231 .map_err(io_err("seek"))?;
232 let remaining = self.len - offset;
233 let want = (buf.len() as u64).min(remaining) as usize;
234 let Some(dst) = buf.get_mut(..want) else {
235 return Ok(0); };
237 let mut total = 0;
239 while total < dst.len() {
240 let Some(slot) = dst.get_mut(total..) else {
241 break; };
243 let n = guard.read(slot).map_err(io_err("read"))?;
244 if n == 0 {
245 break;
246 }
247 total += n;
248 }
249 Ok(total)
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use std::io::{Read, Seek, SeekFrom};
256 use std::sync::Arc;
257
258 use crate::source::{DynSource, ImageSource, SourceId};
259
260 use super::{FileSource, SeekPoolSource, SourceCursor, SubRange};
261
262 fn mem(bytes: &[u8]) -> DynSource {
265 use std::io::Write;
266 let mut f = tempfile::tempfile().unwrap();
267 f.write_all(bytes).unwrap();
268 Arc::new(FileSource::from_file(f).unwrap())
269 }
270
271 #[test]
272 fn subrange_windows_the_parent() {
273 let base = mem(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
274 let sr = SubRange::new(base, 2, 5);
275 assert_eq!(sr.len(), 5);
276 let mut buf = [0u8; 5];
277 assert_eq!(sr.read_at(0, &mut buf).unwrap(), 5);
278 assert_eq!(buf, [2, 3, 4, 5, 6]);
279 let mut two = [0u8; 2];
281 assert_eq!(sr.read_at(3, &mut two).unwrap(), 2);
282 assert_eq!(two, [5, 6]);
283 }
284
285 #[test]
286 fn subrange_clamps_reads_to_the_window() {
287 let base = mem(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
288 let sr = SubRange::new(base, 2, 5); let mut buf = [0xffu8; 8];
290 assert_eq!(sr.read_at(3, &mut buf).unwrap(), 2);
292 assert_eq!(&buf[..2], &[5, 6]);
293 assert_eq!(sr.read_at(5, &mut buf).unwrap(), 0);
295 assert_eq!(sr.read_at(99, &mut buf).unwrap(), 0);
296 }
297
298 #[test]
299 fn subrange_len_is_clamped_to_parent_bounds() {
300 let base = mem(&[0, 1, 2, 3]);
301 let sr = SubRange::new(base, 2, 100);
303 assert_eq!(sr.len(), 2); }
305
306 #[test]
307 fn subrange_nests() {
308 let base = mem(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
309 let outer = Arc::new(SubRange::new(base, 2, 6)); let inner = SubRange::new(outer, 1, 3); let mut buf = [0u8; 3];
312 assert_eq!(inner.read_at(0, &mut buf).unwrap(), 3);
313 assert_eq!(buf, [3, 4, 5]);
314 }
315
316 #[test]
317 fn filesource_reads_by_position() {
318 let mut f = tempfile::NamedTempFile::new().unwrap();
319 std::io::Write::write_all(f.as_file_mut(), &[10, 20, 30, 40, 50]).unwrap();
320 let fs = FileSource::open(f.path()).unwrap();
321 assert_eq!(fs.len(), 5);
322 assert_eq!(fs.source_id(), SourceId::ROOT);
323 let mut buf = [0u8; 3];
324 assert_eq!(fs.read_at(1, &mut buf).unwrap(), 3);
325 assert_eq!(buf, [20, 30, 40]);
326 let mut tail = [0u8; 4];
328 assert_eq!(fs.read_at(3, &mut tail).unwrap(), 2);
329 assert_eq!(&tail[..2], &[40, 50]);
330 assert_eq!(fs.read_at(100, &mut buf).unwrap(), 0);
332 }
333
334 #[test]
335 fn sourcecursor_bridges_read_and_seek() {
336 let base = mem(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
337 let mut cur = SourceCursor::new(base, 2, 6); let mut first = [0u8; 3];
339 cur.read_exact(&mut first).unwrap();
340 assert_eq!(first, [2, 3, 4]);
341 assert_eq!(cur.seek(SeekFrom::Start(4)).unwrap(), 4);
343 let mut rest = Vec::new();
344 cur.read_to_end(&mut rest).unwrap();
345 assert_eq!(rest, vec![6, 7]);
346 assert_eq!(cur.seek(SeekFrom::End(0)).unwrap(), 6);
348 }
349 #[test]
350 fn seek_pool_source_bridges_read_seek_to_image_source() {
351 use std::io::Cursor;
352 let data: Vec<u8> = (0..=255).collect();
353 let len = data.len() as u64;
354 let pool = SeekPoolSource::new(
356 vec![Cursor::new(data.clone()), Cursor::new(data.clone())],
357 len,
358 );
359 assert_eq!(pool.len(), 256);
360 let mut buf = [0u8; 4];
361 assert_eq!(pool.read_at(10, &mut buf).unwrap(), 4);
362 assert_eq!(buf, [10, 11, 12, 13]);
363 assert_eq!(pool.read_at(256, &mut buf).unwrap(), 0);
365 let src: DynSource = Arc::new(SeekPoolSource::single(Cursor::new(data), len));
367 let mut b2 = [0u8; 2];
368 assert_eq!(src.read_at(254, &mut b2).unwrap(), 2);
369 assert_eq!(b2, [254, 255]);
370 }
371
372 #[test]
373 fn seek_pool_short_read_breaks_at_eof() {
374 use std::io::Cursor;
375 let pool = SeekPoolSource::single(Cursor::new(vec![1u8, 2, 3, 4]), 32);
379 let mut buf = [0u8; 16];
380 assert_eq!(pool.read_at(0, &mut buf).unwrap(), 4);
381 assert_eq!(&buf[..4], &[1, 2, 3, 4]);
382 }
383
384 #[test]
385 fn seek_pool_checkout_blocks_when_the_only_cursor_is_busy() {
386 use std::io::{self, Read, Seek, SeekFrom};
387 use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
388 use std::sync::{Arc, Mutex};
389
390 struct Parking {
395 data: Vec<u8>,
396 pos: usize,
397 entered: SyncSender<()>,
398 release: Arc<Mutex<Option<Receiver<()>>>>,
399 }
400 impl Read for Parking {
401 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
402 if let Some(rx) = self
404 .release
405 .lock()
406 .unwrap_or_else(std::sync::PoisonError::into_inner)
407 .take()
408 {
409 let _ = self.entered.send(());
410 let _ = rx.recv();
411 }
412 let n = (self.data.len() - self.pos).min(buf.len());
413 buf[..n].copy_from_slice(&self.data[self.pos..self.pos + n]);
414 self.pos += n;
415 Ok(n)
416 }
417 }
418 impl Seek for Parking {
419 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
420 if let SeekFrom::Start(o) = pos {
421 self.pos = o as usize;
422 }
423 Ok(self.pos as u64)
424 }
425 }
426
427 let (entered_tx, entered_rx) = sync_channel::<()>(0);
428 let (go_tx, go_rx) = sync_channel::<()>(0);
429 let src: DynSource = Arc::new(SeekPoolSource::single(
430 Parking {
431 data: (0..16).collect(),
432 pos: 0,
433 entered: entered_tx,
434 release: Arc::new(Mutex::new(Some(go_rx))),
435 },
436 16,
437 ));
438
439 let a = {
441 let src = src.clone();
442 std::thread::spawn(move || {
443 let mut b = [0u8; 4];
444 src.read_at(0, &mut b).unwrap();
445 b
446 })
447 };
448 entered_rx.recv().unwrap(); let b = {
453 let src = src.clone();
454 std::thread::spawn(move || {
455 let mut b = [0u8; 4];
456 src.read_at(8, &mut b).unwrap();
457 b
458 })
459 };
460 std::thread::sleep(std::time::Duration::from_millis(50));
462 go_tx.send(()).unwrap();
463
464 assert_eq!(a.join().unwrap(), [0, 1, 2, 3]);
465 assert_eq!(b.join().unwrap(), [8, 9, 10, 11]);
466 }
467}