#![deny(unsafe_code)]
const DEFAULT_SEGMENT_SIZE: usize = 256 * 1024 * 1024;
pub struct SegmentedBuf {
segment_size: usize,
segments: Vec<Vec<u8>>,
total_len: usize,
}
#[allow(dead_code)] impl SegmentedBuf {
#[must_use]
pub fn with_capacity(capacity: usize, segment_size: usize) -> Self {
let segment_size = segment_size.max(1);
let first_cap = capacity.min(segment_size);
let estimated_segments = (capacity / segment_size).max(1);
let mut segments = Vec::with_capacity(estimated_segments);
segments.push(Vec::with_capacity(first_cap));
Self { segment_size, segments, total_len: 0 }
}
#[must_use]
pub fn new() -> Self {
Self::with_capacity(0, DEFAULT_SEGMENT_SIZE)
}
pub fn extend_from_slice(&mut self, data: &[u8]) -> usize {
assert!(
data.len() <= self.segment_size,
"write of {} bytes exceeds segment size {}",
data.len(),
self.segment_size,
);
let seg = self.segments.last().expect("segments is never empty");
if seg.len() + data.len() > self.segment_size {
let remainder = self.total_len % self.segment_size;
if remainder > 0 {
self.total_len += self.segment_size - remainder;
}
self.segments.push(Vec::with_capacity(self.segment_size));
}
let offset = self.total_len;
self.segments.last_mut().expect("segments is never empty").extend_from_slice(data);
self.total_len += data.len();
offset
}
pub fn reserve_contiguous(&mut self, additional: usize) -> usize {
assert!(
additional <= self.segment_size,
"reserve of {} bytes exceeds segment size {}",
additional,
self.segment_size,
);
let seg = self.segments.last().expect("segments is never empty");
if seg.len() + additional > self.segment_size {
let remainder = self.total_len % self.segment_size;
if remainder > 0 {
self.total_len += self.segment_size - remainder;
}
self.segments.push(Vec::with_capacity(self.segment_size));
}
self.total_len
}
#[inline]
pub fn extend_in_place(&mut self, data: &[u8]) {
debug_assert!(
self.segments.last().is_some_and(|s| s.len() + data.len() <= self.segment_size),
"extend_in_place exceeds segment capacity; use reserve_contiguous first"
);
self.segments.last_mut().expect("segments is never empty").extend_from_slice(data);
self.total_len += data.len();
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.total_len
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.total_len == 0
}
#[inline]
#[must_use]
pub fn slice(&self, offset: usize, len: usize) -> &[u8] {
let (seg_idx, seg_offset) = self.locate(offset);
let seg = &self.segments[seg_idx];
assert!(
seg_offset + len <= seg.len(),
"slice ({offset}..{}) spans segment boundary (seg {seg_idx}, seg_offset {seg_offset}, seg_len {})",
offset + len,
seg.len(),
);
&seg[seg_offset..seg_offset + len]
}
#[must_use]
pub fn allocated_capacity(&self) -> usize {
self.segments.iter().map(Vec::capacity).sum()
}
#[must_use]
pub fn num_segments(&self) -> usize {
self.segments.len()
}
pub fn clear(&mut self) {
self.segments.truncate(1);
self.segments[0].clear();
self.total_len = 0;
}
#[inline]
fn locate(&self, offset: usize) -> (usize, usize) {
let seg_idx = offset / self.segment_size;
let seg_offset = offset % self.segment_size;
debug_assert!(
seg_idx < self.segments.len(),
"locate({offset}): seg_idx {seg_idx} out of bounds (len {})",
self.segments.len()
);
(seg_idx, seg_offset)
}
#[must_use]
pub fn segment_size(&self) -> usize {
self.segment_size
}
}
impl Default for SegmentedBuf {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_is_empty() {
let buf = SegmentedBuf::new();
assert!(buf.is_empty());
assert_eq!(buf.len(), 0);
assert_eq!(buf.num_segments(), 1); }
#[test]
fn test_extend_and_len() {
let mut buf = SegmentedBuf::with_capacity(0, 1024);
let o1 = buf.extend_from_slice(b"hello");
assert_eq!(o1, 0);
assert_eq!(buf.len(), 5);
assert!(!buf.is_empty());
let o2 = buf.extend_from_slice(b" world");
assert_eq!(o2, 5);
assert_eq!(buf.len(), 11);
}
#[test]
fn test_slice_retrieval() {
let mut buf = SegmentedBuf::with_capacity(0, 1024);
let o1 = buf.extend_from_slice(b"hello");
let o2 = buf.extend_from_slice(b" world");
assert_eq!(buf.slice(o1, 5), b"hello");
assert_eq!(buf.slice(o2, 6), b" world");
assert_eq!(buf.slice(o1, 11), b"hello world");
}
#[test]
fn test_segment_boundary() {
let mut buf = SegmentedBuf::with_capacity(0, 10);
let o1 = buf.extend_from_slice(b"0123456789");
assert_eq!(buf.num_segments(), 1);
assert_eq!(buf.len(), 10);
let o2 = buf.extend_from_slice(b"abcde");
assert_eq!(buf.num_segments(), 2);
assert_eq!(buf.len(), 15);
assert_eq!(buf.slice(o1, 10), b"0123456789");
assert_eq!(buf.slice(o2, 5), b"abcde");
}
#[test]
fn test_spill_to_new_segment_when_not_enough_room() {
let mut buf = SegmentedBuf::with_capacity(0, 10);
let o1 = buf.extend_from_slice(b"1234567"); assert_eq!(o1, 0);
assert_eq!(buf.num_segments(), 1);
let o2 = buf.extend_from_slice(b"abcde");
assert_eq!(o2, 10); assert_eq!(buf.num_segments(), 2);
assert_eq!(buf.len(), 15);
assert_eq!(buf.slice(o1, 7), b"1234567");
assert_eq!(buf.slice(o2, 5), b"abcde");
}
#[test]
fn test_offset_accounting_with_gaps() {
let mut buf = SegmentedBuf::with_capacity(0, 10);
let o0 = buf.extend_from_slice(b"aaa"); assert_eq!(o0, 0);
let o1 = buf.extend_from_slice(b"bbb"); assert_eq!(o1, 3);
let o2 = buf.extend_from_slice(b"ccccc");
assert_eq!(o2, 10);
assert_eq!(buf.len(), 15);
assert_eq!(buf.slice(o0, 3), b"aaa");
assert_eq!(buf.slice(o1, 3), b"bbb");
assert_eq!(buf.slice(o2, 5), b"ccccc");
}
#[test]
#[should_panic(expected = "exceeds segment size")]
fn test_write_exceeding_segment_panics() {
let mut buf = SegmentedBuf::with_capacity(0, 10);
buf.extend_from_slice(b"12345678901"); }
#[test]
fn test_clear_resets() {
let mut buf = SegmentedBuf::with_capacity(0, 1024);
buf.extend_from_slice(b"some data");
buf.clear();
assert!(buf.is_empty());
assert_eq!(buf.len(), 0);
assert_eq!(buf.num_segments(), 1);
}
#[test]
fn test_many_segments() {
let mut buf = SegmentedBuf::with_capacity(0, 100);
let mut offsets = Vec::new();
for i in 0u8..50 {
let record = vec![i; 80];
let offset = buf.extend_from_slice(&record);
offsets.push(offset);
}
assert_eq!(buf.num_segments(), 50);
#[allow(clippy::cast_possible_truncation)]
for (i, &offset) in offsets.iter().enumerate() {
let data = buf.slice(offset, 80);
assert_eq!(data[0], i as u8);
}
}
#[test]
fn test_realistic_record_pattern() {
let mut buf = SegmentedBuf::with_capacity(0, 1024);
let header = [0u8; 16];
let record = [42u8; 300];
let offset = buf.extend_from_slice(&header);
let record_offset = buf.extend_from_slice(&record);
assert_eq!(record_offset, offset + 16);
assert_eq!(buf.slice(offset, 16), &header);
assert_eq!(buf.slice(record_offset, 300), &record);
}
#[test]
fn test_memory_usage_includes_gaps() {
let mut buf = SegmentedBuf::with_capacity(0, 100);
buf.extend_from_slice(&[0u8; 60]); buf.extend_from_slice(&[0u8; 60]);
assert_eq!(buf.len(), 160);
}
#[test]
fn test_reserve_contiguous_then_multi_part_write() {
let mut buf = SegmentedBuf::with_capacity(0, 100);
let offset = buf.reserve_contiguous(76);
assert_eq!(offset, 0);
buf.extend_in_place(&[0xAA; 16]); buf.extend_in_place(&[0xBB; 60]);
let offset2 = buf.reserve_contiguous(76);
assert_eq!(offset2, 100); buf.extend_in_place(&[0xCC; 16]);
buf.extend_in_place(&[0xDD; 60]);
assert_eq!(buf.num_segments(), 2);
assert_eq!(buf.slice(0, 16), &[0xAA; 16]);
assert_eq!(buf.slice(16, 60), &[0xBB; 60]);
assert_eq!(buf.slice(100, 16), &[0xCC; 16]);
assert_eq!(buf.slice(116, 60), &[0xDD; 60]);
}
#[test]
fn test_consecutive_writes_same_segment() {
let mut buf = SegmentedBuf::with_capacity(0, 1024);
let o1 = buf.extend_from_slice(b"aaaa");
let o2 = buf.extend_from_slice(b"bbbb");
let o3 = buf.extend_from_slice(b"cccc");
assert_eq!(o1, 0);
assert_eq!(o2, 4);
assert_eq!(o3, 8);
assert_eq!(buf.num_segments(), 1);
assert_eq!(buf.slice(0, 12), b"aaaabbbbcccc");
}
}