use std::io::Error;
use std::io::ErrorKind;
use std::io::Result;
use crate::Buffer;
use crate::Input;
use crate::traits::validate_read_count;
use crate::util::SliceRange;
pub(super) fn read_more_impl<T>(inner: &mut dyn Input<Item = T>, buffer: &mut Buffer<T>) -> Result<bool>
where
T: Clone + Default,
{
let count = buffer.spare_capacity();
debug_assert!(count > 0, "buffer has no tail capacity");
loop {
let limit = buffer.limit();
match unsafe { inner.read_unchecked(buffer.data_mut(), limit, count) } {
Ok(0) => return Ok(false),
Ok(read) => {
validate_read_count(read, count)?;
unsafe {
buffer.advance(read);
}
return Ok(true);
}
Err(error) if error.kind() == ErrorKind::Interrupted => continue,
Err(error) => return Err(error),
}
}
}
pub(in crate::buffered) fn fill_more_impl<T>(inner: &mut dyn Input<Item = T>, buffer: &mut Buffer<T>) -> Result<bool>
where
T: Clone + Default,
{
if buffer.available() == 0 {
buffer.clear();
} else if buffer.spare_capacity() == 0 {
buffer.compact();
if buffer.spare_capacity() == 0 {
return Err(Error::new(
ErrorKind::InvalidInput,
"buffered input is full; consume buffered items before refilling",
));
}
}
read_more_impl(inner, buffer)
}
pub(in crate::buffered) fn fill_until_impl<T>(
inner: &mut dyn Input<Item = T>,
buffer: &mut Buffer<T>,
count: usize,
) -> Result<bool>
where
T: Clone + Default,
{
if count > buffer.capacity() {
return Err(Error::new(
ErrorKind::InvalidInput,
"requested available items exceed buffered input capacity",
));
}
while buffer.available() < count {
let available = buffer.available();
if available == 0 {
buffer.clear();
} else {
let missing = count - available;
if buffer.spare_capacity() < missing {
buffer.compact();
}
}
if !read_more_impl(inner, buffer)? {
return Ok(false);
}
}
Ok(true)
}
pub(in crate::buffered) fn ensure_available_impl<T>(
inner: &mut dyn Input<Item = T>,
buffer: &mut Buffer<T>,
count: usize,
) -> Result<()>
where
T: Clone + Default,
{
if fill_until_impl(inner, buffer, count)? {
return Ok(());
}
let available = buffer.available();
unsafe {
buffer.consume(available);
}
Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
}
pub(in crate::buffered) unsafe fn read_unchecked_impl<T>(
inner: &mut dyn Input<Item = T>,
buffer: &mut Buffer<T>,
output: &mut [T],
output_index: usize,
count: usize,
) -> Result<usize>
where
T: Clone + Default,
{
debug_assert!(
SliceRange::range_fits(output.len(), output_index, count),
"unchecked read output range exceeds destination buffer"
);
if count == 0 {
return Ok(0);
}
if buffer.available() == 0 {
buffer.clear();
if count >= buffer.capacity() {
let read = unsafe { inner.read_unchecked(output, output_index, count) }?;
validate_read_count(read, count)?;
return Ok(read);
}
if !read_more_impl(inner, buffer)? {
return Ok(0);
}
}
let read_count = count.min(buffer.available());
unsafe {
buffer.copy_to(output, output_index, read_count);
}
Ok(read_count)
}
unsafe fn copy_available_to_output<T>(
buffer: &mut Buffer<T>,
output: &mut [T],
output_index: usize,
count: usize,
) -> usize
where
T: Clone + Default,
{
let copied = count.min(buffer.available());
if copied != 0 {
unsafe {
buffer.copy_to(output, output_index, copied);
}
}
copied
}
unsafe fn read_direct_fully<T>(
inner: &mut dyn Input<Item = T>,
output: &mut [T],
output_index: usize,
count: usize,
) -> Result<usize> {
loop {
match unsafe { inner.read_fully_unchecked(output, output_index, count) } {
Ok(read) => {
validate_read_count(read, count)?;
return Ok(read);
}
Err(error) if error.kind() == ErrorKind::Interrupted => continue,
Err(error) => return Err(error),
}
}
}
unsafe fn read_buffered_remainder<T>(
inner: &mut dyn Input<Item = T>,
buffer: &mut Buffer<T>,
output: &mut [T],
output_index: usize,
count: usize,
) -> Result<usize>
where
T: Clone + Default,
{
let mut total = 0;
while total < count {
let remaining = count - total;
match unsafe { read_unchecked_impl(inner, buffer, output, output_index + total, remaining) } {
Ok(0) => break,
Ok(read) => total += read,
Err(error) => return Err(error),
}
}
Ok(total)
}
pub(in crate::buffered) unsafe fn read_fully_unchecked_impl<T>(
inner: &mut dyn Input<Item = T>,
buffer: &mut Buffer<T>,
output: &mut [T],
output_index: usize,
count: usize,
) -> Result<usize>
where
T: Clone + Default,
{
debug_assert!(
SliceRange::range_fits(output.len(), output_index, count),
"unchecked read-fully output range exceeds destination buffer"
);
if count == 0 {
return Ok(0);
}
let total = unsafe { copy_available_to_output(buffer, output, output_index, count) };
if total == count {
return Ok(total);
}
let remaining = count - total;
if remaining >= buffer.capacity() {
buffer.clear();
let read = unsafe { read_direct_fully(inner, output, output_index + total, remaining) }?;
return Ok(total + read);
}
let read = unsafe { read_buffered_remainder(inner, buffer, output, output_index + total, remaining) }?;
Ok(total + read)
}