use std::io::{
Error,
ErrorKind,
Read,
Result,
};
use crate::util::UncheckedSlice;
pub trait Input {
type Item;
#[inline(always)]
#[must_use]
fn is_buffered(&self) -> bool {
false
}
unsafe fn read_unchecked(
&mut self,
output: &mut [Self::Item],
index: usize,
count: usize,
) -> Result<usize>;
#[inline(always)]
fn read(&mut self, output: &mut [Self::Item]) -> Result<usize> {
let read = unsafe { self.read_unchecked(output, 0, output.len()) }?;
validate_read_count(read, output.len())?;
Ok(read)
}
unsafe fn read_fully_unchecked(
&mut self,
output: &mut [Self::Item],
index: usize,
count: usize,
) -> Result<usize> {
debug_assert!(
UncheckedSlice::range_fits(output.len(), index, count),
"unchecked read-fully range exceeds output buffer"
);
let mut total = 0;
while total < count {
let remaining = count - total;
match unsafe {
self.read_unchecked(output, index + total, remaining)
} {
Ok(0) => break,
Ok(read) => {
validate_read_count(read, remaining)?;
total += read;
}
Err(error) if error.kind() == ErrorKind::Interrupted => {}
Err(error) => return Err(error),
}
}
Ok(total)
}
#[inline(always)]
fn read_fully(&mut self, output: &mut [Self::Item]) -> Result<usize> {
unsafe { self.read_fully_unchecked(output, 0, output.len()) }
}
}
impl<R> Input for R
where
R: Read + ?Sized,
{
type Item = u8;
#[inline(always)]
unsafe fn read_unchecked(
&mut self,
output: &mut [u8],
index: usize,
count: usize,
) -> Result<usize> {
debug_assert!(
UncheckedSlice::range_fits(output.len(), index, count),
"unchecked read range exceeds output buffer"
);
let target =
unsafe { UncheckedSlice::subslice_mut(output, index, count) };
Read::read(self, target)
}
#[inline(always)]
fn read(&mut self, output: &mut [Self::Item]) -> Result<usize> {
Read::read(self, output)
}
}
#[inline(always)]
pub fn validate_read_count(read: usize, requested: usize) -> Result<()> {
if read > requested {
return Err(Error::new(
ErrorKind::InvalidData,
format!(
"reader reported {read} items for a {requested}-item buffer"
),
));
}
Ok(())
}