Created
September 26, 2022 02:28
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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