use core::mem::MaybeUninit;
use super::owned::{IoBuf, IoBufMut, OwnedBuf};
mod sealed {
use super::OwnedBuf;
pub struct Bufs(pub(crate) Vec<OwnedBuf>);
pub trait Written: Sized {
fn into_owned(self) -> Bufs;
fn from_owned(bufs: Bufs) -> Self;
}
pub trait Filled: Sized {
fn into_owned(self) -> Bufs;
fn from_owned(bufs: Bufs) -> Self;
}
}
use sealed::Bufs;
pub trait IoVecBuf: sealed::Written + Send + 'static {}
pub trait IoVecBufMut: sealed::Filled + Send + 'static {}
impl<B> sealed::Written for Vec<B>
where
B: IoBuf,
{
fn into_owned(self) -> Bufs {
Bufs(self.into_iter().map(OwnedBuf::written).collect())
}
fn from_owned(bufs: Bufs) -> Self {
bufs.0.into_iter().map(OwnedBuf::into_written).collect()
}
}
impl<B> IoVecBuf for Vec<B> where B: IoBuf {}
impl<B> sealed::Filled for Vec<B>
where
B: IoBufMut,
{
fn into_owned(self) -> Bufs {
Bufs(self.into_iter().map(OwnedBuf::filled).collect())
}
fn from_owned(bufs: Bufs) -> Self {
bufs.0.into_iter().map(OwnedBuf::into_filled).collect()
}
}
impl<B> IoVecBufMut for Vec<B> where B: IoBufMut {}
impl<B, const N: usize> sealed::Written for [B; N]
where
B: IoBuf,
{
fn into_owned(self) -> Bufs {
Bufs(self.into_iter().map(OwnedBuf::written).collect())
}
fn from_owned(bufs: Bufs) -> Self {
let mut bufs = bufs.0.into_iter();
core::array::from_fn(|_| bufs.next().map_or_else(B::default, OwnedBuf::into_written))
}
}
impl<B, const N: usize> IoVecBuf for [B; N] where B: IoBuf {}
impl<B, const N: usize> sealed::Filled for [B; N]
where
B: IoBufMut,
{
fn into_owned(self) -> Bufs {
Bufs(self.into_iter().map(OwnedBuf::filled).collect())
}
fn from_owned(bufs: Bufs) -> Self {
let mut bufs = bufs.0.into_iter();
core::array::from_fn(|_| bufs.next().map_or_else(B::default, OwnedBuf::into_filled))
}
}
impl<B, const N: usize> IoVecBufMut for [B; N] where B: IoBufMut {}
pub(crate) fn written<V>(bufs: V) -> Vec<OwnedBuf>
where
V: IoVecBuf,
{
sealed::Written::into_owned(bufs).0
}
pub(crate) fn into_written<V>(bufs: Vec<OwnedBuf>) -> V
where
V: IoVecBuf,
{
<V as sealed::Written>::from_owned(Bufs(bufs))
}
pub(crate) fn filled<V>(bufs: V) -> Vec<OwnedBuf>
where
V: IoVecBufMut,
{
sealed::Filled::into_owned(bufs).0
}
pub(crate) fn into_filled<V>(bufs: Vec<OwnedBuf>) -> V
where
V: IoVecBufMut,
{
<V as sealed::Filled>::from_owned(Bufs(bufs))
}
#[cfg(unix)]
pub(crate) type IoVec = libc::iovec;
#[cfg(windows)]
pub(crate) type IoVec = crate::syscore::windows::WSABUF;
pub(crate) const IOV_MAX: usize = 1024;
fn iovec(ptr: *const u8, len: usize) -> IoVec {
#[cfg(unix)]
return libc::iovec {
iov_base: ptr.cast_mut().cast(),
iov_len: len,
};
#[cfg(windows)]
return IoVec {
len: u32::try_from(len).unwrap_or(u32::MAX),
buf: ptr.cast_mut(),
};
}
pub(crate) struct Vectored {
bufs: Vec<OwnedBuf>,
held: Option<Vec<usize>>,
iov: Vec<IoVec>,
#[cfg(ring)]
msg: libc::msghdr,
}
unsafe impl Send for Vectored {}
unsafe impl Sync for Vectored {}
impl Vectored {
fn new(bufs: Vec<OwnedBuf>, held: Option<Vec<usize>>) -> Self {
Self {
bufs,
held,
iov: Vec::new(),
#[cfg(ring)]
msg: unsafe { core::mem::zeroed() },
}
}
pub(crate) fn written(bufs: Vec<OwnedBuf>) -> Self {
Self::new(bufs, None)
}
pub(crate) fn filled(bufs: Vec<OwnedBuf>) -> Self {
let held = bufs.iter().map(OwnedBuf::len).collect();
Self::new(bufs, Some(held))
}
pub(crate) fn into_bufs(self) -> Vec<OwnedBuf> {
self.bufs
}
pub(crate) fn len(&self) -> usize {
self.bufs.iter().map(OwnedBuf::len).sum()
}
pub(crate) fn capacity(&self) -> usize {
match self.held {
Some(_) => self.bufs.iter().map(OwnedBuf::capacity).sum(),
None => self.len(),
}
}
pub(crate) fn rest_from(&self, from: usize) -> &[u8] {
let mut from = from;
for buf in &self.bufs {
if from < buf.len() {
return buf.rest_from(from);
}
from -= buf.len();
}
&[]
}
pub(crate) fn write_iovecs(&mut self, from: usize) -> &[IoVec] {
self.iov.clear();
let mut skip = from;
for buf in &self.bufs {
if self.iov.len() == IOV_MAX {
break;
}
let bytes = buf.rest_from(skip);
skip = skip.saturating_sub(buf.len());
if !bytes.is_empty() {
self.iov.push(iovec(bytes.as_ptr(), bytes.len()));
}
}
&self.iov
}
pub(crate) fn read_iovecs(&mut self) -> &mut [IoVec] {
self.iov.clear();
if self.held.is_some() {
for buf in &mut self.bufs {
if self.iov.len() == IOV_MAX {
break;
}
let room = buf.spare_capacity_mut();
if !room.is_empty() {
self.iov.push(iovec(room.as_mut_ptr().cast(), room.len()));
}
}
}
&mut self.iov
}
#[cfg(ring)]
pub(crate) fn send_msg(&mut self, from: usize) -> *const libc::msghdr {
let count = self.write_iovecs(from).len();
self.msg.msg_iov = self.iov.as_mut_ptr();
self.msg.msg_iovlen = count as _;
&raw const self.msg
}
#[cfg(ring)]
pub(crate) fn recv_msg(&mut self) -> *mut libc::msghdr {
let count = self.read_iovecs().len();
self.msg.msg_iov = self.iov.as_mut_ptr();
self.msg.msg_iovlen = count as _;
&raw mut self.msg
}
#[cfg(windows)]
pub(crate) fn built(&mut self) -> &mut [IoVec] {
&mut self.iov
}
pub(crate) fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
if self.held.is_none() {
return &mut [];
}
match self.bufs.iter_mut().find(|b| b.len() < b.capacity()) {
Some(buf) => buf.spare_capacity_mut(),
None => &mut [],
}
}
pub(crate) unsafe fn set_len(&mut self, len: usize) {
let Some(held) = &self.held else {
return;
};
let mut left = len.saturating_sub(held.iter().sum());
for (buf, &held) in self.bufs.iter_mut().zip(held) {
let take = left.min(buf.capacity() - held);
left -= take;
unsafe { buf.set_len(held + take) };
}
}
pub(crate) fn append(&mut self, bytes: &[u8]) -> usize {
if self.held.is_none() {
return 0;
}
let mut n = 0;
for buf in &mut self.bufs {
if n == bytes.len() {
break;
}
n += buf.append(&bytes[n..]);
}
n
}
pub(crate) fn read_parts(self) -> impl Iterator<Item = (OwnedBuf, usize)> {
let held = self.held.unwrap_or_default();
self.bufs
.into_iter()
.zip(held)
.filter(|(buf, held)| buf.len() > *held)
}
}