use alloc::vec::Vec;
pub(crate) struct CircularBuffer {
buffer: Vec<u8>,
start: usize,
len: usize,
}
impl CircularBuffer {
pub(crate) fn with_capacity(capacity: usize) -> Self {
let capacity = capacity.next_power_of_two().max(4096);
Self {
buffer: vec![0u8; capacity],
start: 0,
len: 0,
}
}
#[inline]
pub(crate) fn available_data(&self) -> usize {
self.len
}
pub(crate) fn as_slices(&self) -> (&[u8], &[u8]) {
if self.len == 0 {
return (&[], &[]);
}
let end = (self.start + self.len) & (self.buffer.len() - 1);
if end > self.start {
(&self.buffer[self.start..self.start + self.len], &[])
} else if end == 0 {
(&self.buffer[self.start..], &[])
} else {
(&self.buffer[self.start..], &self.buffer[..end])
}
}
pub(crate) fn copy_to(&self, out: &mut [u8]) -> usize {
let copy_len = out.len().min(self.len);
if copy_len == 0 {
return 0;
}
let (first, second) = self.as_slices();
if copy_len <= first.len() {
out[..copy_len].copy_from_slice(&first[..copy_len]);
} else {
let first_len = first.len();
out[..first_len].copy_from_slice(first);
let remaining = copy_len - first_len;
if remaining > 0 && !second.is_empty() {
out[first_len..copy_len].copy_from_slice(&second[..remaining]);
}
}
copy_len
}
pub(crate) fn append(&mut self, data: &[u8]) {
if data.is_empty() {
return;
}
if self.len + data.len() > self.buffer.len() {
let new_capacity = (self.len + data.len()).next_power_of_two();
let mut new_buffer = vec![0u8; new_capacity];
let copied = self.copy_to(&mut new_buffer[..self.len]);
debug_assert_eq!(copied, self.len);
self.buffer = new_buffer;
self.start = 0;
}
let write_pos = (self.start + self.len) & (self.buffer.len() - 1);
let available_at_end = self.buffer.len() - write_pos;
if data.len() <= available_at_end {
self.buffer[write_pos..write_pos + data.len()].copy_from_slice(data);
} else {
self.buffer[write_pos..].copy_from_slice(&data[..available_at_end]);
self.buffer[..data.len() - available_at_end].copy_from_slice(&data[available_at_end..]);
}
self.len += data.len();
}
#[inline]
pub(crate) fn consume(&mut self, count: usize) {
let consume_count = count.min(self.len);
self.start = (self.start + consume_count) & (self.buffer.len() - 1);
self.len -= consume_count;
}
pub(crate) fn fill_batch_from_buffer<const BATCH: usize, const DATA_LEN: usize>(
&self,
batch_codewords: &mut [[u8; DATA_LEN]; BATCH],
batch_data_size: usize,
) -> bool {
let (first_slice, second_slice) = self.as_slices();
if first_slice.len() >= batch_data_size {
for (i, codeword) in batch_codewords.iter_mut().enumerate() {
let start = i * DATA_LEN;
codeword.copy_from_slice(&first_slice[start..start + DATA_LEN]);
}
return true;
} else if first_slice.len() + second_slice.len() >= batch_data_size {
let mut processed_bytes = 0;
let mut codeword_idx = 0;
while processed_bytes + DATA_LEN <= first_slice.len() && codeword_idx < BATCH {
batch_codewords[codeword_idx]
.copy_from_slice(&first_slice[processed_bytes..processed_bytes + DATA_LEN]);
processed_bytes += DATA_LEN;
codeword_idx += 1;
}
if processed_bytes < first_slice.len() && codeword_idx < BATCH {
let remaining_in_first = first_slice.len() - processed_bytes;
let needed_from_second = DATA_LEN - remaining_in_first;
if needed_from_second <= second_slice.len() {
batch_codewords[codeword_idx][..remaining_in_first]
.copy_from_slice(&first_slice[processed_bytes..]);
batch_codewords[codeword_idx][remaining_in_first..DATA_LEN]
.copy_from_slice(&second_slice[..needed_from_second]);
codeword_idx += 1;
processed_bytes = needed_from_second;
}
} else {
processed_bytes = 0;
}
while processed_bytes + DATA_LEN <= second_slice.len() && codeword_idx < BATCH {
batch_codewords[codeword_idx]
.copy_from_slice(&second_slice[processed_bytes..processed_bytes + DATA_LEN]);
processed_bytes += DATA_LEN;
codeword_idx += 1;
}
return true;
}
false
}
}