use io_lifetimes::{AsFilelike, AsSocketlike};
use std::fmt::Arguments;
use std::io::{self, IoSlice, IoSliceMut, Read, Write};
use std::slice;
pub trait IoExt {
fn read(&self, buf: &mut [u8]) -> io::Result<usize>;
fn read_exact(&self, buf: &mut [u8]) -> io::Result<()>;
fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize>;
fn read_exact_vectored(&self, mut bufs: &mut [IoSliceMut]) -> io::Result<()> {
bufs = skip_leading_empties(bufs);
while !bufs.is_empty() {
match self.read_vectored(bufs) {
Ok(0) => {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"failed to fill whole buffer",
))
}
Ok(nread) => bufs = advance_mut(bufs, nread),
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
Err(e) => return Err(e),
}
bufs = skip_leading_empties(bufs);
}
Ok(())
}
fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize>;
fn read_to_string(&self, buf: &mut String) -> io::Result<usize>;
fn peek(&self, buf: &mut [u8]) -> io::Result<usize>;
fn write(&self, buf: &[u8]) -> io::Result<usize>;
fn write_all(&self, buf: &[u8]) -> io::Result<()>;
fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize>;
fn write_all_vectored(&self, mut bufs: &mut [IoSlice]) -> io::Result<()> {
while !bufs.is_empty() {
match self.write_vectored(bufs) {
Ok(nwritten) => bufs = advance(bufs, nwritten),
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
Err(e) => return Err(e),
}
}
Ok(())
}
fn write_fmt(&self, fmt: Arguments) -> io::Result<()>;
fn flush(&self) -> io::Result<()>;
}
fn skip_leading_empties<'a, 'b>(mut bufs: &'b mut [IoSliceMut<'a>]) -> &'b mut [IoSliceMut<'a>] {
while !bufs.is_empty() {
if !bufs[0].is_empty() {
break;
}
bufs = &mut bufs[1..];
}
bufs
}
fn advance<'a, 'b>(bufs: &'b mut [IoSlice<'a>], n: usize) -> &'b mut [IoSlice<'a>] {
let mut remove = 0;
let mut accumulated_len = 0;
for buf in bufs.iter() {
if accumulated_len + buf.len() > n {
break;
} else {
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
}
fn advance_mut<'a, 'b>(bufs: &'b mut [IoSliceMut<'a>], n: usize) -> &'b mut [IoSliceMut<'a>] {
let mut remove = 0;
let mut accumulated_len = 0;
for buf in bufs.iter() {
if accumulated_len + buf.len() > n {
break;
} else {
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_mut_ptr();
let mut len = first.len();
unsafe {
ptr = ptr.add(advance_by);
len -= advance_by;
*first = IoSliceMut::<'a>::new(slice::from_raw_parts_mut::<'a>(ptr, len));
}
}
bufs
}
#[cfg(not(windows))]
impl<T: AsFilelike + AsSocketlike> IoExt for T {
#[inline]
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
Read::read(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
}
#[inline]
fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
Read::read_exact(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
}
#[inline]
fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
Read::read_vectored(&mut &*self.as_filelike_view::<std::fs::File>(), bufs)
}
#[inline]
fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
Read::read_to_end(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
}
#[inline]
fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
Read::read_to_string(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
}
#[inline]
fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
match self.as_socketlike_view::<std::net::TcpStream>().peek(buf) {
Err(err) if err.raw_os_error() == Some(rustix::io::Errno::NOTSOCK.raw_os_error()) => {
match self.as_filelike_view::<std::fs::File>().peek(buf) {
Err(err)
if err.raw_os_error() == Some(rustix::io::Errno::SPIPE.raw_os_error()) =>
{
Ok(0)
}
otherwise => otherwise,
}
}
otherwise => otherwise,
}
}
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
Write::write(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
}
#[inline]
fn write_all(&self, buf: &[u8]) -> io::Result<()> {
Write::write_all(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
}
#[inline]
fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
Write::write_vectored(&mut &*self.as_filelike_view::<std::fs::File>(), bufs)
}
#[inline]
fn flush(&self) -> io::Result<()> {
Write::flush(&mut &*self.as_filelike_view::<std::fs::File>())
}
#[inline]
fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
Write::write_fmt(&mut &*self.as_filelike_view::<std::fs::File>(), fmt)
}
}
#[cfg(windows)]
impl IoExt for std::fs::File {
#[inline]
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
Read::read(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
}
#[inline]
fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
Read::read_exact(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
}
#[inline]
fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
Read::read_vectored(&mut &*self.as_filelike_view::<std::fs::File>(), bufs)
}
#[inline]
fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
Read::read_to_end(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
}
#[inline]
fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
Read::read_to_string(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
}
#[inline]
fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
use std::os::windows::io::AsRawHandle;
let mut bytes_read = std::mem::MaybeUninit::<u32>::uninit();
let len = std::cmp::min(buf.len(), u32::MAX as usize) as u32;
let res = unsafe {
windows_sys::Win32::System::Pipes::PeekNamedPipe(
self.as_filelike().as_raw_handle() as _,
buf.as_mut_ptr() as *mut std::ffi::c_void,
len,
bytes_read.as_mut_ptr(),
std::ptr::null_mut(),
std::ptr::null_mut(),
)
};
if res == 0 {
return Err(io::Error::last_os_error());
}
Ok(unsafe { bytes_read.assume_init() } as usize)
}
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
Write::write(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
}
#[inline]
fn write_all(&self, buf: &[u8]) -> io::Result<()> {
Write::write_all(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
}
#[inline]
fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
Write::write_vectored(&mut &*self.as_filelike_view::<std::fs::File>(), bufs)
}
#[inline]
fn flush(&self) -> io::Result<()> {
Write::flush(&mut &*self.as_filelike_view::<std::fs::File>())
}
#[inline]
fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
Write::write_fmt(&mut &*self.as_filelike_view::<std::fs::File>(), fmt)
}
}
#[cfg(windows)]
#[cfg(feature = "cap_std_impls")]
impl IoExt for cap_std::fs::File {
#[inline]
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>().read(buf)
}
#[inline]
fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
self.as_filelike_view::<std::fs::File>().read_exact(buf)
}
#[inline]
fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>().read_vectored(bufs)
}
#[inline]
fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>().read_to_end(buf)
}
#[inline]
fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>().read_to_string(buf)
}
#[inline]
fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>().peek(buf)
}
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>().write(buf)
}
#[inline]
fn write_all(&self, buf: &[u8]) -> io::Result<()> {
self.as_filelike_view::<std::fs::File>().write_all(buf)
}
#[inline]
fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>()
.write_vectored(bufs)
}
#[inline]
fn flush(&self) -> io::Result<()> {
self.as_filelike_view::<std::fs::File>().flush()
}
#[inline]
fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
self.as_filelike_view::<std::fs::File>().write_fmt(fmt)
}
}
#[cfg(windows)]
#[cfg(feature = "cap_std_impls_fs_utf8")]
impl IoExt for cap_std::fs_utf8::File {
#[inline]
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>().read(buf)
}
#[inline]
fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
self.as_filelike_view::<std::fs::File>().read_exact(buf)
}
#[inline]
fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>().read_vectored(bufs)
}
#[inline]
fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>().read_to_end(buf)
}
#[inline]
fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>().read_to_string(buf)
}
#[inline]
fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>().peek(buf)
}
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>().write(buf)
}
#[inline]
fn write_all(&self, buf: &[u8]) -> io::Result<()> {
self.as_filelike_view::<std::fs::File>().write_all(buf)
}
#[inline]
fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
self.as_filelike_view::<std::fs::File>()
.write_vectored(bufs)
}
#[inline]
fn flush(&self) -> io::Result<()> {
self.as_filelike_view::<std::fs::File>().flush()
}
#[inline]
fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
self.as_filelike_view::<std::fs::File>().write_fmt(fmt)
}
}
#[cfg(windows)]
impl IoExt for std::net::TcpStream {
#[inline]
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
Read::read(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), buf)
}
#[inline]
fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
Read::read_exact(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), buf)
}
#[inline]
fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
Read::read_vectored(
&mut &*self.as_socketlike_view::<std::net::TcpStream>(),
bufs,
)
}
#[inline]
fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
Read::read_to_end(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), buf)
}
#[inline]
fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
Read::read_to_string(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), buf)
}
#[inline]
fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.as_socketlike_view::<std::net::TcpStream>().peek(buf)
}
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
Write::write(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), buf)
}
#[inline]
fn write_all(&self, buf: &[u8]) -> io::Result<()> {
Write::write_all(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), buf)
}
#[inline]
fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
Write::write_vectored(
&mut &*self.as_socketlike_view::<std::net::TcpStream>(),
bufs,
)
}
#[inline]
fn flush(&self) -> io::Result<()> {
Write::flush(&mut &*self.as_socketlike_view::<std::net::TcpStream>())
}
#[inline]
fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
Write::write_fmt(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), fmt)
}
}
#[cfg(windows)]
#[cfg(feature = "cap_std_impls")]
impl IoExt for cap_std::net::TcpStream {
#[inline]
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.as_socketlike_view::<std::net::TcpStream>().read(buf)
}
#[inline]
fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
self.as_socketlike_view::<std::net::TcpStream>()
.read_exact(buf)
}
#[inline]
fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
self.as_socketlike_view::<std::net::TcpStream>()
.read_vectored(bufs)
}
#[inline]
fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.as_socketlike_view::<std::net::TcpStream>()
.read_to_end(buf)
}
#[inline]
fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
self.as_socketlike_view::<std::net::TcpStream>()
.read_to_string(buf)
}
#[inline]
fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.as_socketlike_view::<std::net::TcpStream>().peek(buf)
}
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.as_socketlike_view::<std::net::TcpStream>().write(buf)
}
#[inline]
fn write_all(&self, buf: &[u8]) -> io::Result<()> {
self.as_socketlike_view::<std::net::TcpStream>()
.write_all(buf)
}
#[inline]
fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
self.as_socketlike_view::<std::net::TcpStream>()
.write_vectored(bufs)
}
#[inline]
fn flush(&self) -> io::Result<()> {
self.as_socketlike_view::<std::net::TcpStream>().flush()
}
#[inline]
fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
self.as_socketlike_view::<std::net::TcpStream>()
.write_fmt(fmt)
}
}
fn _io_ext_can_be_trait_object(_: &dyn IoExt) {}