Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a skip method to the Read trait #53294

Open
zslayton opened this issue Aug 12, 2018 · 4 comments
Open

Add a skip method to the Read trait #53294

zslayton opened this issue Aug 12, 2018 · 4 comments
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@zslayton
Copy link
Contributor

The Read trait doesn't currently offer an optimal way to discard a number of bytes from the data source. Using the bytes() iterator requires you to evaluate a Result for each byte you discard and using read_exact() requires you to provide a buffer to unnecessarily fill.

This solution (borrowed from a StackOverflow answer) seems to work nicely:

let mut file = File::open("foo.txt").unwrap();

// Discard 27 bytes
io::copy(&mut file.by_ref().take(27), &mut io::sink());

// Read the rest
let mut interesting_contents = Vec::new();
file.read_to_end(&mut interesting_contents).unwrap();

I can put a PR together if you'd like.

@sfackler
Copy link
Member

https://doc.rust-lang.org/std/io/trait.Seek.html covers the File case at the very least.

@zslayton
Copy link
Contributor Author

That's true. For skipping large numbers of bytes, seek is also faster. However, for my use case, I'd like to be able to read from a TcpStream or other non-Seek sources.

Would it be possible to use impl specialization to write a Read::skip() method that used seek for data sources that were Read + Seek and fell back to the io::copy/io::sink implementation for Read-only values?

@memoryruins memoryruins added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. C-feature-request Category: A feature request, i.e: not implemented / a PR. labels Sep 15, 2018
@lovasoa
Copy link
Contributor

lovasoa commented Aug 22, 2019

What is the status on this ? Has it been discussed somewhere else ?

@gwy15
Copy link

gwy15 commented Apr 4, 2023

For those reaching here and urgently need a solution, this is a quick solution

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)
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants