#[cfg(any(
windows,
not(any(
target_os = "linux",
target_os = "android",
target_vendor = "apple",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd"
))
))]
use std::io;
use crate::buf::vectored::IoVec;
#[cfg(unix)]
mod unix {
use std::io;
use std::os::fd::RawFd;
use super::IoVec;
use crate::io::sys::unix::{SEND_FLAGS, cvt, file_offset, retry};
fn count(iov: &[IoVec]) -> libc::c_int {
libc::c_int::try_from(iov.len()).unwrap_or(libc::c_int::MAX)
}
pub(crate) fn writev(fd: RawFd, iov: &[IoVec]) -> io::Result<usize> {
retry(|| cvt(unsafe { libc::writev(fd, iov.as_ptr(), count(iov)) }))
}
pub(crate) fn sendv(fd: RawFd, iov: &[IoVec]) -> io::Result<usize> {
let mut msg: libc::msghdr = unsafe { core::mem::zeroed() };
msg.msg_iov = iov.as_ptr().cast_mut();
msg.msg_iovlen = iov.len() as _;
retry(|| cvt(unsafe { libc::sendmsg(fd, &msg, SEND_FLAGS) }))
}
pub(crate) fn readv(fd: RawFd, iov: &mut [IoVec]) -> io::Result<usize> {
retry(|| cvt(unsafe { libc::readv(fd, iov.as_ptr(), count(iov)) }))
}
#[cfg(any(
target_os = "linux",
target_os = "android",
target_vendor = "apple",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd"
))]
pub(crate) fn preadv(fd: RawFd, iov: &mut [IoVec], offset: u64) -> io::Result<usize> {
let at = file_offset(offset)?;
retry(|| cvt(unsafe { libc::preadv(fd, iov.as_ptr(), count(iov), at) }))
}
#[cfg(any(
target_os = "linux",
target_os = "android",
target_vendor = "apple",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd"
))]
pub(crate) fn pwritev(fd: RawFd, iov: &[IoVec], offset: u64) -> io::Result<usize> {
let at = file_offset(offset)?;
retry(|| cvt(unsafe { libc::pwritev(fd, iov.as_ptr(), count(iov), at) }))
}
#[cfg(not(any(
target_os = "linux",
target_os = "android",
target_vendor = "apple",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd"
)))]
pub(crate) fn preadv(fd: RawFd, iov: &mut [IoVec], offset: u64) -> io::Result<usize> {
super::each_read(iov, offset, |ptr, len, at| {
let room = unsafe { core::slice::from_raw_parts_mut(ptr, len) };
crate::io::sys::pread(fd, room, at)
})
}
#[cfg(not(any(
target_os = "linux",
target_os = "android",
target_vendor = "apple",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd"
)))]
pub(crate) fn pwritev(fd: RawFd, iov: &[IoVec], offset: u64) -> io::Result<usize> {
super::each_write(iov, offset, |bytes, at| {
crate::io::sys::pwrite_all(fd, bytes, at)
})
}
}
#[cfg(unix)]
pub(crate) use self::unix::*;
#[cfg(windows)]
mod windows {
use std::io;
use super::IoVec;
use crate::io::raw::Raw;
use crate::io::sys::windows::{read_at, write_all_at};
pub(crate) fn preadv(raw: Raw, iov: &mut [IoVec], offset: u64) -> io::Result<usize> {
super::each_read(iov, offset, |ptr, len, at| read_at(raw, ptr, len, at))
}
pub(crate) fn pwritev(raw: Raw, iov: &[IoVec], offset: u64) -> io::Result<usize> {
super::each_write(iov, offset, |bytes, at| write_all_at(raw, bytes, Some(at)))
}
}
#[cfg(windows)]
pub(crate) use self::windows::*;
#[cfg(any(
windows,
not(any(
target_os = "linux",
target_os = "android",
target_vendor = "apple",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd"
))
))]
fn parts(iov: &IoVec) -> (*mut u8, usize) {
#[cfg(unix)]
return (iov.iov_base.cast(), iov.iov_len);
#[cfg(windows)]
return (iov.buf, iov.len as usize);
}
#[cfg(any(
windows,
not(any(
target_os = "linux",
target_os = "android",
target_vendor = "apple",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd"
))
))]
fn each_read(
iov: &mut [IoVec],
offset: u64,
mut read: impl FnMut(*mut u8, usize, u64) -> io::Result<usize>,
) -> io::Result<usize> {
let mut done = 0;
for room in iov.iter() {
let (ptr, len) = parts(room);
let n = match read(ptr, len, offset + done as u64) {
Ok(n) => n,
Err(err) if done == 0 => return Err(err),
Err(_) => return Ok(done),
};
done += n;
if n < len {
break;
}
}
Ok(done)
}
#[cfg(any(
windows,
not(any(
target_os = "linux",
target_os = "android",
target_vendor = "apple",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd"
))
))]
fn each_write(
iov: &[IoVec],
offset: u64,
mut write: impl FnMut(&[u8], u64) -> io::Result<()>,
) -> io::Result<usize> {
let mut done = 0;
for bytes in iov {
let (ptr, len) = parts(bytes);
let bytes = unsafe { core::slice::from_raw_parts(ptr.cast_const(), len) };
match write(bytes, offset + done as u64) {
Ok(()) => done += len,
Err(err) if done == 0 => return Err(err),
Err(_) => return Ok(done),
}
}
Ok(done)
}