use core::borrow::{Borrow, BorrowMut};
use core::fmt;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ops::{Deref, DerefMut};
#[cfg(feature = "redox_syscall")]
use syscall::data::IoVec;
#[cfg(all(windows, feature = "winapi"))]
use winapi::shared::{
ntdef::{CHAR, ULONG},
ws2def::WSABUF,
};
pub mod init_marker {
use super::*;
mod private {
pub trait Sealed: Sized + 'static + Send + Sync + Unpin {}
}
pub unsafe trait InitMarker: private::Sealed {
const IS_INITIALIZED: bool;
type DerefTargetItem: fmt::Debug;
}
pub enum Init {}
pub enum Uninit {}
impl private::Sealed for Init {}
impl private::Sealed for Uninit {}
unsafe impl InitMarker for Init {
const IS_INITIALIZED: bool = true;
type DerefTargetItem = u8;
}
unsafe impl InitMarker for Uninit {
const IS_INITIALIZED: bool = false;
type DerefTargetItem = MaybeUninit<u8>;
}
}
use self::init_marker::*;
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct IoSlice<'a, I: InitMarker = Init> {
#[cfg(all(unix, feature = "libc", not(all(feature = "redox_syscall"))))]
inner: (libc::iovec, PhantomData<&'a [I::DerefTargetItem]>),
#[cfg(feature = "redox_syscall")]
inner: (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: InitMarker> Send for IoSlice<'a, I> {}
unsafe impl<'a, I: InitMarker> Sync for IoSlice<'a, I> {}
impl<'a, I: InitMarker> Unpin for IoSlice<'a, I> {}
#[cfg(feature = "std")]
impl<'a, I: InitMarker> std::panic::UnwindSafe for IoSlice<'a, I> {}
#[cfg(feature = "std")]
impl<'a, I: InitMarker> std::panic::RefUnwindSafe for IoSlice<'a, I> {}
impl<'a, I: InitMarker> 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, Uninit> {
unsafe { &*(self as *const Self as *const IoSlice<'a, Uninit>) }
}
#[inline]
pub fn as_uninit_mut(&mut self) -> &mut IoSlice<'a, Uninit> {
unsafe { &mut *(self as *mut Self as *mut IoSlice<'a, Uninit>) }
}
#[inline]
pub fn cast_to_uninit_slices(selves: &[Self]) -> &[IoSlice<'a, Uninit>] {
unsafe { crate::cast_slice_same_layout(selves) }
}
#[inline]
pub fn cast_to_uninit_slices_mut(selves: &mut [Self]) -> &mut [IoSlice<'a, Uninit>] {
unsafe { crate::cast_slice_same_layout_mut(selves) }
}
#[inline]
pub fn into_uninit(self) -> IoSlice<'a, Uninit> {
unsafe { IoSlice::__construct(self.__ptr(), self.__len()) }
}
#[inline]
pub unsafe fn assume_init(self) -> IoSlice<'a, Init> {
IoSlice::__construct(self.__ptr(), self.__len())
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub unsafe fn from_raw_iovec(slice: libc::iovec) -> Self {
Self {
#[cfg(not(feature = "redox_syscall"))]
inner: (slice, PhantomData),
#[cfg(feature = "redox_syscall")]
inner: (
IoVec {
addr: slice.iov_base as usize,
len: slice.iov_len,
},
PhantomData,
),
_marker: PhantomData,
}
}
#[cfg(all(windows, feature = "winapi"))]
#[inline]
pub unsafe fn from_raw_wsabuf(slice: WSABUF) -> Self {
Self {
inner: (slice, PhantomData),
_marker: PhantomData,
}
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub fn as_raw_iovec(&self) -> libc::iovec {
#[cfg(not(feature = "redox_syscall"))]
return self.inner.0;
#[cfg(feature = "redox_syscall")]
return libc::iovec {
iov_base: self.inner.0.addr as *mut libc::c_void,
iov_len: self.inner.0.len,
};
}
#[cfg(all(windows, feature = "winapi"))]
#[inline]
pub fn as_raw_wsabuf(&self) -> WSABUF {
self.inner.0
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub fn cast_to_raw_iovecs(slices: &'a [Self]) -> &'a [libc::iovec] {
unsafe { crate::cast_slice_same_layout(slices) }
}
#[cfg(all(windows, feature = "winapi"))]
#[inline]
pub fn cast_to_raw_wsabufs(slices: &'a [Self]) -> &'a [WSABUF] {
unsafe { crate::cast_slice_same_layout(slices) }
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub unsafe fn cast_to_raw_iovecs_mut(slices: &'a mut [Self]) -> &'a mut [libc::iovec] {
crate::cast_slice_same_layout_mut(slices)
}
#[cfg(all(windows, feature = "winapi"))]
#[inline]
pub unsafe fn cast_to_raw_wsabufs_mut(slices: &'a mut [Self]) -> &'a mut [WSABUF] {
cast_slice_same_layout_mut(slices)
}
#[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] {
unsafe {
core::slice::from_raw_parts(self.__ptr() as *const I::DerefTargetItem, self.__len())
}
}
#[inline]
pub fn from_inner_data(inner_data: &'a [I::DerefTargetItem]) -> Self {
unsafe { Self::__construct(inner_data.as_ptr() as *const u8, inner_data.len()) }
}
#[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", not(feature = "redox_syscall")))]
return self.inner.0.iov_base as *const u8;
#[cfg(feature = "redox_syscall")]
return self.inner.0.addr 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", not(feature = "redox_syscall")))]
return self.inner.0.iov_len as usize;
#[cfg(feature = "redox_syscall")]
return self.inner.0.len;
#[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", not(feature = "redox_syscall")))]
{
self.inner.0.iov_base = ptr as *mut libc::c_void;
}
#[cfg(feature = "redox_syscall")]
{
self.inner.0.addr = ptr as usize;
}
#[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", not(feature = "redox_syscall")))]
{
self.inner.0.iov_len = len as usize;
}
#[cfg(feature = "redox_syscall")]
{
self.inner.0.len = len;
}
#[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", not(feature = "redox_syscall")))]
inner: (
libc::iovec {
iov_base: ptr as *mut libc::c_void,
iov_len: len as usize,
},
PhantomData,
),
#[cfg(feature = "redox_syscall")]
inner: (
IoVec {
addr: ptr as usize,
len,
},
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,
}
}
#[inline]
pub fn split_at(self, mid: usize) -> (Self, Self) {
let (a, b) = self.inner_data().split_at(mid);
(Self::from_inner_data(a), Self::from_inner_data(b))
}
}
impl<'a> IoSlice<'a, Init> {
#[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 { crate::cast_slice_same_layout(slices) }
}
#[cfg(feature = "std")]
#[inline]
pub fn cast_to_std_ioslices_mut(slices: &'a mut [Self]) -> &'a mut [std::io::IoSlice<'a>] {
unsafe { crate::cast_slice_same_layout_mut(slices) }
}
}
impl<'a, I: InitMarker> 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: InitMarker> AsRef<[MaybeUninit<u8>]> for IoSlice<'a, I> {
#[inline]
fn as_ref(&self) -> &[MaybeUninit<u8>] {
self.as_maybe_uninit_slice()
}
}
impl<'a> AsRef<[u8]> for IoSlice<'a, Init> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl<'a, I: InitMarker> Borrow<[I::DerefTargetItem]> for IoSlice<'a, I> {
#[inline]
fn borrow(&self) -> &[I::DerefTargetItem] {
self.inner_data()
}
}
impl<'a> Borrow<[MaybeUninit<u8>]> for IoSlice<'a, Init> {
#[inline]
fn borrow(&self) -> &[MaybeUninit<u8>] {
self.as_maybe_uninit_slice()
}
}
impl<'a, I: InitMarker> Deref for IoSlice<'a, I> {
type Target = [I::DerefTargetItem];
#[inline]
fn deref(&self) -> &Self::Target {
self.inner_data()
}
}
impl<'a, I: InitMarker> From<&'a [I::DerefTargetItem]> for IoSlice<'a, I> {
#[inline]
fn from(slice: &'a [I::DerefTargetItem]) -> Self {
Self::from_inner_data(slice)
}
}
impl<'a, I: InitMarker> 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, Uninit> {
fn from(maybe_uninit_slice: &'a [u8]) -> Self {
Self::new(maybe_uninit_slice)
}
}
impl<'a> From<&'a mut [u8]> for IoSlice<'a, Uninit> {
fn from(maybe_uninit_slice: &'a mut [u8]) -> Self {
Self::new(&*maybe_uninit_slice)
}
}
#[cfg(feature = "nightly")]
impl<'a, I: InitMarker, 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: InitMarker, 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, Uninit> {
#[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, Uninit> {
#[inline]
fn from(array_ref: &'a mut [u8; N]) -> Self {
Self::new(&array_ref[..])
}
}
impl<'a> PartialEq for IoSlice<'a, Init> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self == other.as_slice()
}
}
impl<'a> PartialEq<[u8]> for IoSlice<'a, Init> {
#[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, Init> {
#[inline]
fn eq(&self, other: &[u8; N]) -> bool {
self == &other[..]
}
}
impl<'a, 'b> PartialEq<IoSliceMut<'b, Init>> for IoSlice<'a, Init> {
#[inline]
fn eq(&self, other: &IoSliceMut<'b>) -> bool {
self == other.as_slice()
}
}
impl<'a> Eq for IoSlice<'a, Init> {}
impl<'a> PartialOrd<[u8]> for IoSlice<'a, Init> {
#[inline]
fn partial_cmp(&self, other: &[u8]) -> Option<core::cmp::Ordering> {
PartialOrd::partial_cmp(self.as_slice(), other)
}
}
impl<'a, 'b> PartialOrd<IoSliceMut<'b, Init>> for IoSlice<'a, Init> {
#[inline]
fn partial_cmp(&self, other: &IoSliceMut<'b>) -> Option<core::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, Init> {
#[inline]
fn partial_cmp(&self, other: &[u8; N]) -> Option<core::cmp::Ordering> {
PartialOrd::partial_cmp(self.as_slice(), other)
}
}
impl<'a> PartialOrd for IoSlice<'a, Init> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(Ord::cmp(self, other))
}
}
impl<'a> Ord for IoSlice<'a, Init> {
#[inline]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
Ord::cmp(self.as_slice(), other.as_slice())
}
}
impl<'a, I: InitMarker> Default for IoSlice<'a, I> {
#[inline]
fn default() -> Self {
Self::new(&[])
}
}
impl<'a> core::hash::Hash for IoSlice<'a, Init> {
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
state.write(self.as_slice())
}
}
#[cfg(feature = "std")]
impl<'a, I: InitMarker> From<std::io::IoSlice<'a>> for IoSlice<'a, I> {
#[inline]
fn from(slice: std::io::IoSlice<'a>) -> Self {
unsafe { Self::__construct(slice.as_ptr(), slice.len()) }
}
}
#[cfg(feature = "std")]
impl<'a, I: InitMarker> 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: InitMarker> 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: InitMarker> stable_deref_trait::StableDeref for IoSlice<'a, I> {}
#[repr(transparent)]
pub struct IoSliceMut<'a, I: InitMarker = Init> {
#[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: InitMarker> Send for IoSliceMut<'a, I> {}
unsafe impl<'a, I: InitMarker> Sync for IoSliceMut<'a, I> {}
impl<'a, I: InitMarker> Unpin for IoSliceMut<'a, I> {}
#[cfg(feature = "std")]
impl<'a, I: InitMarker> std::panic::UnwindSafe for IoSliceMut<'a, I> {}
#[cfg(feature = "std")]
impl<'a, I: InitMarker> std::panic::RefUnwindSafe for IoSliceMut<'a, I> {}
impl<'a, I: InitMarker> 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, Init> {
IoSliceMut::__construct(self.__ptr(), self.__len())
}
#[inline]
pub unsafe fn assume_init_ref(&self) -> &IoSliceMut<'a, Init> {
&*(self as *const Self as *const IoSliceMut<'a, Init>)
}
#[inline]
pub unsafe fn assume_init_mut(&mut self) -> &mut IoSliceMut<'a, Init> {
&mut *(self as *mut Self as *mut IoSliceMut<'a, Init>)
}
#[inline]
pub fn into_uninit(self) -> IoSliceMut<'a, Uninit> {
unsafe { IoSliceMut::__construct(self.__ptr(), self.__len()) }
}
#[inline]
pub fn as_uninit(&self) -> &IoSliceMut<'a, Uninit> {
unsafe { &*(self as *const Self as *const IoSliceMut<'a, Uninit>) }
}
#[inline]
pub fn as_uninit_mut(&mut self) -> &mut IoSliceMut<'a, Uninit> {
unsafe { &mut *(self as *mut Self as *mut IoSliceMut<'a, Uninit>) }
}
#[inline]
pub fn cast_to_uninit_slices(selves: &[Self]) -> &[IoSliceMut<'a, Uninit>] {
unsafe { crate::cast_slice_same_layout(selves) }
}
#[inline]
pub unsafe fn cast_to_uninit_slices_mut(selves: &mut [Self]) -> &mut [IoSliceMut<'a, Uninit>] {
crate::cast_slice_same_layout_mut(selves)
}
#[inline]
pub unsafe fn cast_to_init_slices(selves: &[Self]) -> &[IoSliceMut<'a, Init>] {
crate::cast_slice_same_layout(selves)
}
#[inline]
pub unsafe fn cast_to_init_slices_mut(selves: &mut [Self]) -> &mut [IoSliceMut<'a, Init>] {
crate::cast_slice_same_layout_mut(selves)
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub unsafe fn from_raw_iovec(slice: libc::iovec) -> Self {
Self {
inner: (slice, PhantomData),
_marker: PhantomData,
}
}
#[cfg(all(windows, feature = "winapi"))]
#[inline]
pub unsafe fn from_raw_wsabuf(slice: WSABUF) -> 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(windows, feature = "winapi"))]
#[inline]
pub fn as_raw_wsabuf(&self) -> WSABUF {
self.inner.0
}
#[cfg(all(windows, feature = "winapi"))]
#[inline]
pub fn as_raw_wsabuf_mut(&mut self) -> WSABUF {
self.inner.0
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub fn cast_to_raw_iovecs(slices: &[Self]) -> &[libc::iovec] {
unsafe { crate::cast_slice_same_layout(slices) }
}
#[cfg(all(windows, feature = "winapi"))]
#[inline]
pub fn cast_to_raw_wsabufs(slices: &[Self]) -> &[WSABUF] {
unsafe { crate::cast_slice_same_layout(slices) }
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub unsafe fn cast_to_raw_iovecs_mut(slices: &mut [Self]) -> &mut [libc::iovec] {
crate::cast_slice_same_layout_mut(slices)
}
#[cfg(all(windows, feature = "winapi"))]
#[inline]
pub unsafe fn cast_to_raw_wsabufs_mut(slices: &mut [Self]) -> &mut [WSABUF] {
cast_slice_same_layout_mut(slices)
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub unsafe fn from_raw_iovecs(slice: &[libc::iovec]) -> &[Self] {
crate::cast_slice_same_layout(slice)
}
#[cfg(all(unix, feature = "libc"))]
#[inline]
pub unsafe fn from_raw_iovecs_mut(slice: &mut [libc::iovec]) -> &mut [Self] {
crate::cast_slice_same_layout_mut(slice)
}
#[cfg(all(windows, feature = "winapi"))]
#[inline]
pub unsafe fn from_raw_wsabufs(slice: &[WSABUF]) -> &[Self] {
cast_slice_same_layout(slice)
}
#[cfg(all(windows, feature = "winapi"))]
#[inline]
pub unsafe fn from_raw_wsabufs_mut(slice: &mut [WSABUF]) -> &mut [Self] {
cast_slice_same_layout_mut(slice)
}
#[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_by_ref<'b>(&'b mut self) -> &'b mut IoSliceMut<'a, Init> {
self.as_maybe_uninit_slice_mut().fill(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,
}
}
#[inline]
pub fn split_at(self, mid: usize) -> (Self, Self) {
let (a, b) = self.into_inner_data().split_at_mut(mid);
(Self::from_inner_data(a), Self::from_inner_data(b))
}
}
impl<'a> IoSliceMut<'a, Uninit> {
pub fn from_uninit(uninit: &'a mut [MaybeUninit<u8>]) -> Self {
Self::from_inner_data(uninit)
}
}
impl<'a> IoSliceMut<'a, Init> {
#[inline]
pub fn as_slice(&self) -> &[u8] {
unsafe { crate::cast_slice_same_layout(self.inner_data()) }
}
#[inline]
pub fn into_slice(self) -> &'a [u8] {
&*self.into_slice_mut()
}
#[inline]
pub fn as_slice_mut(&mut self) -> &mut [u8] {
unsafe { crate::cast_slice_same_layout_mut(self.inner_data_mut()) }
}
#[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 { crate::cast_slice_same_layout(slices) }
}
#[cfg(feature = "std")]
#[inline]
pub fn cast_to_std_mut_ioslices<'b>(slices: &'b [Self]) -> &'b [std::io::IoSliceMut<'a>] {
unsafe { crate::cast_slice_same_layout(slices) }
}
#[cfg(feature = "std")]
#[inline]
pub fn cast_to_std_ioslices_mut<'b>(slices: &'b mut [Self]) -> &'b mut [std::io::IoSlice<'a>] {
unsafe { crate::cast_slice_same_layout_mut(slices) }
}
#[cfg(feature = "std")]
#[inline]
pub fn cast_to_std_mut_ioslices_mut(
slices: &'a mut [Self],
) -> &'a mut [std::io::IoSliceMut<'a>] {
unsafe { crate::cast_slice_same_layout_mut(slices) }
}
}
impl<'a, I: InitMarker> AsRef<[I::DerefTargetItem]> for IoSliceMut<'a, I> {
#[inline]
fn as_ref(&self) -> &[I::DerefTargetItem] {
self.inner_data()
}
}
impl<'a> AsRef<[MaybeUninit<u8>]> for IoSliceMut<'a, Init> {
#[inline]
fn as_ref(&self) -> &[MaybeUninit<u8>] {
self.as_maybe_uninit_slice()
}
}
impl<'a, I: InitMarker> Borrow<[MaybeUninit<u8>]> for IoSliceMut<'a, I> {
#[inline]
fn borrow(&self) -> &[MaybeUninit<u8>] {
self.as_maybe_uninit_slice()
}
}
impl<'a> Borrow<[u8]> for IoSliceMut<'a, Init> {
#[inline]
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}
impl<'a, I: InitMarker> Deref for IoSliceMut<'a, I> {
type Target = [I::DerefTargetItem];
#[inline]
fn deref(&self) -> &Self::Target {
self.inner_data()
}
}
impl<'a> AsMut<[u8]> for IoSliceMut<'a, Init> {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
impl<'a, I: InitMarker> AsMut<[MaybeUninit<u8>]> for IoSliceMut<'a, I> {
#[inline]
fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
self.as_maybe_uninit_slice_mut()
}
}
impl<'a, I: InitMarker> BorrowMut<[MaybeUninit<u8>]> for IoSliceMut<'a, I> {
#[inline]
fn borrow_mut(&mut self) -> &mut [MaybeUninit<u8>] {
self.as_maybe_uninit_slice_mut()
}
}
impl<'a> BorrowMut<[u8]> for IoSliceMut<'a, Init> {
#[inline]
fn borrow_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
impl<'a, I: InitMarker> 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: InitMarker> From<IoSliceMut<'a, I>> for libc::iovec {
#[inline]
fn from(slice: IoSliceMut<'a, I>) -> Self {
slice.as_raw_iovec()
}
}
impl<'a, I: InitMarker> 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, Init> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<'a> PartialEq<[u8]> for IoSliceMut<'a, Init> {
#[inline]
fn eq(&self, other: &[u8]) -> bool {
self.as_slice() == other
}
}
impl<'a, 'b> PartialEq<&'b [u8]> for IoSliceMut<'a, Init> {
#[inline]
fn eq(&self, other: &&'b [u8]) -> bool {
self.as_slice() == *other
}
}
impl<'a, 'b> PartialEq<IoSlice<'b, Init>> for IoSliceMut<'a, Init> {
#[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, Init> {
#[inline]
fn eq(&self, other: &[u8; N]) -> bool {
self.as_slice() == &other[..]
}
}
impl<'a> Eq for IoSliceMut<'a, Init> {}
impl<'a> PartialOrd for IoSliceMut<'a, Init> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(Ord::cmp(self, other))
}
}
impl<'a> PartialOrd<[u8]> for IoSliceMut<'a, Init> {
#[inline]
fn partial_cmp(&self, other: &[u8]) -> Option<core::cmp::Ordering> {
PartialOrd::partial_cmp(self.as_slice(), other)
}
}
impl<'a, 'b> PartialOrd<IoSlice<'b, Init>> for IoSliceMut<'a, Init> {
#[inline]
fn partial_cmp(&self, other: &IoSlice<'b, Init>) -> Option<core::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, Init> {
#[inline]
fn partial_cmp(&self, other: &[u8; N]) -> Option<core::cmp::Ordering> {
PartialOrd::partial_cmp(self.as_slice(), other)
}
}
impl<'a> Ord for IoSliceMut<'a, Init> {
#[inline]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
Ord::cmp(self.as_slice(), other.as_slice())
}
}
impl<'a> core::hash::Hash for IoSliceMut<'a, Init> {
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
state.write(self.as_slice())
}
}
impl<'a, I: InitMarker> 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, Uninit> {
#[inline]
fn from(slice: &'a mut [u8]) -> Self {
Self::new(slice)
}
}
#[cfg(feature = "nightly")]
impl<'a, I: InitMarker, 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(feature = "alloc")]
mod io_box {
use super::*;
#[cfg(any(all(unix, feature = "libc"), all(windows, feature = "winapi")))]
use alloc::alloc::dealloc as deallocate;
use alloc::alloc::{alloc as allocate, alloc_zeroed as allocate_zeroed, Layout};
use alloc::boxed::Box;
use alloc::vec::Vec;
#[repr(transparent)]
pub struct IoBox<I: InitMarker = Init> {
#[cfg(all(unix, feature = "libc"))]
inner: libc::iovec,
#[cfg(all(windows, feature = "winapi"))]
inner: WSABUF,
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
inner: Box<[I::DerefTargetItem]>,
_marker: PhantomData<I>,
}
#[derive(Debug)]
pub struct AllocationError(Layout);
impl AllocationError {
#[inline]
pub fn layout(&self) -> &Layout {
&self.0
}
}
impl fmt::Display for AllocationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"failed to allocate {} bytes on a {}-byte alignment for buffer",
self.layout().size(),
self.layout().align()
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for AllocationError {}
impl<I: InitMarker> IoBox<I> {
fn try_alloc_inner<J: InitMarker>(
length: usize,
zeroed: bool,
) -> Result<IoBox<J>, AllocationError> {
let layout = Layout::from_size_align(
core::mem::size_of::<u8>()
.checked_mul(length)
.expect("overflow when multiplying length with size of u8"),
core::mem::align_of::<u8>(),
)
.expect("error when creating allocation layout");
#[cfg(all(windows, feature = "winapi"))]
if length > u32::MAX as usize {
panic!("IoBox (or any WSABUF-based I/O slice) cannot be larger in size than ULONG, which is 32 bits on Windows.");
}
let pointer = match zeroed {
false => unsafe { allocate(layout) },
true => unsafe { allocate_zeroed(layout) },
};
if pointer.is_null() {
return Err(AllocationError(layout));
}
Ok(unsafe { IoBox::__construct(pointer as *mut J::DerefTargetItem, 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) {
let ptr = self.__ptr();
let len = self.__len();
core::mem::forget(self);
(ptr as *mut u8, len)
}
#[inline]
pub unsafe fn from_raw_parts(base: *mut I::DerefTargetItem, len: usize) -> Self {
Self::__construct(base, len)
}
#[cfg(all(unix, feature = "libc"))]
pub fn into_raw_iovec(self) -> libc::iovec {
let iovec = self.inner;
core::mem::forget(self);
iovec
}
#[cfg(all(windows, feature = "winapi"))]
pub fn into_raw_wsabuf(self) -> WSABUF {
let wsabuf = self.inner;
core::mem::forget(self);
wsabuf
}
#[inline]
pub fn into_box(self) -> Box<[I::DerefTargetItem]> {
let (ptr, len) = self.into_raw_parts();
unsafe {
Box::from_raw(core::slice::from_raw_parts_mut(
ptr as *mut I::DerefTargetItem,
len,
))
}
}
#[inline]
pub fn as_ioslice(&self) -> IoSlice<I> {
IoSlice::from_inner_data(self.inner_data())
}
#[inline]
pub fn as_ioslice_mut(&mut self) -> IoSliceMut<I> {
IoSliceMut::from_inner_data(self.inner_data_mut())
}
#[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 cast_to_ioslices(these: &[Self]) -> &[IoSlice<I>] {
unsafe { crate::cast_slice_same_layout(these) }
}
#[inline]
pub unsafe fn cast_to_ioslices_mut(these: &mut [Self]) -> &mut [IoSlice<I>] {
crate::cast_slice_same_layout_mut(these)
}
#[inline]
pub fn cast_to_mut_ioslices(these: &[Self]) -> &[IoSliceMut<I>] {
unsafe { crate::cast_slice_same_layout(these) }
}
#[inline]
pub unsafe fn cast_to_mut_ioslices_mut(these: &mut [Self]) -> &mut [IoSliceMut<I>] {
crate::cast_slice_same_layout_mut(these)
}
#[inline]
pub unsafe fn assume_init(self) -> IoBox<Init> {
let (ptr, len) = self.into_raw_parts();
IoBox::from_raw_parts(ptr, len)
}
#[inline]
pub fn as_maybe_uninit_slice(&self) -> &[MaybeUninit<u8>] {
unsafe { crate::cast_slice_same_layout(self.inner_data()) }
}
#[inline]
pub fn as_maybe_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<u8>] {
unsafe { crate::cast_slice_same_layout_mut(self.inner_data_mut()) }
}
#[inline]
pub fn into_uninit(self) -> IoBox<Uninit> {
unsafe {
let (ptr, len) = self.into_raw_parts();
IoBox::from_raw_parts(ptr as *mut MaybeUninit<u8>, len)
}
}
#[inline]
pub fn into_uninit_box(self) -> Box<[MaybeUninit<u8>]> {
self.into_uninit().into_box()
}
fn __ptr(&self) -> *mut I::DerefTargetItem {
#[cfg(all(unix, feature = "libc"))]
{
self.inner.iov_base as *mut I::DerefTargetItem
}
#[cfg(all(windows, feature = "winapi"))]
{
self.inner.buf as *mut I::DerefTargetItem
}
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
{
self.inner.as_ptr() as *mut I::DerefTargetItem
}
}
#[inline]
fn __len(&self) -> usize {
#[cfg(all(unix, feature = "libc"))]
{
self.inner.iov_len as usize
}
#[cfg(all(windows, feature = "winapi"))]
{
self.inner.len as usize
}
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
{
self.inner.len()
}
}
#[inline]
unsafe fn __construct(ptr: *mut I::DerefTargetItem, len: usize) -> Self {
Self {
#[cfg(all(unix, feature = "libc"))]
inner: libc::iovec {
iov_base: ptr as *mut libc::c_void,
iov_len: len,
},
#[cfg(all(windows, feature = "winapi"))]
inner: WSABUF {
buf: ptr as *mut CHAR,
len: len as ULONG,
},
#[cfg(not(any(all(unix, feature = "libc"), all(windows, feature = "winapi"))))]
inner: Box::from_raw(core::slice::from_raw_parts_mut(ptr, len)),
_marker: PhantomData,
}
}
}
impl IoBox<Uninit> {
#[inline]
pub fn try_alloc_uninit(length: usize) -> Result<IoBox<Uninit>, AllocationError> {
Self::try_alloc_inner(length, false)
}
#[inline]
pub fn alloc_uninit(length: usize) -> IoBox<Uninit> {
match Self::try_alloc_uninit(length) {
Ok(boxed) => boxed,
Err(AllocationError(layout)) => alloc::alloc::handle_alloc_error(layout),
}
}
}
impl IoBox<Init> {
#[inline]
pub fn as_slice(&self) -> &[u8] {
self.inner_data()
}
#[inline]
pub fn as_slice_mut(&mut self) -> &mut [u8] {
self.inner_data_mut()
}
}
impl<I: InitMarker> Drop for IoBox<I> {
fn drop(&mut self) {
#[cfg(any(all(unix, feature = "libc"), all(windows, feature = "winapi")))]
unsafe {
deallocate(
self.__ptr() as *mut u8,
Layout::from_size_align(
self.__len()
.checked_mul(core::mem::size_of::<u8>())
.expect("overflow on multiplication that should be a no-op"),
core::mem::align_of::<u8>(),
)
.expect("failed to deallocate due to invalid layout"),
);
}
}
}
impl<I: InitMarker> From<Box<[I::DerefTargetItem]>> for IoBox<I> {
#[inline]
fn from(boxed: Box<[I::DerefTargetItem]>) -> Self {
unsafe {
let slice_ptr = Box::into_raw(boxed);
let len = (&*slice_ptr).len();
let base = (&*slice_ptr).as_ptr() as *mut I::DerefTargetItem;
Self::from_raw_parts(base, len)
}
}
}
impl From<Box<[u8]>> for IoBox<Uninit> {
#[inline]
fn from(boxed: Box<[u8]>) -> Self {
unsafe {
let slice_ptr = Box::into_raw(boxed);
let len = (&*slice_ptr).len();
let base = (&*slice_ptr).as_ptr() as *mut MaybeUninit<u8>;
Self::from_raw_parts(base, len)
}
}
}
impl<I: InitMarker> From<Vec<I::DerefTargetItem>> for IoBox<I> {
#[inline]
fn from(vector: Vec<I::DerefTargetItem>) -> Self {
Self::from(vector.into_boxed_slice())
}
}
impl From<Vec<u8>> for IoBox<Uninit> {
#[inline]
fn from(vector: Vec<u8>) -> Self {
Self::from(vector.into_boxed_slice())
}
}
impl<I: InitMarker> From<IoBox<I>> for Box<[I::DerefTargetItem]> {
#[inline]
fn from(io_box: IoBox<I>) -> Self {
io_box.into_box()
}
}
impl From<IoBox<Init>> for Box<[MaybeUninit<u8>]> {
#[inline]
fn from(io_box: IoBox<Init>) -> Self {
io_box.into_uninit_box()
}
}
impl<I: InitMarker> From<IoBox<I>> for Vec<I::DerefTargetItem> {
#[inline]
fn from(io_box: IoBox<I>) -> Self {
Self::from(Box::from(io_box))
}
}
impl From<IoBox<Init>> for Vec<MaybeUninit<u8>> {
#[inline]
fn from(io_box: IoBox<Init>) -> Self {
io_box.into_uninit_box().into()
}
}
impl core::fmt::Debug for IoBox {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.as_slice())
}
}
impl<I: InitMarker> Deref for IoBox<I> {
type Target = [I::DerefTargetItem];
#[inline]
fn deref(&self) -> &Self::Target {
self.inner_data()
}
}
impl<I: InitMarker> DerefMut for IoBox<I> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner_data_mut()
}
}
impl<I: InitMarker> AsRef<[MaybeUninit<u8>]> for IoBox<I> {
#[inline]
fn as_ref(&self) -> &[MaybeUninit<u8>] {
self.as_maybe_uninit_slice()
}
}
impl<I: InitMarker> AsMut<[MaybeUninit<u8>]> for IoBox<I> {
#[inline]
fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
self.as_maybe_uninit_slice_mut()
}
}
impl AsRef<[u8]> for IoBox<Init> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl AsMut<[u8]> for IoBox<Init> {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
impl<I: InitMarker> core::borrow::Borrow<[MaybeUninit<u8>]> for IoBox<I> {
#[inline]
fn borrow(&self) -> &[MaybeUninit<u8>] {
self.as_maybe_uninit_slice()
}
}
impl<I: InitMarker> core::borrow::BorrowMut<[MaybeUninit<u8>]> for IoBox<I> {
#[inline]
fn borrow_mut(&mut self) -> &mut [MaybeUninit<u8>] {
self.as_maybe_uninit_slice_mut()
}
}
impl core::borrow::Borrow<[u8]> for IoBox<Init> {
#[inline]
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}
impl core::borrow::BorrowMut<[u8]> for IoBox<Init> {
#[inline]
fn borrow_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
impl PartialEq for IoBox<Init> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl PartialEq<[u8]> for IoBox<Init> {
#[inline]
fn eq(&self, other: &[u8]) -> bool {
self.as_slice() == other
}
}
impl<'a> PartialEq<IoSlice<'a, Init>> for IoBox<Init> {
#[inline]
fn eq(&self, other: &IoSlice<Init>) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<'a> PartialEq<IoSliceMut<'a, Init>> for IoBox<Init> {
#[inline]
fn eq(&self, other: &IoSliceMut<Init>) -> bool {
self.as_slice() == other.as_slice()
}
}
impl Eq for IoBox<Init> {}
}
#[cfg(feature = "alloc")]
pub use io_box::*;
pub trait CastSlice<T>: Sized {
fn cast_slice(selves: &[Self]) -> &[T];
}
pub trait CastSliceMut<T>: CastSlice<T> {
fn cast_slice_mut(selves: &mut [Self]) -> &mut [T];
}
#[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);
}
macro_rules! splitting_inner(
($slice:ident) => {{
let mut buf: [u8; 13] = *b"Hello, world!";
let full = $slice::<Init>::new(&mut buf);
let (first, remainder) = full.split_at(4);
assert_eq!(&*first, b"Hell");
let (second, third) = remainder.split_at(5);
assert_eq!(&*second, b"o, wo");
assert_eq!(&*third, b"rld!");
}}
);
#[test]
fn splitting_ioslice() {
splitting_inner!(IoSlice)
}
#[test]
fn splitting_ioslice_mut() {
splitting_inner!(IoSliceMut)
}
#[test]
#[cfg(all(windows, feature = "winapi"))]
#[cfg_attr(target_pointer_width = "32", ignore)]
#[should_panic = "IoBox (or any WSABUF-based I/O slice) cannot be larger in size than ULONG, which is 32 bits on Windows."]
fn wsabuf_limit() {
let _ = IoBox::try_alloc_uninit(u32::MAX as usize + 1);
}
#[test]
#[cfg(feature = "std")]
fn abi_compatibility_with_std() {
assert_eq!(
std::mem::size_of::<IoSlice>(),
std::mem::size_of::<std::io::IoSlice>()
);
assert_eq!(
std::mem::align_of::<IoSlice>(),
std::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"))]
#[cfg_attr(miri, ignore)]
fn abi_compatibility_with_iovec() {
use std::convert::TryInto;
assert_eq!(
std::mem::size_of::<IoSlice>(),
std::mem::size_of::<libc::iovec>()
);
assert_eq!(
std::mem::align_of::<IoSlice>(),
std::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 = std::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));
}
}