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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
use std::io;
use std::io::Read;
/// Track whether a stream has hit the end of file.
///
/// This allows slightly nicer code when reading lots of items using an uncooperative api,
/// or when you want an `UnexpectedEof` only after the first byte.
/// It also simplifies determining the last chunk when processing
/// input in fixed-size chunks.
///
/// `Eof::eof()` and – for consistency – the `Read` implementation of `Eof`
/// ignore `ErrorKind::Interrupted` errors and retry the operation.
///
/// # Example
///
/// ```rust,no_run
/// use std::io;
/// use std::io::Read;
/// use std::fs::File;
/// use iowrap::Eof;
///
/// fn load() -> io::Result<Vec<u64>> {
/// let mut ret = Vec::new();
/// let mut file = Eof::new(File::open("foo.bin")?);
/// while !file.eof()? {
/// ret.push(third_party::parse_thing(&mut file));
/// }
/// Ok(ret)
/// }
///
/// mod third_party {
/// use std::io::Read;
/// pub fn parse_thing<R: Read>(mut from: R) -> u64 {
/// let mut buf = [0u8; 8];
/// from.read_exact(&mut buf).unwrap();
/// u64::from(buf[0]) // oops!
/// }
/// }
/// ```
pub struct Eof<R: Read> {
inner: R,
next: Option<u8>,
}
impl<R: Read> Eof<R> {
pub fn new(inner: R) -> Self {
Eof { inner, next: None }
}
/// Test if we are at the end of the stream.
/// If false, then a proceeding `read()` will always succeed.
pub fn eof(&mut self) -> io::Result<bool> {
if self.next.is_some() {
return Ok(false);
}
let mut buf = [0u8; 1];
Ok(loop {
break match self.inner.read(&mut buf) {
Ok(0) => true,
Ok(1) => {
self.next = Some(buf[0]);
false
}
Ok(_) => unreachable!(),
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
};
})
}
/// The buffered value, which we read while checking for EOF.
pub fn held_state(&self) -> Option<u8> {
self.next
}
pub fn get_ref(&self) -> &R {
&self.inner
}
pub fn get_mut(&mut self) -> &mut R {
&mut self.inner
}
pub fn into_inner(self) -> R {
self.inner
}
}
impl<R: Read> Read for Eof<R> {
/// For consistency with `eof()`, this implementation retries the
/// operation on `ErrorKind::Interrupted` errors.
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if buf.is_empty() {
return Ok(0);
}
if let Some(val) = self.next {
buf[0] = val;
self.next = None;
return Ok(1);
}
loop {
match self.inner.read(buf) {
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
e => return e,
}
}
}
}
#[cfg(test)]
mod tests {
use super::Eof;
use crate::short::ShortRead;
use std::io;
use std::io::Read;
#[test]
fn smoke_cursor() {
let mut eof = Eof::new(io::Cursor::new(vec![7, 8, 9, 10, 11, 12]));
assert_eq!(None, eof.held_state(), "nothing held initially");
assert_eq!(
false,
eof.eof().unwrap(),
"there's bytes to read, we're not at the end"
);
assert_eq!(
false,
eof.eof().unwrap(),
"we weren't at the end before, so we're not now"
);
assert_eq!(Some(7), eof.held_state(), "the state is the first byte");
assert_eq!(
false,
eof.eof().unwrap(),
"viewing the state doesn't move us to the end"
);
let mut buf = [0u8; 2];
eof.read_exact(&mut buf).unwrap();
assert_eq!(None, eof.held_state(), "reading consumed the state");
assert_eq!(
false,
eof.eof().unwrap(),
"reading two bytes didn't push us past the end"
);
assert_eq!(
Some(9),
eof.held_state(),
"checking the eof read the third byte into state"
);
let mut buf = [0u8; 20];
assert_eq!(
1,
eof.read(&mut buf).unwrap(),
"[implementation detail] read will only return one byte"
);
assert_eq!(9, buf[0], "it was the right byte");
assert_eq!(3, eof.read(&mut buf).unwrap(), "there's three more bytes");
assert_eq!(
None,
eof.held_state(),
"there's no state after some reading"
);
assert_eq!(true, eof.eof().unwrap(), "we're at the end");
assert_eq!(None, eof.held_state(), "there's still no state");
eof.get_mut().get_mut().push(100);
assert_eq!(
false,
eof.eof().unwrap(),
"if the underlying reader starts returning data again, so do we"
);
}
#[test]
fn interrupted_read() {
let take_a_break = ShortRead::new(
io::Cursor::new(b"12345"),
vec![0, 1, 0, 1, 0, 0, 0, 9, 9, 0, 1].into_iter(),
);
let mut eof = Eof::new(take_a_break);
let mut buf = [0u8; 2];
assert_eq!(
false,
eof.eof().unwrap(),
"skip interruption at the beginning"
);
assert_eq!(1, eof.read(&mut buf).unwrap());
assert_eq!(b'1', buf[0]);
assert_eq!(
1,
eof.read(&mut buf).unwrap(),
"skip interruption while reading"
);
assert_eq!(b'2', buf[0]);
assert_eq!(false, eof.eof().unwrap(), "skip multiple interruptions");
assert_eq!(1, eof.read(&mut buf).unwrap());
assert_eq!(b'3', buf[0]);
assert_eq!(2, eof.read(&mut buf).unwrap());
assert_eq!(b"45", &buf);
assert_eq!(true, eof.eof().unwrap(), "skip interruption before eof");
}
}