Skip to content

Instantly share code, notes, and snippets.

@gwy15
Created April 4, 2023 09:25
Show Gist options
  • Save gwy15/351cec07715f4f20014fafe570984b08 to your computer and use it in GitHub Desktop.
Save gwy15/351cec07715f4f20014fafe570984b08 to your computer and use it in GitHub Desktop.
A skippable reader wrapper for Rust
pub struct SkipReader<R> {
inner: R,
skip: usize,
skipped: bool,
}
impl<R> SkipReader<R> {
pub fn new(reader: R, skip: usize) -> Self {
Self {
inner: reader,
skip,
skipped: skip == 0,
}
}
fn skip(&mut self) -> std::io::Result<()>
where
R: std::io::Read,
{
if self.skipped {
return Ok(());
}
// N.B.: This does cost 1k of extra stack space. Be aware.
let mut buf = [0; 1024];
let mut total = 0;
while total < self.skip {
let len = std::cmp::min(self.skip - total, buf.len());
match self.inner.read(&mut buf[..len]) {
Ok(0) => break,
Ok(n) => total += n,
Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
};
debug_assert!(total <= self.skip);
}
self.skipped = true;
Ok(())
}
}
impl<R: std::io::Read> std::io::Read for SkipReader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
if !self.skipped {
self.skip()?;
}
self.inner.read(buf)
}
}
#[test]
fn skip_empty_reader() {
use std::io::Read;
let mut reader = SkipReader::new(&[][..], 100);
let mut buf = vec![];
reader.read_to_end(&mut buf).unwrap();
assert!(buf.is_empty());
}
#[test]
fn skip_0_out_of_1000() {
use std::io::Read;
let mut bytes = vec![0; 1000];
for i in 0..bytes.len() {
bytes[i] = i as u8;
}
let mut reader = SkipReader::new(&bytes[..], 0);
let mut buf = vec![];
reader.read_to_end(&mut buf).unwrap();
assert_eq!(buf, &bytes[..]);
}
#[test]
fn skip_100_out_of_1000() {
use std::io::Read;
let mut bytes = vec![0; 1000];
for i in 0..bytes.len() {
bytes[i] = i as u8;
}
let mut reader = SkipReader::new(&bytes[..], 100);
let mut buf = vec![];
reader.read_to_end(&mut buf).unwrap();
assert_eq!(buf, &bytes[100..]);
}
#[test]
fn skip_2000_out_of_1000() {
use std::io::Read;
let mut bytes = vec![0; 1000];
for i in 0..bytes.len() {
bytes[i] = i as u8;
}
let mut reader = SkipReader::new(&bytes[..], 2000);
let mut buf = vec![];
reader.read_to_end(&mut buf).unwrap();
assert!(buf.is_empty());
}
#[test]
fn skipped_with_read_exact() {
use std::io::Read;
let mut bytes = vec![0; 1000];
for i in 0..bytes.len() {
bytes[i] = i as u8;
}
let mut reader = SkipReader::new(&bytes[..], 2000);
let mut buf = vec![0; 100];
reader.read_exact(&mut buf).unwrap_err();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment