#![cfg_attr(not(any(test, feature = "std")), no_std)]
#![cfg_attr(feature = "nightly", feature(min_const_generics, slice_fill))]
#[cfg(all(unix, windows))]
compile_error!("cannot compile for both windows and unix");
mod private {
pub trait Sealed {}
}
pub unsafe trait Initialization: private::Sealed {
const IS_INITIALIZED: bool;
type DerefTargetItem: fmt::Debug;
}
pub enum Initialized {}
pub enum Uninitialized {}
impl private::Sealed for Initialized {}
impl private::Sealed for Uninitialized {}
unsafe impl Initialization for Initialized {
const IS_INITIALIZED: bool = true;
type DerefTargetItem = u8;
}
unsafe impl Initialization for Uninitialized {
const IS_INITIALIZED: bool = false;
type DerefTargetItem = MaybeUninit<u8>;
}
use core::borrow::{Borrow, BorrowMut};
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::{cmp, fmt, hash, ops};
#[allow(unused_imports)]
use core::mem;
#[cfg(all(windows, feature = "winapi"))]
use winapi::shared::{
ntdef::{CHAR, ULONG},
ws2def::WSABUF,
};
#[cfg(feature = "alloc")]
extern crate alloc;
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct IoSlice<'a, I: Initialization = Initialized> {
#[cfg(all(unix, feature = "libc"))]
inner: (libc::iovec, PhantomData<&'a [I::DerefTargetItem]>),
#[cfg(all(windows, feature = "winapi"))]
inner: (WSABUF, PhantomData<&'a [I::DerefTargetItem]>),
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
inner: &'a [I::DerefTargetItem],
_marker: PhantomData<I>,
}
unsafe impl<'a, I: Initialization> Send for IoSlice<'a, I> {}
unsafe impl<'a, I: Initialization> Sync for IoSlice<'a, I> {}
impl<'a, I: Initialization> Unpin for IoSlice<'a, I> {}
#[cfg(feature = "std")]
impl<'a, I: Initialization> std::panic::UnwindSafe for IoSlice<'a, I> {}
#[cfg(feature = "std")]
impl<'a, I: Initialization> std::panic::RefUnwindSafe for IoSlice<'a, I> {}
impl<'a, I: Initialization> IoSlice<'a, I> {
#[inline]
pub fn new(slice: &'a [u8]) -> Self {
unsafe { Self::__construct(slice.as_ptr(), slice.len()) }
}
#[inline]
pub fn as_uninit(&self) -> &IoSlice<'a, Uninitialized> {
unsafe { &*(self as *const Self as *const IoSlice<'a, Uninitialized>) }
}
#[inline]
pub fn as_uninit_mut(&mut self) -> &mut IoSlice<'a, Uninitialized> {
unsafe { &mut *(self as *mut Self as *mut IoSlice<'a, Uninitialized>) }
}
#[inline]
pub fn into_uninit(self) -> IoSlice<'a, Uninitialized> {
unsafe { IoSlice::__construct(self.__ptr(), self.__len()) }
}
#[inline]
pub unsafe fn assume_init(self) -> IoSlice<'a, Initialized> {
IoSlice::__construct(self.__ptr(), self.__len())
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub unsafe fn from_raw_iovec(slice: libc::iovec) -> Self {
Self {
inner: (slice, PhantomData),
_marker: PhantomData,
}
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub fn as_raw_iovec(&self) -> libc::iovec {
self.inner.0
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub fn cast_to_raw_iovecs(slices: &'a [Self]) -> &'a [libc::iovec] {
unsafe { core::slice::from_raw_parts(slices.as_ptr() as *const libc::iovec, slices.len()) }
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub unsafe fn cast_to_raw_iovecs_mut(slices: &'a mut [Self]) -> &'a mut [libc::iovec] {
core::slice::from_raw_parts_mut(slices.as_mut_ptr() as *mut libc::iovec, slices.len())
}
#[inline]
pub fn advance(&mut self, count: usize) {
unsafe {
self.__set_len(
self.__len()
.checked_sub(count)
.expect("IoSlice::advance causes length to overflow"),
);
self.__set_ptr(self.__ptr().add(count));
}
}
#[must_use]
pub fn advance_within(mut slices: &mut [Self], mut n: usize) -> Option<&mut [Self]> {
while let Some(buffer) = slices.first_mut() {
if n == 0 {
return Some(slices);
};
let buffer_len = buffer.len();
if buffer_len > n {
buffer.advance(n);
} else {
slices = &mut slices[1..];
}
n -= core::cmp::min(buffer_len, n);
}
if n > 0 {
return None;
}
Some(slices)
}
#[inline]
pub fn inner_data(&self) -> &'a [I::DerefTargetItem] {
#[cfg(all(unix, feature = "libc"))]
return unsafe {
core::slice::from_raw_parts(self.inner.0.iov_base as *const _, self.inner.0.iov_len)
};
#[cfg(all(windows, feature = "winapi"))]
return unsafe {
core::slice::from_raw_parts(self.inner.0.buf as *const _, self.inner.0.len as usize)
};
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
return unsafe {
core::slice::from_raw_parts(self.inner.as_ptr() as *const _, self.inner.len())
};
}
#[inline]
pub fn from_inner_data(inner_data: &'a [I::DerefTargetItem]) -> Self {
Self {
#[cfg(all(unix, feature = "libc"))]
inner: (
libc::iovec {
iov_base: inner_data.as_ptr() as *mut libc::c_void,
iov_len: inner_data.len(),
},
PhantomData,
),
#[cfg(all(windows, feature = "winapi"))]
inner: (
WSABUF {
len: inner_data.len() as ULONG,
buf: inner_data.as_ptr() as *mut CHAR,
},
PhantomData,
),
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
inner: inner_data,
_marker: PhantomData,
}
}
#[inline]
pub fn as_maybe_uninit_slice(&self) -> &'a [MaybeUninit<u8>] {
self.as_uninit().inner_data()
}
fn __ptr(&self) -> *const u8 {
#[cfg(all(unix, feature = "libc"))]
return self.inner.0.iov_base as *const u8;
#[cfg(all(windows, feature = "winapi"))]
return self.inner.0.buf as *const u8;
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
return self.inner.as_ptr() as *const u8;
}
fn __len(&self) -> usize {
#[cfg(all(unix, feature = "libc"))]
return self.inner.0.iov_len as usize;
#[cfg(all(windows, feature = "winapi"))]
return self.inner.0.len as usize;
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
return self.inner.len();
}
#[inline]
unsafe fn __set_ptr(&mut self, ptr: *const u8) {
#[cfg(all(unix, feature = "libc"))]
{
self.inner.0.iov_base = ptr as *mut libc::c_void;
}
#[cfg(all(windows, feature = "winapi"))]
{
self.inner.0.buf = ptr as *mut CHAR;
}
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
{
self.inner =
core::slice::from_raw_parts(ptr as *const I::DerefTargetItem, self.__len());
}
}
#[inline]
unsafe fn __set_len(&mut self, len: usize) {
#[cfg(all(unix, feature = "libc"))]
{
self.inner.0.iov_len = len as usize;
}
#[cfg(all(windows, feature = "libc"))]
{
use core::convert::TryInto;
self.inner.0.len = len
.try_into()
.expect("length exceeding 2^32 bytes, which is the limit of WSABUF");
}
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
{
self.inner =
core::slice::from_raw_parts(self.__ptr() as *const I::DerefTargetItem, len);
}
}
unsafe fn __construct(ptr: *const u8, len: usize) -> Self {
#[cfg(all(windows, feature = "winapi"))]
use core::convert::TryInto;
Self {
#[cfg(all(unix, feature = "libc"))]
inner: (
libc::iovec {
iov_base: ptr as *mut libc::c_void,
iov_len: len as usize,
},
PhantomData,
),
#[cfg(all(windows, feature = "winapi"))]
inner: (
WSABUF {
len: len.try_into().expect(
"Constructing an IoSlice that is larger than the 2^32 limit of WSABUF",
),
buf: ptr as *mut CHAR,
},
PhantomData,
),
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
inner: { core::slice::from_raw_parts(ptr as *const I::DerefTargetItem, len) },
_marker: PhantomData,
}
}
}
impl<'a> IoSlice<'a, Initialized> {
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
self.inner_data()
}
#[cfg(feature = "std")]
#[inline]
pub fn into_std_ioslice(self) -> std::io::IoSlice<'a> {
std::io::IoSlice::new(self.as_slice())
}
#[cfg(feature = "std")]
#[inline]
pub fn cast_to_std_ioslices<'b>(slices: &'b [Self]) -> &'b [std::io::IoSlice<'a>] {
unsafe {
core::slice::from_raw_parts(
slices.as_ptr() as *const std::io::IoSlice<'a>,
slices.len(),
)
}
}
#[cfg(feature = "std")]
#[inline]
pub fn cast_to_std_ioslices_mut(slices: &'a mut [Self]) -> &'a mut [std::io::IoSlice<'a>] {
unsafe {
core::slice::from_raw_parts_mut(
slices.as_mut_ptr() as *mut std::io::IoSlice<'a>,
slices.len(),
)
}
}
}
impl<'a, I: Initialization> fmt::Debug for IoSlice<'a, I> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if I::IS_INITIALIZED {
write!(f, "{:?}", self.inner_data())
} else {
write!(
f,
"[possibly uninitialized immutable I/O slice at {:p}, len {} bytes]",
self.as_maybe_uninit_slice().as_ptr(),
self.as_maybe_uninit_slice().len()
)
}
}
}
impl<'a, I: Initialization> AsRef<[I::DerefTargetItem]> for IoSlice<'a, I> {
#[inline]
fn as_ref(&self) -> &[I::DerefTargetItem] {
self.inner_data()
}
}
impl<'a, I: Initialization> Borrow<[I::DerefTargetItem]> for IoSlice<'a, I> {
#[inline]
fn borrow(&self) -> &[I::DerefTargetItem] {
self.inner_data()
}
}
impl<'a, I: Initialization> ops::Deref for IoSlice<'a, I> {
type Target = [I::DerefTargetItem];
#[inline]
fn deref(&self) -> &Self::Target {
self.inner_data()
}
}
impl<'a, I: Initialization> From<&'a [I::DerefTargetItem]> for IoSlice<'a, I> {
#[inline]
fn from(slice: &'a [I::DerefTargetItem]) -> Self {
Self::from_inner_data(slice)
}
}
impl<'a, I: Initialization> From<&'a mut [I::DerefTargetItem]> for IoSlice<'a, I> {
#[inline]
fn from(slice: &'a mut [I::DerefTargetItem]) -> Self {
Self::from_inner_data(&*slice)
}
}
impl<'a> From<&'a [u8]> for IoSlice<'a, Uninitialized> {
fn from(maybe_uninit_slice: &'a [u8]) -> Self {
Self::new(maybe_uninit_slice)
}
}
impl<'a> From<&'a mut [u8]> for IoSlice<'a, Uninitialized> {
fn from(maybe_uninit_slice: &'a mut [u8]) -> Self {
Self::new(&*maybe_uninit_slice)
}
}
#[cfg(feature = "nightly")]
impl<'a, I: Initialization, const N: usize> From<&'a [I::DerefTargetItem; N]> for IoSlice<'a, I> {
#[inline]
fn from(array_ref: &'a [I::DerefTargetItem; N]) -> Self {
Self::from_inner_data(&array_ref[..])
}
}
#[cfg(feature = "nightly")]
impl<'a, I: Initialization, const N: usize> From<&'a mut [I::DerefTargetItem; N]>
for IoSlice<'a, I>
{
#[inline]
fn from(array_ref: &'a mut [I::DerefTargetItem; N]) -> Self {
Self::from_inner_data(&array_ref[..])
}
}
#[cfg(feature = "nightly")]
impl<'a, const N: usize> From<&'a [u8; N]> for IoSlice<'a, Uninitialized> {
#[inline]
fn from(array_ref: &'a [u8; N]) -> Self {
Self::new(&array_ref[..])
}
}
#[cfg(feature = "nightly")]
impl<'a, const N: usize> From<&'a mut [u8; N]> for IoSlice<'a, Uninitialized> {
#[inline]
fn from(array_ref: &'a mut [u8; N]) -> Self {
Self::new(&array_ref[..])
}
}
impl<'a> PartialEq for IoSlice<'a, Initialized> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self == other.as_slice()
}
}
impl<'a> PartialEq<[u8]> for IoSlice<'a, Initialized> {
#[inline]
fn eq(&self, other: &[u8]) -> bool {
self.as_slice() == other
}
}
#[cfg(feature = "nightly")]
impl<'a, const N: usize> PartialEq<[u8; N]> for IoSlice<'a, Initialized> {
#[inline]
fn eq(&self, other: &[u8; N]) -> bool {
self == &other[..]
}
}
impl<'a, 'b> PartialEq<IoSliceMut<'b, Initialized>> for IoSlice<'a, Initialized> {
#[inline]
fn eq(&self, other: &IoSliceMut<'b>) -> bool {
self == other.as_slice()
}
}
impl<'a> Eq for IoSlice<'a, Initialized> {}
impl<'a> PartialOrd<[u8]> for IoSlice<'a, Initialized> {
#[inline]
fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(self.as_slice(), other)
}
}
impl<'a, 'b> PartialOrd<IoSliceMut<'b, Initialized>> for IoSlice<'a, Initialized> {
#[inline]
fn partial_cmp(&self, other: &IoSliceMut<'b>) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(self.as_slice(), other.as_slice())
}
}
#[cfg(feature = "nightly")]
impl<'a, const N: usize> PartialOrd<[u8; N]> for IoSlice<'a, Initialized> {
#[inline]
fn partial_cmp(&self, other: &[u8; N]) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(self.as_slice(), other)
}
}
impl<'a> PartialOrd for IoSlice<'a, Initialized> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(Ord::cmp(self, other))
}
}
impl<'a> Ord for IoSlice<'a, Initialized> {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
Ord::cmp(self.as_slice(), other.as_slice())
}
}
impl<'a, I: Initialization> Default for IoSlice<'a, I> {
#[inline]
fn default() -> Self {
Self::new(&[])
}
}
impl<'a> hash::Hash for IoSlice<'a, Initialized> {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
state.write(self.as_slice())
}
}
#[cfg(feature = "std")]
impl<'a, I: Initialization> From<std::io::IoSlice<'a>> for IoSlice<'a, I> {
#[inline]
fn from(slice: std::io::IoSlice<'a>) -> Self {
Self {
#[cfg(all(unix, feature = "libc"))]
inner: (
libc::iovec {
iov_base: slice.as_ptr() as *mut libc::c_void,
iov_len: slice.len(),
},
PhantomData,
),
#[cfg(all(windows, feature = "winapi"))]
inner: (
WSABUF {
len: slice.len() as ULONG,
buf: slice.as_ptr() as *mut CHAR,
},
PhantomData,
),
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
inner: unsafe {
core::slice::from_raw_parts(
slice.as_ptr() as *const I::DerefTargetItem,
slice.len(),
)
},
_marker: PhantomData,
}
}
}
#[cfg(feature = "std")]
impl<'a, I: Initialization> From<std::io::IoSliceMut<'a>> for IoSlice<'a, I> {
#[inline]
fn from(mut slice: std::io::IoSliceMut<'a>) -> Self {
unsafe { Self::__construct(slice.as_mut_ptr(), slice.len()) }
}
}
#[cfg(all(unix, feature = "libc"))]
impl<'a, I: Initialization> From<IoSlice<'a, I>> for libc::iovec {
#[inline]
fn from(slice: IoSlice<'a, I>) -> Self {
slice.as_raw_iovec()
}
}
#[cfg(feature = "stable_deref_trait")]
unsafe impl<'a, I: Initialization> stable_deref_trait::StableDeref for IoSlice<'a, I> {}
#[repr(transparent)]
pub struct IoSliceMut<'a, I: Initialization = Initialized> {
#[cfg(all(unix, feature = "libc"))]
inner: (libc::iovec, PhantomData<&'a mut [I::DerefTargetItem]>),
#[cfg(all(windows, feature = "winapi"))]
inner: (WSABUF, PhantomData<&'a mut [I::DerefTargetItem]>),
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
inner: &'a mut [I::DerefTargetItem],
_marker: PhantomData<I>,
}
unsafe impl<'a, I: Initialization> Send for IoSliceMut<'a, I> {}
unsafe impl<'a, I: Initialization> Sync for IoSliceMut<'a, I> {}
impl<'a, I: Initialization> Unpin for IoSliceMut<'a, I> {}
#[cfg(feature = "std")]
impl<'a, I: Initialization> std::panic::UnwindSafe for IoSliceMut<'a, I> {}
#[cfg(feature = "std")]
impl<'a, I: Initialization> std::panic::RefUnwindSafe for IoSliceMut<'a, I> {}
impl<'a, I: Initialization> IoSliceMut<'a, I> {
#[inline]
pub fn new(slice: &'a mut [u8]) -> Self {
unsafe { Self::__construct(slice.as_mut_ptr(), slice.len()) }
}
#[inline]
pub unsafe fn assume_init(self) -> IoSliceMut<'a, Initialized> {
IoSliceMut::__construct(self.__ptr(), self.__len())
}
#[inline]
pub unsafe fn assume_init_ref(&self) -> &IoSliceMut<'a, Initialized> {
&*(self as *const Self as *const IoSliceMut<'a, Initialized>)
}
#[inline]
pub unsafe fn assume_init_mut(&mut self) -> &mut IoSliceMut<'a, Initialized> {
&mut *(self as *mut Self as *mut IoSliceMut<'a, Initialized>)
}
#[inline]
pub fn into_uninit(self) -> IoSliceMut<'a, Uninitialized> {
unsafe { IoSliceMut::__construct(self.__ptr(), self.__len()) }
}
pub fn as_uninit(&self) -> &IoSliceMut<'a, Uninitialized> {
unsafe { &*(self as *const Self as *const IoSliceMut<'a, Uninitialized>) }
}
pub fn as_uninit_mut(&mut self) -> &mut IoSliceMut<'a, Uninitialized> {
unsafe { &mut *(self as *mut Self as *mut IoSliceMut<'a, Uninitialized>) }
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub unsafe fn from_raw_iovec(slice: libc::iovec) -> Self {
Self {
inner: (slice, PhantomData),
_marker: PhantomData,
}
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub fn as_raw_iovec(&self) -> libc::iovec {
self.inner.0
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub fn as_raw_iovec_mut(&mut self) -> libc::iovec {
self.inner.0
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub fn cast_to_raw_iovecs(slices: &[Self]) -> &[libc::iovec] {
unsafe { core::slice::from_raw_parts(slices.as_ptr() as *const libc::iovec, slices.len()) }
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub unsafe fn cast_to_raw_iovecs_mut(slices: &mut [Self]) -> &mut [libc::iovec] {
core::slice::from_raw_parts_mut(slices.as_mut_ptr() as *mut libc::iovec, slices.len())
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub unsafe fn from_raw_iovecs(slice: &[libc::iovec]) -> &[Self] {
core::slice::from_raw_parts(slice.as_ptr() as *const Self, slice.len())
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub unsafe fn from_raw_iovecs_mut(slice: &mut [libc::iovec]) -> &mut [Self] {
core::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut Self, slice.len())
}
#[inline]
pub fn advance(&mut self, count: usize) {
unsafe {
self.__set_len(
self.__len()
.checked_sub(count)
.expect("IoSlice::advance causes length to overflow"),
);
self.__set_ptr(self.__ptr().add(count));
}
}
#[must_use]
#[inline]
pub fn advance_within(mut slices: &mut [Self], mut n: usize) -> Option<&mut [Self]> {
while let Some(buffer) = slices.first_mut() {
if n == 0 {
return Some(slices);
};
let buffer_len = buffer.len();
if buffer_len > n {
buffer.advance(n);
} else {
slices = &mut slices[1..];
}
n -= core::cmp::min(buffer_len, n);
}
if n > 0 {
return None;
}
Some(slices)
}
#[inline]
pub fn inner_data(&self) -> &[I::DerefTargetItem] {
unsafe {
core::slice::from_raw_parts(self.__ptr() as *const I::DerefTargetItem, self.__len())
}
}
#[inline]
pub fn inner_data_mut(&mut self) -> &mut [I::DerefTargetItem] {
unsafe {
core::slice::from_raw_parts_mut(self.__ptr() as *mut I::DerefTargetItem, self.__len())
}
}
#[inline]
pub fn into_inner_data(self) -> &'a mut [I::DerefTargetItem] {
unsafe {
core::slice::from_raw_parts_mut(self.__ptr() as *mut I::DerefTargetItem, self.__len())
}
}
#[inline]
pub fn from_inner_data(inner_data: &'a mut [I::DerefTargetItem]) -> Self {
unsafe { Self::__construct(inner_data.as_mut_ptr() as *mut u8, inner_data.len()) }
}
#[inline]
pub fn as_maybe_uninit_slice(&self) -> &[MaybeUninit<u8>] {
self.as_uninit().inner_data()
}
#[inline]
pub fn as_maybe_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<u8>] {
self.as_uninit_mut().inner_data_mut()
}
#[inline]
#[must_use]
pub fn zeroed(mut self) -> IoSliceMut<'a, Initialized> {
#[cfg(feature = "nightly")]
{
self.as_maybe_uninit_slice_mut().fill(MaybeUninit::new(0));
}
#[cfg(not(feature = "nightly"))]
{
for byte in self.as_maybe_uninit_slice_mut() {
*byte = MaybeUninit::new(0);
}
}
unsafe { self.assume_init() }
}
#[inline]
#[must_use]
pub fn zeroed_by_ref<'b>(&'b mut self) -> &'b mut IoSliceMut<'a, Initialized> {
#[cfg(feature = "nightly")]
{
self.as_maybe_uninit_slice_mut().fill(MaybeUninit::new(0));
}
#[cfg(not(feature = "nightly"))]
{
for byte in self.as_maybe_uninit_slice_mut() {
*byte = MaybeUninit::new(0);
}
}
unsafe { self.assume_init_mut() }
}
#[inline]
fn __ptr(&self) -> *mut u8 {
#[cfg(all(unix, feature = "libc"))]
return self.inner.0.iov_base as *mut u8;
#[cfg(all(windows, feature = "libc"))]
return self.inner.0.buf as *mut u8;
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
return self.inner.as_ptr() as *mut u8;
}
#[inline]
fn __len(&self) -> usize {
#[cfg(all(unix, feature = "libc"))]
return self.inner.0.iov_len as usize;
#[cfg(all(windows, feature = "libc"))]
return self.inner.0.len as usize;
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
return self.inner.len();
}
#[inline]
unsafe fn __set_ptr(&mut self, ptr: *mut u8) {
#[cfg(all(unix, feature = "libc"))]
{
self.inner.0.iov_base = ptr as *mut libc::c_void;
}
#[cfg(all(windows, feature = "winapi"))]
{
self.inner.0.buf = ptr as *mut CHAR;
}
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
{
self.inner =
core::slice::from_raw_parts_mut(ptr as *mut I::DerefTargetItem, self.__len());
}
}
#[inline]
unsafe fn __set_len(&mut self, len: usize) {
#[cfg(all(unix, feature = "libc"))]
{
self.inner.0.iov_len = len as usize;
}
#[cfg(all(windows, feature = "libc"))]
{
use core::convert::TryInto;
self.inner.0.len = len
.try_into()
.expect("length exceeding 2^32 bytes, which is the limit of WSABUF");
}
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
{
self.inner =
core::slice::from_raw_parts_mut(self.__ptr() as *mut I::DerefTargetItem, len);
}
}
#[inline]
unsafe fn __construct(ptr: *mut u8, len: usize) -> Self {
#[cfg(all(windows, feature = "winapi"))]
use core::convert::TryInto;
Self {
#[cfg(all(unix, feature = "libc"))]
inner: (
libc::iovec {
iov_base: ptr as *mut libc::c_void,
iov_len: len as usize,
},
PhantomData,
),
#[cfg(all(windows, feature = "winapi"))]
inner: (
WSABUF {
len: len.try_into().expect(
"constructing an IoSlice that is larger than the 2^32 limits of WSABUF",
),
buf: ptr as *mut CHAR,
},
PhantomData,
),
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
inner: { core::slice::from_raw_parts_mut(ptr as *mut I::DerefTargetItem, len) },
_marker: PhantomData,
}
}
}
impl<'a> IoSliceMut<'a, Initialized> {
#[inline]
pub fn as_slice(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self.__ptr() as *const u8, self.__len()) }
}
#[inline]
pub fn into_slice(self) -> &'a [u8] {
&*self.into_slice_mut()
}
#[inline]
pub fn as_slice_mut(&mut self) -> &mut [u8] {
unsafe { core::slice::from_raw_parts_mut(self.__ptr(), self.__len()) }
}
#[inline]
pub fn into_slice_mut(self) -> &'a mut [u8] {
unsafe { core::slice::from_raw_parts_mut(self.__ptr(), self.__len()) }
}
#[cfg(feature = "std")]
#[inline]
pub fn cast_to_std_ioslices<'b>(slices: &'b [Self]) -> &'b [std::io::IoSlice<'a>] {
unsafe {
core::slice::from_raw_parts(
slices.as_ptr() as *const std::io::IoSlice<'a>,
slices.len(),
)
}
}
#[cfg(feature = "std")]
#[inline]
pub fn cast_to_std_mut_ioslices<'b>(slices: &'b [Self]) -> &'b [std::io::IoSliceMut<'a>] {
unsafe {
core::slice::from_raw_parts(slices.as_ptr() as *const std::io::IoSliceMut, slices.len())
}
}
#[cfg(feature = "std")]
#[inline]
pub fn cast_to_std_ioslices_mut<'b>(slices: &'b mut [Self]) -> &'b mut [std::io::IoSlice<'a>] {
unsafe {
core::slice::from_raw_parts_mut(
slices.as_mut_ptr() as *mut std::io::IoSlice<'a>,
slices.len(),
)
}
}
#[cfg(feature = "std")]
#[inline]
pub fn cast_to_std_mut_ioslices_mut(
slices: &'a mut [Self],
) -> &'a mut [std::io::IoSliceMut<'a>] {
unsafe {
core::slice::from_raw_parts_mut(
slices.as_mut_ptr() as *mut std::io::IoSliceMut<'a>,
slices.len(),
)
}
}
}
impl<'a, I: Initialization> AsRef<[I::DerefTargetItem]> for IoSliceMut<'a, I> {
#[inline]
fn as_ref(&self) -> &[I::DerefTargetItem] {
self.inner_data()
}
}
impl<'a, I: Initialization> Borrow<[I::DerefTargetItem]> for IoSliceMut<'a, I> {
#[inline]
fn borrow(&self) -> &[I::DerefTargetItem] {
self.inner_data()
}
}
impl<'a, I: Initialization> ops::Deref for IoSliceMut<'a, I> {
type Target = [I::DerefTargetItem];
#[inline]
fn deref(&self) -> &Self::Target {
self.inner_data()
}
}
impl<'a, I: Initialization> AsMut<[I::DerefTargetItem]> for IoSliceMut<'a, I> {
#[inline]
fn as_mut(&mut self) -> &mut [I::DerefTargetItem] {
self.inner_data_mut()
}
}
impl<'a, I: Initialization> BorrowMut<[I::DerefTargetItem]> for IoSliceMut<'a, I> {
#[inline]
fn borrow_mut(&mut self) -> &mut [I::DerefTargetItem] {
self.inner_data_mut()
}
}
impl<'a, I: Initialization> ops::DerefMut for IoSliceMut<'a, I> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner_data_mut()
}
}
#[cfg(all(unix, feature = "libc"))]
impl<'a, I: Initialization> From<IoSliceMut<'a, I>> for libc::iovec {
#[inline]
fn from(slice: IoSliceMut<'a, I>) -> Self {
slice.as_raw_iovec()
}
}
impl<'a, I: Initialization> fmt::Debug for IoSliceMut<'a, I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if I::IS_INITIALIZED {
write!(f, "{:?}", self.inner_data())
} else {
write!(
f,
"[possibly uninitialized mutable I/O slice at {:p}, len {} bytes]",
self.as_maybe_uninit_slice().as_ptr(),
self.as_maybe_uninit_slice().len()
)
}
}
}
impl<'a> PartialEq for IoSliceMut<'a, Initialized> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<'a> PartialEq<[u8]> for IoSliceMut<'a, Initialized> {
#[inline]
fn eq(&self, other: &[u8]) -> bool {
self.as_slice() == other
}
}
impl<'a, 'b> PartialEq<IoSlice<'b, Initialized>> for IoSliceMut<'a, Initialized> {
#[inline]
fn eq(&self, other: &IoSlice<'b>) -> bool {
self.as_slice() == other.as_slice()
}
}
#[cfg(feature = "nightly")]
impl<'a, const N: usize> PartialEq<[u8; N]> for IoSliceMut<'a, Initialized> {
#[inline]
fn eq(&self, other: &[u8; N]) -> bool {
self.as_slice() == &other[..]
}
}
impl<'a> Eq for IoSliceMut<'a, Initialized> {}
impl<'a> PartialOrd for IoSliceMut<'a, Initialized> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(Ord::cmp(self, other))
}
}
impl<'a> PartialOrd<[u8]> for IoSliceMut<'a, Initialized> {
#[inline]
fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(self.as_slice(), other)
}
}
impl<'a, 'b> PartialOrd<IoSlice<'b, Initialized>> for IoSliceMut<'a, Initialized> {
#[inline]
fn partial_cmp(&self, other: &IoSlice<'b, Initialized>) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(self.as_slice(), other.as_slice())
}
}
#[cfg(feature = "nightly")]
impl<'a, const N: usize> PartialOrd<[u8; N]> for IoSliceMut<'a, Initialized> {
#[inline]
fn partial_cmp(&self, other: &[u8; N]) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(self.as_slice(), other)
}
}
impl<'a> Ord for IoSliceMut<'a, Initialized> {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
Ord::cmp(self.as_slice(), other.as_slice())
}
}
impl<'a> hash::Hash for IoSliceMut<'a, Initialized> {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
state.write(self.as_slice())
}
}
impl<'a, I: Initialization> From<&'a mut [I::DerefTargetItem]> for IoSliceMut<'a, I> {
#[inline]
fn from(slice: &'a mut [I::DerefTargetItem]) -> Self {
Self::from_inner_data(slice)
}
}
impl<'a> From<&'a mut [u8]> for IoSliceMut<'a, Uninitialized> {
#[inline]
fn from(slice: &'a mut [u8]) -> Self {
Self::new(slice)
}
}
#[cfg(feature = "nightly")]
impl<'a, I: Initialization, const N: usize> From<&'a mut [I::DerefTargetItem; N]>
for IoSliceMut<'a, I>
{
#[inline]
fn from(slice: &'a mut [I::DerefTargetItem; N]) -> Self {
Self::from_inner_data(slice)
}
}
#[cfg(feature = "stable_deref_trait")]
unsafe impl<'a> stable_deref_trait::StableDeref for IoSliceMut<'a> {}
#[cfg(all(unix, feature = "alloc"))]
mod io_box {
use super::*;
use alloc::alloc::{
alloc as allocate, alloc_zeroed as allocate_zeroed, dealloc as deallocate, Layout,
};
use alloc::boxed::Box;
use alloc::vec::Vec;
#[repr(transparent)]
pub struct IoBox<I: Initialization = Initialized> {
#[cfg(all(unix, feature = "libc"))]
inner: libc::iovec,
#[cfg(not(all(unix, feature = "libc")))]
inner: Box<[I::DerefTargetItem]>,
_marker: PhantomData<I>,
}
pub struct AllocationError(Layout);
impl AllocationError {
pub fn layout(&self) -> &Layout {
&self.0
}
}
impl<I: Initialization> IoBox<I> {
#[inline]
fn try_alloc_inner<J: Initialization>(
length: usize,
zeroed: bool,
) -> Result<IoBox<J>, AllocationError> {
let layout = Layout::from_size_align(
mem::size_of::<u8>()
.checked_mul(length)
.expect("overflow when multiplying length with size of u8"),
mem::align_of::<u8>(),
)
.expect("error when creating allocation layout");
let pointer = match zeroed {
false => unsafe { allocate(layout) },
true => unsafe { allocate_zeroed(layout) },
};
if pointer.is_null() {
return Err(AllocationError(layout));
}
Ok(unsafe { IoBox::from_raw_parts(pointer, length) })
}
#[inline]
pub fn try_alloc_zeroed(length: usize) -> Result<Self, AllocationError> {
Self::try_alloc_inner(length, true)
}
#[inline]
pub fn alloc_zeroed(length: usize) -> Self {
match Self::try_alloc_zeroed(length) {
Ok(boxed) => boxed,
Err(AllocationError(layout)) => alloc::alloc::handle_alloc_error(layout),
}
}
#[inline]
pub fn into_raw_parts(self) -> (*mut u8, usize) {
#[cfg(all(unix, feature = "libc"))]
return {
let iov_base = self.inner.iov_base as *mut u8;
let iov_len = self.inner.iov_len;
core::mem::forget(self);
(iov_base, iov_len)
};
#[cfg(not(all(unix, feature = "libc")))]
return {
let slice_ptr = self.inner.into_raw();
unsafe {
let slice = &*slice_ptr;
(slice.as_mut_ptr(), slice.len())
}
};
}
#[inline]
pub unsafe fn from_raw_parts(base: *mut u8, len: usize) -> Self {
#[cfg(all(unix, feature = "libc"))]
return {
Self {
inner: libc::iovec {
iov_base: base as *mut libc::c_void,
iov_len: len,
},
_marker: PhantomData,
}
};
#[cfg(not(all(unix, feature = "libc")))]
return {
Self {
inner: Box::from_raw(core::slice::from_raw_parts_mut(base, len)),
}
};
}
#[cfg(all(unix, feature = "libc"))]
pub fn into_iovec(self) -> libc::iovec {
let iovec = self.inner;
core::mem::forget(self);
iovec
}
pub fn into_box(self) -> Box<[u8]> {
#[cfg(all(unix, feature = "libc"))]
return {
let (ptr, len) = self.into_raw_parts();
unsafe { Box::from_raw(core::slice::from_raw_parts_mut(ptr, len)) }
};
#[cfg(not(all(unix, feature = "libc")))]
return { io_box.inner };
}
pub fn as_ioslice(&self) -> IoSlice<I> {
IoSlice::from_inner_data(self.inner_data())
}
pub fn as_ioslice_mut(&mut self) -> IoSliceMut<I> {
IoSliceMut::from_inner_data(self.inner_data_mut())
}
pub fn inner_data(&self) -> &[I::DerefTargetItem] {
#[cfg(all(unix, feature = "libc"))]
return unsafe {
core::slice::from_raw_parts(
self.inner.iov_base as *const I::DerefTargetItem,
self.inner.iov_len,
)
};
#[cfg(not(all(unix, feature = "libc")))]
return &*self.inner;
}
pub fn inner_data_mut(&mut self) -> &mut [I::DerefTargetItem] {
#[cfg(all(unix, feature = "libc"))]
return unsafe {
core::slice::from_raw_parts_mut(
self.inner.iov_base as *mut I::DerefTargetItem,
self.inner.iov_len,
)
};
#[cfg(not(all(unix, feature = "libc")))]
return &mut *self.inner;
}
#[inline]
pub fn slice_as_ioslices(these: &[Self]) -> &[IoSlice] {
unsafe { core::slice::from_raw_parts(these.as_ptr() as *const IoSlice, these.len()) }
}
#[inline]
pub fn slice_as_ioslices_mut(these: &mut [Self]) -> &mut [IoSlice] {
unsafe {
core::slice::from_raw_parts_mut(these.as_mut_ptr() as *mut IoSlice, these.len())
}
}
#[inline]
pub fn slice_as_mut_ioslices(these: &[Self]) -> &[IoSliceMut] {
unsafe { core::slice::from_raw_parts(these.as_ptr() as *const IoSliceMut, these.len()) }
}
#[inline]
pub fn slice_as_mut_ioslices_mut(these: &mut [Self]) -> &mut [IoSliceMut] {
unsafe {
core::slice::from_raw_parts_mut(these.as_mut_ptr() as *mut IoSliceMut, these.len())
}
}
#[inline]
pub unsafe fn assume_init(self) -> IoBox<Initialized> {
IoBox {
inner: self.inner,
_marker: PhantomData,
}
}
#[inline]
pub fn as_maybe_uninit_slice(&self) -> &[MaybeUninit<u8>] {
unsafe {
core::slice::from_raw_parts(
self.inner_data().as_ptr() as *const MaybeUninit<u8>,
self.inner_data().len(),
)
}
}
#[inline]
pub fn as_maybe_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<u8>] {
unsafe {
core::slice::from_raw_parts_mut(
self.inner_data_mut().as_mut_ptr() as *mut MaybeUninit<u8>,
self.inner_data_mut().len(),
)
}
}
pub fn zeroed(mut self) -> IoBox<Initialized> {
#[cfg(feature = "nightly")]
{
self.as_maybe_uninit_slice_mut().fill(MaybeUninit::new(0u8));
}
#[cfg(not(feature = "nightly"))]
{
for byte in self.as_maybe_uninit_slice_mut() {
*byte = MaybeUninit::new(0u8);
}
}
unsafe { self.assume_init() }
}
pub fn try_alloc_uninit(length: usize) -> Result<IoBox<Uninitialized>, AllocationError> {
Self::try_alloc_inner(length, false)
}
pub fn alloc_uninit(length: usize) -> IoBox<Uninitialized> {
match Self::try_alloc_uninit(length) {
Ok(boxed) => boxed,
Err(AllocationError(layout)) => alloc::alloc::handle_alloc_error(layout),
}
}
}
impl IoBox<Initialized> {
pub fn as_slice(&self) -> &[u8] {
self.inner_data()
}
pub fn as_slice_mut(&mut self) -> &mut [u8] {
self.inner_data_mut()
}
}
impl<I: Initialization> Drop for IoBox<I> {
fn drop(&mut self) {
#[cfg(all(unix, feature = "libc"))]
unsafe {
deallocate(
self.inner.iov_base as *mut u8,
Layout::from_size_align(
self.inner
.iov_len
.checked_mul(mem::size_of::<u8>())
.unwrap(),
mem::align_of::<u8>(),
)
.unwrap(),
);
}
}
}
impl From<Box<[u8]>> for IoBox {
fn from(boxed: Box<[u8]>) -> Self {
Self {
#[cfg(all(unix, feature = "libc"))]
inner: {
let slice_ptr = Box::into_raw(boxed);
let iov_len = unsafe { &*slice_ptr }.len();
let iov_base = unsafe { &*slice_ptr }.as_ptr() as *mut libc::c_void;
libc::iovec { iov_base, iov_len }
},
#[cfg(not(all(unix, feature = "libc")))]
inner: boxed,
_marker: PhantomData,
}
}
}
impl From<Vec<u8>> for IoBox {
fn from(vector: Vec<u8>) -> Self {
Self::from(vector.into_boxed_slice())
}
}
impl From<IoBox> for Box<[u8]> {
fn from(io_box: IoBox) -> Self {
io_box.into_box()
}
}
impl From<IoBox> for Vec<u8> {
fn from(io_box: IoBox) -> Self {
Self::from(Box::from(io_box))
}
}
impl core::fmt::Debug for IoBox {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.as_slice())
}
}
impl core::ops::Deref for IoBox {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.as_slice()
}
}
impl core::ops::DerefMut for IoBox {
fn deref_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
impl AsRef<[u8]> for IoBox {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl AsMut<[u8]> for IoBox {
fn as_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
impl core::borrow::Borrow<[u8]> for IoBox {
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}
impl core::borrow::BorrowMut<[u8]> for IoBox {
fn borrow_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
impl PartialEq for IoBox {
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl PartialEq<[u8]> for IoBox {
fn eq(&self, other: &[u8]) -> bool {
self.as_slice() == other
}
}
impl<'a> PartialEq<IoSlice<'a>> for IoBox {
fn eq(&self, other: &IoSlice) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<'a> PartialEq<IoSliceMut<'a>> for IoBox {
fn eq(&self, other: &IoSliceMut) -> bool {
self.as_slice() == other.as_slice()
}
}
impl Eq for IoBox {}
}
#[cfg(all(unix, feature = "alloc"))]
pub use io_box::*;
#[cfg(test)]
mod tests {
use super::*;
const FIRST: &[u8] = b"this";
const SECOND: &[u8] = b"is";
const THIRD: &[u8] = b"FAL";
const FOURTH: &[u8] = b"-rs";
const SPACE: &[u8] = b" ";
#[test]
fn advance() {
let original_slices = [FIRST, SPACE, SECOND, SPACE, THIRD, FOURTH];
let mut original_ioslices = original_slices
.iter()
.copied()
.map(|slice| IoSlice::from(slice))
.collect::<Vec<_>>();
let original_slices = &original_slices[..];
let original_ioslices = &mut original_ioslices[..];
fn check_slices(ioslices: &[IoSlice], slice: &[&[u8]]) {
assert!(ioslices
.iter()
.map(|ioslice| ioslice.as_slice())
.eq(slice.iter().copied()));
}
let mut ioslices = original_ioslices;
check_slices(ioslices, original_slices);
ioslices = IoSlice::advance_within(ioslices, 0).unwrap();
check_slices(ioslices, &[b"this", b" ", b"is", b" ", b"FAL", b"-rs"]);
ioslices = IoSlice::advance_within(ioslices, 2).unwrap();
check_slices(ioslices, &[b"is", b" ", b"is", b" ", b"FAL", b"-rs"]);
ioslices = IoSlice::advance_within(ioslices, 5).unwrap();
check_slices(ioslices, &[b" ", b"FAL", b"-rs"]);
ioslices = IoSlice::advance_within(ioslices, 6).unwrap();
check_slices(ioslices, &[b"s"]);
ioslices = IoSlice::advance_within(ioslices, 1).unwrap();
check_slices(ioslices, &[]);
assert_eq!(IoSlice::advance_within(ioslices, 1), None);
}
#[test]
#[cfg(feature = "std")]
fn abi_compatibility_with_std() {
assert_eq!(
mem::size_of::<IoSlice>(),
mem::size_of::<std::io::IoSlice>()
);
assert_eq!(
mem::align_of::<IoSlice>(),
mem::align_of::<std::io::IoSlice>()
);
let slices = [FIRST, SECOND, THIRD, FOURTH];
let mut ioslices = [
IoSlice::new(FIRST),
IoSlice::new(SECOND),
IoSlice::new(THIRD),
IoSlice::new(FOURTH),
];
let std_ioslices = IoSlice::cast_to_std_ioslices(&ioslices);
assert!(std_ioslices
.iter()
.map(|ioslice| ioslice.as_ref())
.eq(slices.iter().copied()));
use std::io::prelude::*;
let mut buffer =
vec![0u8; slices.iter().copied().map(<[u8]>::len).sum()].into_boxed_slice();
let mut total = 0;
let mut ioslices = &mut ioslices[..];
loop {
let std_ioslices = IoSlice::cast_to_std_ioslices(&ioslices);
match (&mut *buffer).write_vectored(std_ioslices) {
Ok(0) => break,
Ok(n) => {
ioslices = IoSlice::advance_within(ioslices, n).unwrap();
total += n
}
Err(error) if error.kind() == std::io::ErrorKind::Interrupted => continue,
Err(error) => Err(error).unwrap(),
}
}
assert_eq!(total, buffer.len());
assert_eq!(&*buffer, b"thisisFAL-rs");
}
#[test]
#[cfg(all(unix, feature = "libc"))]
fn abi_compatibility_with_iovec() {
use std::convert::TryInto;
assert_eq!(mem::size_of::<IoSlice>(), mem::size_of::<libc::iovec>());
assert_eq!(mem::align_of::<IoSlice>(), mem::align_of::<libc::iovec>());
unsafe {
let slice: &[u8] = b"Hello, world!";
let iov_base = slice.as_ptr() as *mut libc::c_void;
let iov_len = slice.len();
let vec = libc::iovec { iov_base, iov_len };
let wrapped: IoSlice = mem::transmute::<libc::iovec, IoSlice>(vec);
assert_eq!(wrapped.as_ptr(), iov_base as *const u8);
assert_eq!(wrapped.len(), iov_len);
}
let ioslices = [
IoSlice::new(FIRST),
IoSlice::new(SPACE),
IoSlice::new(SECOND),
IoSlice::new(SPACE),
IoSlice::new(THIRD),
IoSlice::new(FOURTH),
];
let iovecs = IoSlice::cast_to_raw_iovecs(&ioslices);
let mut fds = [0; 2];
unsafe {
libc::pipe(fds.as_mut_ptr());
}
let [receiver_fd, sender_fd] = fds;
let mut buffer = vec![0u8; ioslices.iter().map(|slice| slice.len()).sum()];
let buffer_parts = buffer
.chunks_mut(4)
.map(|slice| IoSliceMut::new(slice))
.collect::<Vec<_>>();
let buffer_parts_iovecs = IoSliceMut::cast_to_raw_iovecs(&*buffer_parts);
unsafe {
let result = libc::writev(sender_fd, iovecs.as_ptr(), iovecs.len().try_into().unwrap());
if result == -1 {
panic!("failed to writev: {}", std::io::Error::last_os_error());
}
let result = libc::readv(
receiver_fd,
buffer_parts_iovecs.as_ptr(),
buffer_parts_iovecs.len().try_into().unwrap(),
);
if result == -1 {
panic!("failed to readv: {}", std::io::Error::last_os_error());
}
}
let src_iter = ioslices
.iter()
.flat_map(|ioslice| ioslice.as_slice())
.copied();
let dst_iter = buffer_parts
.iter()
.flat_map(|ioslice| ioslice.as_slice())
.copied();
assert!(Iterator::eq(src_iter, dst_iter));
}
}