use crate::{Activity, Bufferable, Status};
use std::convert::TryInto;
use std::io::{self, IoSlice, Write};
pub trait WriteLayered: Write + Bufferable {
fn close(&mut self) -> io::Result<()>;
fn flush_with_status(&mut self, status: Status) -> io::Result<()> {
match status {
Status::Open(Activity::Active) => Ok(()),
Status::Open(Activity::Push) => self.flush(),
Status::End => self.close(),
}
}
}
pub fn default_write_vectored<Inner: Write + ?Sized>(
inner: &mut Inner,
bufs: &[IoSlice<'_>],
) -> io::Result<usize> {
let buf = bufs
.iter()
.find(|b| !b.is_empty())
.map_or(&[][..], |b| &**b);
inner.write(buf)
}
#[cfg(can_vector)]
#[inline]
pub fn default_is_write_vectored<Inner: Write + ?Sized>(_inner: &Inner) -> bool {
false
}
#[allow(clippy::indexing_slicing)]
pub fn default_write_all<Inner: Write + ?Sized>(
inner: &mut Inner,
mut buf: &[u8],
) -> io::Result<()> {
while !buf.is_empty() {
match inner.write(buf) {
Ok(0) => {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to write whole buffer",
));
}
Ok(n) => buf = &buf[n..],
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
Ok(())
}
#[cfg(write_all_vectored)]
pub fn default_write_all_vectored<Inner: Write + ?Sized>(
inner: &mut Inner,
mut bufs: &mut [IoSlice],
) -> io::Result<()> {
while !bufs.is_empty() {
match inner.write_vectored(bufs) {
Ok(nwritten) => bufs = advance(bufs, nwritten),
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
Err(e) => return Err(e),
}
}
Ok(())
}
#[cfg(write_all_vectored)]
fn advance<'a, 'b>(bufs: &'b mut [IoSlice<'a>], n: usize) -> &'b mut [IoSlice<'a>] {
use std::slice;
let mut remove = 0;
let mut accumulated_len = 0;
for buf in bufs.iter() {
if accumulated_len + buf.len() > n {
break;
}
accumulated_len += buf.len();
remove += 1;
}
#[allow(clippy::indexing_slicing)]
let bufs = &mut bufs[remove..];
if let Some(first) = bufs.first_mut() {
let advance_by = n - accumulated_len;
let mut ptr = first.as_ptr();
let mut len = first.len();
unsafe {
ptr = ptr.add(advance_by);
len -= advance_by;
*first = IoSlice::<'a>::new(slice::from_raw_parts::<'a>(ptr, len));
}
}
bufs
}
impl WriteLayered for std::io::Cursor<Vec<u8>> {
#[inline]
fn close(&mut self) -> io::Result<()> {
self.set_position(self.get_ref().len().try_into().unwrap());
Ok(())
}
}
impl WriteLayered for std::io::Cursor<Box<[u8]>> {
#[inline]
fn close(&mut self) -> io::Result<()> {
self.set_position(self.get_ref().len().try_into().unwrap());
Ok(())
}
}
impl WriteLayered for std::io::Cursor<&mut Vec<u8>> {
#[inline]
fn close(&mut self) -> io::Result<()> {
self.set_position(self.get_ref().len().try_into().unwrap());
Ok(())
}
}
impl WriteLayered for std::io::Cursor<&mut [u8]> {
#[inline]
fn close(&mut self) -> io::Result<()> {
self.set_position(self.get_ref().len().try_into().unwrap());
Ok(())
}
}
impl<W: WriteLayered> WriteLayered for Box<W> {
#[inline]
fn close(&mut self) -> io::Result<()> {
self.as_mut().close()
}
}
impl<W: WriteLayered> WriteLayered for &mut W {
#[inline]
fn close(&mut self) -> io::Result<()> {
(**self).close()
}
}