use super::{Bufferable, Status};
use std::io::{self, IoSliceMut, Read};
pub trait ReadLayered: Read + Bufferable {
fn read_with_status(&mut self, buf: &mut [u8]) -> io::Result<(usize, Status)>;
#[inline]
fn read_vectored_with_status(
&mut self,
bufs: &mut [IoSliceMut<'_>],
) -> io::Result<(usize, Status)> {
default_read_vectored_with_status(self, bufs)
}
#[inline]
fn read_exact_using_status(&mut self, buf: &mut [u8]) -> io::Result<Status> {
default_read_exact_using_status(self, buf)
}
#[inline]
fn minimum_buffer_size(&self) -> usize {
0
}
}
#[inline]
pub fn default_read<Inner: ReadLayered + ?Sized>(
inner: &mut Inner,
buf: &mut [u8],
) -> io::Result<usize> {
inner.read_with_status(buf).and_then(to_std_io_read_result)
}
pub fn default_read_vectored<Inner: ReadLayered + ?Sized>(
inner: &mut Inner,
bufs: &mut [IoSliceMut<'_>],
) -> io::Result<usize> {
inner
.read_vectored_with_status(bufs)
.and_then(to_std_io_read_result)
}
#[allow(clippy::indexing_slicing)]
pub fn default_read_to_end<Inner: ReadLayered + ?Sized>(
inner: &mut Inner,
buf: &mut Vec<u8>,
) -> io::Result<usize> {
let start_len = buf.len();
let buffer_size = inner.suggested_buffer_size();
let mut read_len = buffer_size;
loop {
let read_pos = buf.len();
buf.resize(read_pos + read_len, 0);
match inner.read_with_status(&mut buf[read_pos..]) {
Ok((size, status)) => {
buf.resize(read_pos + size, 0);
match status {
Status::Open(_) => {
read_len -= size;
if read_len < inner.minimum_buffer_size() {
read_len += buffer_size;
}
}
Status::End => return Ok(buf.len() - start_len),
}
}
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => {
buf.resize(start_len, 0);
return Err(e);
}
}
}
}
pub fn default_read_to_string<Inner: ReadLayered + ?Sized>(
inner: &mut Inner,
buf: &mut String,
) -> io::Result<usize> {
let mut vec = Vec::new();
let size = inner.read_to_end(&mut vec)?;
let new = String::from_utf8(vec).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
buf.push_str(&new);
Ok(size)
}
#[allow(clippy::indexing_slicing)]
pub fn default_read_exact_using_status<Inner: ReadLayered + ?Sized>(
inner: &mut Inner,
mut buf: &mut [u8],
) -> io::Result<Status> {
let mut result_status = Status::active();
while !buf.is_empty() {
match inner.read_with_status(buf) {
Ok((size, status)) => {
let t = buf;
buf = &mut t[size..];
if status.is_end() {
result_status = status;
break;
}
}
Err(e) => return Err(e),
}
}
if buf.is_empty() {
Ok(result_status)
} else {
Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"failed to fill whole buffer",
))
}
}
pub fn default_read_vectored_with_status<Inner: ReadLayered + ?Sized>(
inner: &mut Inner,
bufs: &mut [IoSliceMut<'_>],
) -> io::Result<(usize, Status)> {
let buf = bufs
.iter_mut()
.find(|b| !b.is_empty())
.map_or(&mut [][..], |b| &mut **b);
inner.read_with_status(buf)
}
#[cfg(can_vector)]
pub fn default_is_read_vectored<Inner: ReadLayered + ?Sized>(_inner: &Inner) -> bool {
false
}
pub fn to_std_io_read_result(size_and_status: (usize, Status)) -> io::Result<usize> {
match size_and_status {
(0, Status::Open(_)) => Err(io::Error::new(
io::ErrorKind::Interrupted,
"read zero bytes from stream",
)),
(size, _) => Ok(size),
}
}
impl<R: ReadLayered> ReadLayered for Box<R> {
#[inline]
fn read_with_status(&mut self, buf: &mut [u8]) -> io::Result<(usize, Status)> {
self.as_mut().read_with_status(buf)
}
#[inline]
fn read_vectored_with_status(
&mut self,
bufs: &mut [IoSliceMut<'_>],
) -> io::Result<(usize, Status)> {
self.as_mut().read_vectored_with_status(bufs)
}
#[inline]
fn minimum_buffer_size(&self) -> usize {
self.as_ref().minimum_buffer_size()
}
}
impl<R: ReadLayered> ReadLayered for &mut R {
#[inline]
fn read_with_status(&mut self, buf: &mut [u8]) -> io::Result<(usize, Status)> {
(**self).read_with_status(buf)
}
#[inline]
fn read_vectored_with_status(
&mut self,
bufs: &mut [IoSliceMut<'_>],
) -> io::Result<(usize, Status)> {
(**self).read_vectored_with_status(bufs)
}
#[inline]
fn minimum_buffer_size(&self) -> usize {
(**self).minimum_buffer_size()
}
}