use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::{
collections::VecDeque,
io::IoSlice,
iter::{FromIterator, FusedIterator},
sync::OnceLock,
};
#[derive(Clone, Debug, Default)]
pub struct BufList {
bufs: VecDeque<Bytes>,
start_pos: OnceLock<Box<[u64]>>,
}
impl BufList {
#[inline]
pub fn new() -> Self {
Self::default()
}
#[inline]
pub(crate) fn get_start_pos(&self) -> &[u64] {
self.start_pos.get_or_init(|| {
let mut start_pos = Vec::with_capacity(self.bufs.len() + 1);
let mut next = 0u64;
for chunk in self.bufs.iter() {
start_pos.push(next);
next += chunk.len() as u64;
}
start_pos.push(next);
start_pos.into_boxed_slice()
})
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
bufs: VecDeque::with_capacity(capacity),
start_pos: OnceLock::new(),
}
}
#[inline]
pub fn num_chunks(&self) -> usize {
self.bufs.len()
}
#[inline]
pub fn num_bytes(&self) -> usize {
self.remaining()
}
#[inline]
pub fn get_chunk(&self, index: usize) -> Option<&Bytes> {
self.bufs.get(index)
}
#[inline]
pub fn iter(&self) -> Iter<'_> {
Iter {
iter: self.bufs.iter(),
}
}
pub fn push_chunk<B: Buf>(&mut self, mut data: B) -> Bytes {
self.start_pos = OnceLock::new();
let len = data.remaining();
let bytes = data.copy_to_bytes(len);
if len > 0 {
self.bufs.push_back(bytes.clone());
}
bytes
}
}
impl<B: Buf> Extend<B> for BufList {
fn extend<T: IntoIterator<Item = B>>(&mut self, iter: T) {
self.start_pos = OnceLock::new();
for buf in iter.into_iter() {
self.push_chunk(buf);
}
}
}
impl<B: Buf> FromIterator<B> for BufList {
fn from_iter<T: IntoIterator<Item = B>>(iter: T) -> Self {
let mut buf_list = BufList::new();
for buf in iter.into_iter() {
buf_list.push_chunk(buf);
}
buf_list
}
}
impl IntoIterator for BufList {
type Item = Bytes;
type IntoIter = IntoIter;
#[inline]
fn into_iter(self) -> Self::IntoIter {
IntoIter {
iter: self.bufs.into_iter(),
}
}
}
impl<'a> IntoIterator for &'a BufList {
type Item = &'a Bytes;
type IntoIter = Iter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl AsRef<BufList> for BufList {
fn as_ref(&self) -> &BufList {
self
}
}
impl Buf for BufList {
fn remaining(&self) -> usize {
self.bufs.iter().map(Buf::remaining).sum()
}
fn chunk(&self) -> &[u8] {
self.bufs.front().map(Buf::chunk).unwrap_or(&[])
}
fn chunks_vectored<'iovs>(&'iovs self, iovs: &mut [IoSlice<'iovs>]) -> usize {
if iovs.is_empty() {
return 0;
}
let to_fill = (iovs.len()).min(self.bufs.len());
for (i, iov) in iovs.iter_mut().enumerate().take(to_fill) {
*iov = IoSlice::new(&self.bufs[i]);
}
to_fill
}
fn advance(&mut self, mut amt: usize) {
self.start_pos = OnceLock::new();
while amt > 0 {
let rem = self.bufs[0].remaining();
if rem > amt {
self.bufs[0].advance(amt);
return;
}
self.bufs[0].advance(rem);
amt -= rem;
self.bufs.pop_front();
}
}
fn copy_to_bytes(&mut self, len: usize) -> Bytes {
self.start_pos = OnceLock::new();
match self.bufs.front_mut() {
Some(first) if len <= first.remaining() => {
let buf = first.copy_to_bytes(len);
if first.remaining() == 0 {
self.bufs.pop_front();
}
buf
}
_ => {
assert!(
len <= self.remaining(),
"`len` ({}) greater than remaining ({})",
len,
self.remaining()
);
let mut buf = BytesMut::with_capacity(len);
buf.put(self.take(len));
buf.freeze()
}
}
}
}
impl<T: Into<Bytes>> From<T> for BufList {
fn from(value: T) -> Self {
let mut buf_list = BufList::with_capacity(1);
buf_list.push_chunk(value.into());
buf_list
}
}
#[derive(Clone, Debug)]
pub struct IntoIter {
iter: std::collections::vec_deque::IntoIter<Bytes>,
}
impl Iterator for IntoIter {
type Item = Bytes;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for IntoIter {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl ExactSizeIterator for IntoIter {
#[inline]
fn len(&self) -> usize {
self.iter.len()
}
}
impl FusedIterator for IntoIter {}
#[derive(Clone, Debug)]
pub struct Iter<'a> {
iter: std::collections::vec_deque::Iter<'a, Bytes>,
}
impl<'a> Iterator for Iter<'a> {
type Item = &'a Bytes;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
#[inline]
fn fold<B, F>(self, init: B, f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
self.iter.fold(init, f)
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.iter.nth(n)
}
#[inline]
fn last(self) -> Option<Self::Item>
where
Self: Sized,
{
self.iter.last()
}
}
impl<'a> DoubleEndedIterator for Iter<'a> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
#[inline]
fn rfold<B, F>(self, init: B, f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
self.iter.rfold(init, f)
}
}
impl<'a> ExactSizeIterator for Iter<'a> {
#[inline]
fn len(&self) -> usize {
self.iter.len()
}
}
impl<'a> FusedIterator for Iter<'a> {}