use std::{iter, mem::MaybeUninit};
use crate::{IntoInner, IoBuf, IoBufMut, SetLen, VectoredSlice, t_alloc};
pub trait IoVectoredBuf: 'static {
fn iter_slice(&self) -> impl Iterator<Item = &[u8]>;
fn total_len(&self) -> usize {
self.iter_slice().map(|buf| buf.len()).sum()
}
fn owned_iter(self) -> Result<VectoredBufIter<Self>, Self>
where
Self: Sized,
{
VectoredBufIter::new(self)
}
fn slice(self, begin: usize) -> VectoredSlice<Self>
where
Self: Sized,
{
let mut offset = begin;
let mut idx = 0;
for b in self.iter_slice() {
let len = b.len();
if len > offset {
break;
}
offset -= len;
idx += 1;
}
VectoredSlice::new(self, begin, idx, offset)
}
}
impl<T: IoBuf> IoVectoredBuf for &'static [T] {
fn iter_slice(&self) -> impl Iterator<Item = &[u8]> {
self.iter().map(|buf| buf.as_init())
}
}
impl<T: IoBuf> IoVectoredBuf for &'static mut [T] {
fn iter_slice(&self) -> impl Iterator<Item = &[u8]> {
self.iter().map(|buf| buf.as_init())
}
}
impl<T: IoBuf, const N: usize> IoVectoredBuf for [T; N] {
fn iter_slice(&self) -> impl Iterator<Item = &[u8]> {
self.iter().map(|buf| buf.as_init())
}
}
impl<T: IoBuf, #[cfg(feature = "allocator_api")] A: std::alloc::Allocator + 'static> IoVectoredBuf
for t_alloc!(Vec, T, A)
{
fn iter_slice(&self) -> impl Iterator<Item = &[u8]> {
self.iter().map(|buf| buf.as_init())
}
}
#[cfg(feature = "arrayvec")]
impl<T: IoBuf, const N: usize> IoVectoredBuf for arrayvec::ArrayVec<T, N> {
fn iter_slice(&self) -> impl Iterator<Item = &[u8]> {
self.iter().map(|buf| buf.as_init())
}
}
#[cfg(feature = "smallvec")]
impl<T: IoBuf, const N: usize> IoVectoredBuf for smallvec::SmallVec<[T; N]>
where
[T; N]: smallvec::Array<Item = T>,
{
fn iter_slice(&self) -> impl Iterator<Item = &[u8]> {
self.iter().map(|buf| buf.as_init())
}
}
impl<T: IoBuf, Rest: IoVectoredBuf> IoVectoredBuf for (T, Rest) {
fn iter_slice(&self) -> impl Iterator<Item = &[u8]> {
std::iter::once(self.0.as_init()).chain(self.1.iter_slice())
}
}
impl<T: IoBuf> IoVectoredBuf for (T,) {
fn iter_slice(&self) -> impl Iterator<Item = &[u8]> {
std::iter::once(self.0.as_init())
}
}
impl IoVectoredBuf for () {
fn iter_slice(&self) -> impl Iterator<Item = &[u8]> {
std::iter::empty()
}
}
pub trait IoVectoredBufMut: IoVectoredBuf + SetLen {
fn iter_uninit_slice(&mut self) -> impl Iterator<Item = &mut [MaybeUninit<u8>]>;
fn total_capacity(&mut self) -> usize {
self.iter_uninit_slice().map(|buf| buf.len()).sum()
}
fn slice_mut(mut self, begin: usize) -> VectoredSlice<Self>
where
Self: Sized,
{
let mut offset = begin;
let mut idx = 0;
for b in self.iter_uninit_slice() {
let len = b.len();
if len > offset {
break;
}
offset -= len;
idx += 1;
}
VectoredSlice::new(self, begin, idx, offset)
}
}
impl<T: IoBufMut> IoVectoredBufMut for &'static mut [T] {
fn iter_uninit_slice(&mut self) -> impl Iterator<Item = &mut [MaybeUninit<u8>]> {
self.iter_mut().map(|buf| buf.as_uninit())
}
}
impl<T: IoBufMut, const N: usize> IoVectoredBufMut for [T; N] {
fn iter_uninit_slice(&mut self) -> impl Iterator<Item = &mut [MaybeUninit<u8>]> {
self.iter_mut().map(|buf| buf.as_uninit())
}
}
impl<T: IoBufMut, #[cfg(feature = "allocator_api")] A: std::alloc::Allocator + 'static>
IoVectoredBufMut for t_alloc!(Vec, T, A)
{
fn iter_uninit_slice(&mut self) -> impl Iterator<Item = &mut [MaybeUninit<u8>]> {
self.iter_mut().map(|buf| buf.as_uninit())
}
}
#[cfg(feature = "arrayvec")]
impl<T: IoBufMut, const N: usize> IoVectoredBufMut for arrayvec::ArrayVec<T, N> {
fn iter_uninit_slice(&mut self) -> impl Iterator<Item = &mut [MaybeUninit<u8>]> {
self.iter_mut().map(|buf| buf.as_uninit())
}
}
#[cfg(feature = "smallvec")]
impl<T: IoBufMut, const N: usize> IoVectoredBufMut for smallvec::SmallVec<[T; N]>
where
[T; N]: smallvec::Array<Item = T>,
{
fn iter_uninit_slice(&mut self) -> impl Iterator<Item = &mut [MaybeUninit<u8>]> {
self.iter_mut().map(|buf| buf.as_uninit())
}
}
impl<T: IoBufMut, Rest: IoVectoredBufMut> IoVectoredBufMut for (T, Rest) {
fn iter_uninit_slice(&mut self) -> impl Iterator<Item = &mut [MaybeUninit<u8>]> {
let (h, t) = self;
iter::once(h.as_uninit()).chain(t.iter_uninit_slice())
}
}
impl<T: IoBufMut> IoVectoredBufMut for (T,) {
fn iter_uninit_slice(&mut self) -> impl Iterator<Item = &mut [MaybeUninit<u8>]> {
iter::once(self.0.as_uninit())
}
}
impl IoVectoredBufMut for () {
fn iter_uninit_slice(&mut self) -> impl Iterator<Item = &mut [MaybeUninit<u8>]> {
iter::empty()
}
}
impl<T: IoBufMut, Rest: IoVectoredBufMut> SetLen for (T, Rest) {
unsafe fn set_len(&mut self, len: usize) {
let head_len = std::cmp::min(len, self.0.buf_capacity());
let rest_len = len - head_len;
unsafe { self.0.set_len(head_len) };
unsafe { self.1.set_len(rest_len) };
}
}
impl<T: IoBufMut> SetLen for (T,) {
unsafe fn set_len(&mut self, len: usize) {
unsafe { self.0.set_len(len) };
}
}
impl SetLen for () {
unsafe fn set_len(&mut self, len: usize) {
assert_eq!(len, 0, "set_len called with non-zero len on empty buffer");
}
}
pub struct VectoredBufIter<T> {
buf: T,
total_filled: usize,
index: usize,
len: usize,
filled: usize,
}
impl<T> VectoredBufIter<T> {
pub fn next(mut self) -> Result<Self, T> {
self.index += 1;
if self.index < self.len {
self.total_filled += self.filled;
self.filled = 0;
Ok(self)
} else {
Err(self.buf)
}
}
}
impl<T: IoVectoredBuf> VectoredBufIter<T> {
fn new(buf: T) -> Result<Self, T> {
let len = buf.iter_slice().count();
if len > 0 {
Ok(Self {
buf,
index: 0,
len,
total_filled: 0,
filled: 0,
})
} else {
Err(buf)
}
}
}
impl<T> IntoInner for VectoredBufIter<T> {
type Inner = T;
fn into_inner(self) -> Self::Inner {
self.buf
}
}
impl<T: IoVectoredBuf> IoBuf for VectoredBufIter<T> {
fn as_init(&self) -> &[u8] {
let curr = self
.buf
.iter_slice()
.nth(self.index)
.expect("`index` should not exceed `len`");
&curr[self.filled..]
}
}
impl<T: IoVectoredBuf + SetLen> SetLen for VectoredBufIter<T> {
unsafe fn set_len(&mut self, len: usize) {
self.filled = len;
unsafe { self.buf.set_len(self.total_filled + self.filled) };
}
}
impl<T: IoVectoredBufMut> IoBufMut for VectoredBufIter<T> {
fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
self.buf
.iter_uninit_slice()
.nth(self.index)
.expect("`index` should not exceed `len`")
}
}