Skip to content

Instantly share code, notes, and snippets.

@Rainb0wCodes
Created September 26, 2022 02:28
Show Gist options
  • Save Rainb0wCodes/4fa9ae5336cc0ca5875a69e2f4f2382d to your computer and use it in GitHub Desktop.
Save Rainb0wCodes/4fa9ae5336cc0ca5875a69e2f4f2382d to your computer and use it in GitHub Desktop.
A wrapper for any stream to make it seekable in the forwards direction
/* The following code is licensed under the CC0 1.0 Universal license. Details can be found at http://creativecommons.org/publicdomain/zero/1.0/
To the full extent, I, a Canadian citizen have waived all copyright and related or neighboring rights to this work. */
struct SeekableStreamWrapper<T: Read> {
offset: usize,
inner: T,
}
impl<T> Read for SeekableStreamWrapper<T>
where
T: Read,
{
#[inline]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let result = self.inner.read(buf);
match result {
Ok(n) => {
self.offset += n;
}
Err(_) => {}
};
return result;
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
let result = self.inner.read_exact(buf);
match result {
Ok(_) => {
self.offset += buf.len();
}
Err(_) => {}
};
return result;
}
#[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
let result = self.inner.read_to_end(buf);
match result {
Ok(n) => {
self.offset += n;
}
Err(_) => {}
};
return result;
}
#[inline]
fn read_to_string(&mut self, buf: &mut String) -> std::io::Result<usize> {
let result = self.inner.read_to_string(buf);
match result {
Ok(n) => {
self.offset += n;
}
Err(_) => {}
};
return result;
}
}
impl<T> Seek for SeekableStreamWrapper<T>
where
T: Read,
{
/// This implementation of seek() panics on any seek from `std::io::SeekFrom::End`, if the seek offset is negative, or if the seek offset is unreasonably sized.
#[inline]
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
match pos {
Current(seek_offset) => {
let real_seek_offset = seek_offset.try_into().unwrap();
if seek_offset < 0 {
panic!("SeekableStreamWrapper does not support seeking backwards!");
}
self.offset = self.offset.checked_add(real_seek_offset).unwrap();
let mut discard = vec![0u8; real_seek_offset];
self.inner.read_exact(&mut discard)?;
}
Start(seek_offset) => {
let real_seek_offset: usize = seek_offset.try_into().unwrap();
if self.offset > real_seek_offset {
panic!("SeekableStreamWrapper does not support seeking backwards!");
}
let relative_seek_offset = real_seek_offset - self.offset;
debug!(
"Seeking to Start({}) from {} requires relative seek of {}",
seek_offset, self.offset, relative_seek_offset
);
let mut discard = vec![0u8; relative_seek_offset];
self.inner.read_exact(&mut discard)?;
self.offset = real_seek_offset;
}
End(_) => {
panic!(
"SeekableStreamWrapper does not support seeking from the end of the stream!"
);
}
}
return Ok(self.offset.try_into().unwrap());
}
}
#[allow(dead_code)]
impl<T> SeekableStreamWrapper<T>
where
T: Read,
{
#[inline]
pub fn into_inner(self) -> T {
self.inner
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment