use bytes::{Buf, Bytes, BytesMut};
use std::collections::VecDeque;
#[derive(Debug, Default)]
pub struct SegmentedBuffer {
segs: VecDeque<Bytes>,
len: usize,
}
impl SegmentedBuffer {
#[must_use]
pub const fn new() -> Self {
Self {
segs: VecDeque::new(),
len: 0,
}
}
#[inline]
#[must_use]
pub const fn len(&self) -> usize {
self.len
}
#[inline]
#[must_use]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn push(&mut self, bytes: Bytes) {
if bytes.is_empty() {
return;
}
self.len += bytes.len();
self.segs.push_back(bytes);
}
pub fn copy_prefix(&self, n: usize, dst: &mut [u8]) -> bool {
if n > self.len || dst.len() < n {
return false;
}
let mut remaining = n;
let mut out_off = 0;
for seg in &self.segs {
if remaining == 0 {
break;
}
let take = remaining.min(seg.len());
dst[out_off..out_off + take].copy_from_slice(&seg[..take]);
out_off += take;
remaining -= take;
}
true
}
pub fn advance(&mut self, mut n: usize) {
assert!(n <= self.len);
self.len -= n;
while n > 0 {
let Some(mut front) = self.segs.pop_front() else {
break;
};
if n >= front.len() {
n -= front.len();
continue;
}
front.advance(n);
self.segs.push_front(front);
break;
}
}
pub fn take_bytes(&mut self, n: usize) -> Option<Bytes> {
if n == 0 {
return Some(Bytes::new());
}
if n > self.len {
return None;
}
let Some(front) = self.segs.front_mut() else {
return None;
};
if front.len() >= n {
self.len -= n;
let out = front.split_to(n);
if front.is_empty() {
self.segs.pop_front();
}
return Some(out);
}
let mut out = BytesMut::with_capacity(n);
let mut remaining = n;
while remaining > 0 {
let seg = self
.segs
.pop_front()
.expect("len check ensures segments exist");
let take = remaining.min(seg.len());
out.extend_from_slice(&seg[..take]);
remaining -= take;
self.len -= take;
if take < seg.len() {
let mut rest = seg;
rest.advance(take);
self.segs.push_front(rest);
}
}
Some(out.freeze())
}
}