Created
April 4, 2023 09:25
-
-
Save gwy15/351cec07715f4f20014fafe570984b08 to your computer and use it in GitHub Desktop.
A skippable reader wrapper for Rust
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
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