use std::io::{
ErrorKind,
Read,
Result,
Seek,
SeekFrom,
};
use crate::ReadSeek;
pub trait ReadSeekExt: Read + Seek {
fn peek_exact_or_eof(&mut self, buffer: &mut [u8]) -> Result<usize>;
fn read_exact_or_eof_at(&mut self, offset: u64, buffer: &mut [u8]) -> Result<usize>;
}
impl<T> ReadSeekExt for T
where
T: Read + Seek + ?Sized,
{
#[inline]
fn peek_exact_or_eof(&mut self, buffer: &mut [u8]) -> Result<usize> {
let mut reader = self;
peek_exact_or_eof_impl(&mut reader, buffer)
}
#[inline]
fn read_exact_or_eof_at(&mut self, offset: u64, buffer: &mut [u8]) -> Result<usize> {
let mut reader = self;
read_exact_or_eof_at_impl(&mut reader, offset, buffer)
}
}
fn peek_exact_or_eof_impl(reader: &mut dyn ReadSeek, buffer: &mut [u8]) -> Result<usize> {
let position = reader.stream_position()?;
let read_result = read_exact_or_eof(reader, buffer);
let restore_result = reader.seek(SeekFrom::Start(position));
match (read_result, restore_result) {
(Ok(count), Ok(_)) => Ok(count),
(Err(error), Ok(_)) => Err(error),
(_, Err(error)) => Err(error),
}
}
fn read_exact_or_eof_at_impl(
reader: &mut dyn ReadSeek,
offset: u64,
buffer: &mut [u8],
) -> Result<usize> {
let position = reader.stream_position()?;
let read_result = match reader.seek(SeekFrom::Start(offset)) {
Ok(_) => read_exact_or_eof(reader, buffer),
Err(error) => Err(error),
};
let restore_result = reader.seek(SeekFrom::Start(position));
match (read_result, restore_result) {
(Ok(count), Ok(_)) => Ok(count),
(Err(error), Ok(_)) => Err(error),
(_, Err(error)) => Err(error),
}
}
fn read_exact_or_eof(reader: &mut dyn ReadSeek, buffer: &mut [u8]) -> Result<usize> {
let mut total = 0;
while total < buffer.len() {
match reader.read(&mut buffer[total..]) {
Ok(0) => break,
Ok(count) => total += count,
Err(error) => {
if error.kind() == ErrorKind::Interrupted {
continue;
}
return Err(error);
}
}
}
Ok(total)
}