use std::io::{
Error,
ErrorKind,
Result,
Write,
};
use crate::util::UncheckedSlice;
pub trait Output {
type Item;
#[inline(always)]
#[must_use]
fn is_buffered(&self) -> bool {
false
}
unsafe fn write_unchecked(
&mut self,
input: &[Self::Item],
index: usize,
count: usize,
) -> Result<usize>;
#[inline(always)]
fn write(&mut self, input: &[Self::Item]) -> Result<usize> {
let written = unsafe { self.write_unchecked(input, 0, input.len()) }?;
validate_write_count(written, input.len())?;
Ok(written)
}
unsafe fn write_fully_unchecked(
&mut self,
input: &[Self::Item],
index: usize,
count: usize,
) -> Result<()> {
debug_assert!(
UncheckedSlice::range_fits(input.len(), index, count),
"unchecked write-fully range exceeds input buffer"
);
let mut written = 0;
while written < count {
let remaining = count - written;
match unsafe {
self.write_unchecked(input, index + written, remaining)
} {
Ok(0) => {
return Err(Error::new(
ErrorKind::WriteZero,
"failed to write whole output range",
));
}
Ok(progress) => {
validate_write_count(progress, remaining)?;
written += progress;
}
Err(error) if error.kind() == ErrorKind::Interrupted => {}
Err(error) => return Err(error),
}
}
Ok(())
}
#[inline(always)]
fn write_fully(&mut self, input: &[Self::Item]) -> Result<()> {
unsafe { self.write_fully_unchecked(input, 0, input.len()) }
}
fn flush(&mut self) -> Result<()>;
}
impl<W> Output for W
where
W: Write + ?Sized,
{
type Item = u8;
#[inline(always)]
unsafe fn write_unchecked(
&mut self,
input: &[u8],
index: usize,
count: usize,
) -> Result<usize> {
debug_assert!(
UncheckedSlice::range_fits(input.len(), index, count),
"unchecked write range exceeds input buffer"
);
let source = unsafe { UncheckedSlice::subslice(input, index, count) };
Write::write(self, source)
}
#[inline(always)]
fn write(&mut self, input: &[Self::Item]) -> Result<usize> {
Write::write(self, input)
}
#[inline(always)]
fn flush(&mut self) -> Result<()> {
Write::flush(self)
}
}
#[inline(always)]
pub fn validate_write_count(written: usize, requested: usize) -> Result<()> {
if written > requested {
return Err(Error::new(
ErrorKind::InvalidData,
format!(
"writer reported {written} items for a {requested}-item buffer"
),
));
}
Ok(())
}