use std::{
fmt::{Debug, Formatter},
ops::{Deref, DerefMut},
str,
};
#[derive(Default)]
#[doc(hidden)]
pub struct Buffer(usize, Vec<u8>);
impl Debug for Buffer {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let slice = self.as_slice();
if let Ok(str) = str::from_utf8(slice) {
str.fmt(f)
} else {
slice.fmt(f)
}
}
}
impl From<Buffer> for Vec<u8> {
fn from(Buffer(offset, mut vec): Buffer) -> Self {
if offset > 0 {
vec.copy_within(offset.., 0);
vec.truncate(vec.len() - offset);
}
vec
}
}
impl From<Vec<u8>> for Buffer {
fn from(value: Vec<u8>) -> Self {
Self(0, value)
}
}
impl Deref for Buffer {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl DerefMut for Buffer {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
#[doc(hidden)]
impl Buffer {
pub fn truncate(&mut self, n: usize) {
if n == 0 {
self.0 = 0;
self.1.clear();
} else {
self.1.truncate(self.0 + n);
}
}
pub fn extend_from_slice(&mut self, slice: &[u8]) {
self.1.extend_from_slice(slice);
}
pub fn prepend(&mut self, slice: &[u8]) {
if slice.len() <= self.0 {
self.0 -= slice.len();
self.1[self.0..self.0 + slice.len()].copy_from_slice(slice);
} else {
let active_len = self.len();
let new_total = slice.len() + active_len;
self.1.resize(new_total, 0);
if active_len > 0 {
self.1.copy_within(self.0..self.0 + active_len, slice.len());
}
self.1[..slice.len()].copy_from_slice(slice);
self.0 = 0;
}
}
pub fn ignore_front(&mut self, n: usize) {
self.0 += n;
if self.0 >= self.1.len() {
self.1.clear();
self.0 = 0;
}
}
pub fn len(&self) -> usize {
self.1.len() - self.0
}
pub fn is_empty(&self) -> bool {
self.1.len() == self.0
}
pub fn fill_capacity(&mut self) {
self.1.resize(self.1.capacity(), 0);
}
pub fn with_capacity(capacity: usize) -> Self {
Self(0, Vec::with_capacity(capacity))
}
pub fn expand(&mut self) {
if self.1.len() == self.1.capacity() {
let live = self.len();
if self.0 > 0 && self.0 >= live {
self.1.copy_within(self.0.., 0);
self.1.truncate(live);
self.0 = 0;
} else {
self.1.reserve(32);
}
}
self.fill_capacity();
}
pub fn as_slice(&self) -> &[u8] {
&self.1[self.0..]
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.1[self.0..]
}
}
#[cfg(test)]
mod tests {
use super::Buffer;
#[test]
fn prepend_on_empty_default() {
let mut buf = Buffer::default();
buf.prepend(b"hello");
assert_eq!(&*buf, b"hello");
assert_eq!(buf.len(), 5);
assert_eq!(buf.0, 0);
}
#[test]
fn prepend_empty_slice_is_noop() {
let mut buf = Buffer::default();
buf.prepend(b"");
assert!(buf.is_empty());
let mut buf = Buffer::from(b"abc".to_vec());
buf.ignore_front(1);
let offset_before = buf.0;
buf.prepend(b"");
assert_eq!(&*buf, b"bc");
assert_eq!(buf.0, offset_before);
}
#[test]
fn prepend_fast_path_uses_existing_room() {
let mut buf = Buffer::from(b"abcdef".to_vec());
buf.ignore_front(4); assert_eq!(buf.0, 4);
let ptr_before = buf.1.as_ptr();
let len_before = buf.1.len();
buf.prepend(b"XYZ"); assert_eq!(&*buf, b"XYZef");
assert_eq!(buf.0, 1);
assert_eq!(buf.1.len(), len_before, "underlying vec length unchanged");
assert_eq!(buf.1.as_ptr(), ptr_before, "no reallocation on fast path");
}
#[test]
fn prepend_fast_path_exact_offset() {
let mut buf = Buffer::from(b"abcdef".to_vec());
buf.ignore_front(3); buf.prepend(b"XYZ"); assert_eq!(&*buf, b"XYZdef");
assert_eq!(buf.0, 0);
}
#[test]
fn prepend_slow_path_zero_offset_with_content() {
let mut buf = Buffer::from(b"world".to_vec());
assert_eq!(buf.0, 0);
buf.prepend(b"hello ");
assert_eq!(&*buf, b"hello world");
assert_eq!(buf.0, 0);
}
#[test]
fn prepend_slow_path_insufficient_offset() {
let mut buf = Buffer::from(b"abcdef".to_vec());
buf.ignore_front(2); buf.prepend(b"WXYZ"); assert_eq!(&*buf, b"WXYZcdef");
assert_eq!(buf.0, 0);
}
#[test]
fn prepend_preserves_order_after_extend() {
let mut buf = Buffer::default();
buf.extend_from_slice(b"later"); buf.prepend(b"earlier "); assert_eq!(&*buf, b"earlier later");
}
#[test]
fn expand_compacts_when_offset_reclaims_enough() {
let mut buf = Buffer::from(b"ABCDEFGH".to_vec()); let cap_before = buf.1.capacity();
buf.ignore_front(5); let ptr_before = buf.1.as_ptr();
buf.expand();
assert_eq!(buf.1.as_ptr(), ptr_before, "compaction must not reallocate");
assert_eq!(
buf.1.capacity(),
cap_before,
"capacity unchanged by compaction"
);
assert_eq!(buf.0, 0, "offset reset to front");
assert_eq!(&buf[..3], b"FGH", "live content preserved in order");
}
#[test]
fn expand_grows_when_offset_too_small() {
let mut buf = Buffer::from(b"ABCDEFGH".to_vec());
let cap_before = buf.1.capacity();
buf.ignore_front(2);
buf.expand();
assert!(
buf.1.capacity() > cap_before,
"must grow when offset is too small"
);
assert_eq!(buf.0, 2, "offset unchanged when growing");
assert_eq!(&buf[..6], b"CDEFGH", "live content preserved");
}
#[test]
fn expand_grows_default_buffer() {
let mut buf = Buffer::default();
buf.expand();
assert!(buf.1.capacity() >= 32);
assert_eq!(buf.len(), buf.1.capacity());
}
#[test]
fn expand_grows_full_buffer_with_no_offset() {
let mut buf = Buffer::from(b"ABCD".to_vec()); let cap_before = buf.1.capacity();
buf.expand();
assert!(buf.1.capacity() > cap_before);
assert_eq!(&buf[..4], b"ABCD");
}
#[test]
fn into_vec_round_trips_active_region() {
let mut buf = Buffer::from(b"abcdef".to_vec());
buf.ignore_front(2);
assert_eq!(Vec::from(buf), b"cdef");
let buf = Buffer::from(b"xyz".to_vec());
assert_eq!(Vec::from(buf), b"xyz");
}
#[test]
fn prepend_then_ignore_front_then_prepend() {
let mut buf = Buffer::from(b"cccc".to_vec());
buf.ignore_front(4); assert!(buf.is_empty());
buf.prepend(b"bb"); assert_eq!(&*buf, b"bb");
buf.ignore_front(1);
buf.prepend(b"a"); assert_eq!(&*buf, b"ab");
}
}