Skip to content

Add a skip method to the Read trait #53294

New issue

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

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

Already on GitHub? # to your account

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

# for free to join this conversation on GitHub. Already have an account? # 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