#![allow(clippy::module_name_repetitions)]
#![allow(dead_code)]
#[derive(Debug)]
pub(crate) struct CursorBuf {
data: Vec<u8>,
head: usize,
}
impl CursorBuf {
#[must_use]
pub(crate) fn with_capacity(cap: usize) -> Self {
Self {
data: Vec::with_capacity(cap),
head: 0,
}
}
#[inline]
#[must_use]
pub(crate) fn len(&self) -> usize {
self.data.len() - self.head
}
#[inline]
#[must_use]
pub(crate) fn is_empty(&self) -> bool {
self.head == self.data.len()
}
#[inline]
#[must_use]
pub(crate) fn as_slice(&self) -> &[u8] {
&self.data[self.head..]
}
#[inline]
#[must_use]
pub(crate) fn as_ptr(&self) -> *const u8 {
unsafe { self.data.as_ptr().add(self.head) }
}
pub(crate) fn extend_from_slice(&mut self, bytes: &[u8]) {
if bytes.is_empty() {
return;
}
let need = self.data.len() + bytes.len();
if need > self.data.capacity() && self.head > 0 {
self.compact();
}
self.data.extend_from_slice(bytes);
}
#[inline]
pub(crate) fn consume(&mut self, n: usize) {
debug_assert!(n <= self.len(), "consume({n}) > len({})", self.len());
self.head += n;
if self.head == self.data.len() {
self.data.clear();
self.head = 0;
}
}
#[inline]
pub(crate) fn clear(&mut self) {
self.data.clear();
self.head = 0;
}
fn compact(&mut self) {
if self.head == 0 {
return;
}
self.data.drain(..self.head);
self.head = 0;
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::indexing_slicing)]
mod tests {
use super::*;
#[test]
fn extend_then_consume_all_resets() {
let mut b = CursorBuf::with_capacity(16);
b.extend_from_slice(b"hello");
assert_eq!(b.len(), 5);
assert_eq!(b.as_slice(), b"hello");
b.consume(5);
assert!(b.is_empty());
assert_eq!(b.as_slice(), b"");
}
#[test]
fn partial_consume_advances_head() {
let mut b = CursorBuf::with_capacity(16);
b.extend_from_slice(b"hello world");
b.consume(6);
assert_eq!(b.as_slice(), b"world");
assert_eq!(b.len(), 5);
}
#[test]
fn extend_after_partial_compacts_only_when_full() {
let mut b = CursorBuf::with_capacity(8);
b.extend_from_slice(b"abcdef"); b.consume(3); b.extend_from_slice(b"X"); assert_eq!(b.as_slice(), b"defX");
b.extend_from_slice(b"YZ"); assert_eq!(b.as_slice(), b"defXYZ");
assert_eq!(b.len(), 6);
}
#[test]
fn consume_exact_length_zeroes_head() {
let mut b = CursorBuf::with_capacity(4);
b.extend_from_slice(b"ab");
b.consume(1);
b.consume(1);
assert_eq!(b.len(), 0);
b.extend_from_slice(b"cd");
assert_eq!(b.as_slice(), b"cd");
}
#[test]
fn empty_extend_is_noop() {
let mut b = CursorBuf::with_capacity(4);
b.extend_from_slice(b"");
assert!(b.is_empty());
b.extend_from_slice(b"x");
b.extend_from_slice(b"");
assert_eq!(b.as_slice(), b"x");
}
#[test]
fn as_ptr_aligns_with_head() {
let mut b = CursorBuf::with_capacity(8);
b.extend_from_slice(b"hello");
let ptr0 = b.as_ptr();
b.consume(2);
unsafe {
assert_eq!(*ptr0.add(2), *b.as_ptr());
}
}
}