aboutsummaryrefslogtreecommitdiff
path: root/src/utils/cursor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/cursor.rs')
-rw-r--r--src/utils/cursor.rs60
1 files changed, 60 insertions, 0 deletions
diff --git a/src/utils/cursor.rs b/src/utils/cursor.rs
new file mode 100644
index 0000000..c41270a
--- /dev/null
+++ b/src/utils/cursor.rs
@@ -0,0 +1,60 @@
1use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Write};
2
3pub struct IoCursor<Io> {
4 io: Io,
5 cursor: u64,
6 bounds: (u64, u64),
7}
8
9impl<Io: Seek> IoCursor<Io> {
10 pub fn new(mut io: Io, start: u64, end: u64) -> Result<Self> {
11 let cursor = io.seek(SeekFrom::Start(start))?;
12 Ok(Self {
13 io,
14 cursor,
15 bounds: (cursor, end),
16 })
17 }
18}
19
20impl<Io: Read> Read for IoCursor<Io> {
21 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
22 let upper = buf.len().min((self.bounds.1 - self.cursor) as usize);
23 let bytes = self.io.read(&mut buf[..upper])?;
24 self.cursor += bytes as u64;
25 Ok(bytes)
26 }
27}
28
29impl<Io: Write> Write for IoCursor<Io> {
30 fn write(&mut self, buf: &[u8]) -> Result<usize> {
31 let upper = buf.len().min((self.bounds.1 - self.cursor) as usize);
32 let bytes = self.io.write(&buf[..upper])?;
33 self.cursor += bytes as u64;
34 Ok(bytes)
35 }
36
37 #[inline]
38 fn flush(&mut self) -> Result<()> {
39 self.io.flush()
40 }
41}
42
43impl<Io: Seek> Seek for IoCursor<Io> {
44 fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
45 self.cursor = match pos {
46 SeekFrom::Start(0) => return Ok(self.cursor - self.bounds.0),
47 SeekFrom::Start(offset) => self.bounds.0.checked_add(offset),
48 SeekFrom::End(offset) => self.bounds.1.checked_add_signed(offset),
49 SeekFrom::Current(offset) => self.cursor.checked_add_signed(offset),
50 }
51 .filter(|v| *v >= self.bounds.0)
52 .ok_or(Error::new(
53 ErrorKind::InvalidInput,
54 "Invalid seek to a negative or overflowing position",
55 ))?
56 .min(self.bounds.1);
57
58 Ok(self.io.seek(SeekFrom::Start(self.cursor))? - self.bounds.0)
59 }
60}