use core::{
marker::PhantomData,
mem,
ops::{Deref, DerefMut},
slice,
};
#[cfg(unix)]
use libc::{c_void, iovec};
#[cfg(unix)]
#[repr(transparent)]
struct RawIoSliceMut<'a>(iovec, PhantomData<&'a mut [u8]>);
#[cfg(unix)]
impl<'a> RawIoSliceMut<'a> {
#[inline]
fn new(buf: &'a mut [u8]) -> RawIoSliceMut<'a> {
RawIoSliceMut(
iovec {
iov_base: buf.as_mut_ptr() as *mut c_void,
iov_len: buf.len(),
},
PhantomData,
)
}
#[inline]
pub fn advance(&mut self, n: usize) {
if self.0.iov_len < n {
panic!("advancing IoSlice beyond its length");
}
unsafe {
self.0.iov_len -= n;
self.0.iov_base = self.0.iov_base.add(n);
}
}
#[inline]
fn as_slice(&self) -> &'a [u8] {
unsafe { slice::from_raw_parts(self.0.iov_base as *const u8, self.0.iov_len) }
}
#[inline]
fn as_mut_slice(&mut self) -> &'a mut [u8] {
unsafe { slice::from_raw_parts_mut(self.0.iov_base as *mut u8, self.0.iov_len) }
}
}
#[cfg(unix)]
#[derive(Copy, Clone)]
#[repr(transparent)]
struct RawIoSlice<'a>(iovec, PhantomData<&'a [u8]>);
#[cfg(unix)]
impl<'a> RawIoSlice<'a> {
#[inline]
fn new(buf: &'a [u8]) -> RawIoSlice<'a> {
RawIoSlice(
iovec {
iov_base: buf.as_ptr() as *mut u8 as *mut c_void,
iov_len: buf.len(),
},
PhantomData,
)
}
#[inline]
pub fn advance(&mut self, n: usize) {
if self.0.iov_len < n {
panic!("advancing IoSlice beyond its length");
}
unsafe {
self.0.iov_len -= n;
self.0.iov_base = self.0.iov_base.add(n);
}
}
#[inline]
fn as_slice(&self) -> &'a [u8] {
unsafe { slice::from_raw_parts(self.0.iov_base as *const u8, self.0.iov_len) }
}
}
#[repr(transparent)]
pub struct IoSliceMut<'a>(RawIoSliceMut<'a>);
unsafe impl<'a> Send for IoSliceMut<'a> {}
unsafe impl<'a> Sync for IoSliceMut<'a> {}
impl<'a> IoSliceMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
IoSliceMut(RawIoSliceMut::new(buf))
}
#[doc(hidden)]
#[inline]
pub fn advance(&mut self, n: usize) {
self.0.advance(n)
}
#[doc(hidden)]
#[inline]
pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) {
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;
}
}
*bufs = &mut mem::take(bufs)[remove..];
if !bufs.is_empty() {
bufs[0].advance(n - accumulated_len)
}
}
}
impl<'a> Deref for IoSliceMut<'a> {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.0.as_slice()
}
}
impl<'a> DerefMut for IoSliceMut<'a> {
#[inline]
fn deref_mut(&mut self) -> &mut [u8] {
self.0.as_mut_slice()
}
}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct IoSlice<'a>(RawIoSlice<'a>);
unsafe impl<'a> Send for IoSlice<'a> {}
unsafe impl<'a> Sync for IoSlice<'a> {}
impl<'a> IoSlice<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
IoSlice(RawIoSlice::new(buf))
}
#[doc(hidden)]
#[inline]
pub fn advance(&mut self, n: usize) {
self.0.advance(n)
}
#[doc(hidden)]
#[inline]
pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) {
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;
}
}
*bufs = &mut mem::take(bufs)[remove..];
if !bufs.is_empty() {
bufs[0].advance(n - accumulated_len)
}
}
}
impl<'a> Deref for IoSlice<'a> {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.0.as_slice()
}
}