Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for readers that implement Seek (#218)
`Archive::new` requires only `Read` for backward-compatibility, while `Archive::new_from_seek` can be used with readers that also implement `Seek`, to allow more efficient skipping over file contents.
- Loading branch information
Showing
5 changed files
with
153 additions
and
31 deletions.
There are no files selected for viewing
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
use std::cmp; | ||
use std::io; | ||
use std::io::prelude::*; | ||
|
||
use crate::other; | ||
|
||
/// The `SkipRead` trait allows for reading bytes from a source, as well as | ||
/// skipping over a number of bytes | ||
/// | ||
/// This is used for backward compatibility with [`std::io::Read`]. Each reader | ||
/// automatically implements `SkipRead`. Readers that additionally implement | ||
/// [`std::io::Seek`] can use `SeekingSkipRead` to implements efficient skipping | ||
/// based on [`std::io::Seek:seek`]. | ||
pub trait SkipRead { | ||
/// Pull some bytes from this source into the specified buffer, returning | ||
/// how many bytes were read. | ||
/// | ||
/// Identical to [`std::io::Read::read`]. | ||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>; | ||
|
||
/// Skip a specified number of bytes from the source, returning how many | ||
/// bytes were skipped. | ||
fn skip(&mut self, amt: u64) -> io::Result<u64>; | ||
} | ||
|
||
/// `SkipRead` is implemented for all readers by using [`std::io::Read::read`] | ||
/// for both reading and skipping. | ||
impl<R: Read> SkipRead for R { | ||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||
self.read(buf) | ||
} | ||
|
||
fn skip(&mut self, amt: u64) -> io::Result<u64> { | ||
let mut buf = [0u8; 4096 * 8]; | ||
let mut skipped = 0; | ||
while skipped < amt { | ||
let n = cmp::min(amt - skipped, buf.len() as u64); | ||
let n = self.read(&mut buf[..n as usize])?; | ||
if n == 0 { | ||
return Err(other("unexpected EOF during skip")); | ||
} | ||
skipped += n as u64; | ||
} | ||
Ok(skipped) | ||
} | ||
} | ||
|
||
/// Wrapper to implement `SkipRead` more efficiently for readers that also | ||
/// implement [`std::io::Seek`]. Skipping is implemented using | ||
/// [`std::io::Seek:seek`]. | ||
pub struct SeekingSkipRead<R: Read + Seek> { | ||
inner: R, | ||
} | ||
|
||
impl<R: Read + Seek> SeekingSkipRead<R> { | ||
pub fn new(obj: R) -> SeekingSkipRead<R> { | ||
SeekingSkipRead { inner: obj } | ||
} | ||
} | ||
|
||
impl<R: Read + Seek> SkipRead for SeekingSkipRead<R> { | ||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||
self.inner.read(buf) | ||
} | ||
|
||
fn skip(&mut self, amount: u64) -> io::Result<u64> { | ||
let old_pos = self.inner.stream_position()?; | ||
self.inner | ||
.seek(io::SeekFrom::Current(amount as i64)) | ||
.map(|pos| pos - old_pos) | ||
} | ||
} |
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