/
skip.rs
72 lines (63 loc) · 2.25 KB
/
skip.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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)
}
}