chunkable-ringbuf/src/lib.rs

131 lines
3.2 KiB
Rust

#[cfg(test)]
mod test;
pub struct RingBuf<T> {
data: Vec<T>,
read_index: usize,
write_index: usize,
available: usize,
}
impl<T> RingBuf<T> {
pub fn new(size: usize, value: T) -> Self
where
T: Clone,
{
Self {
data: vec![value; size],
read_index: 0,
write_index: 0,
available: 0,
}
}
pub fn push(&mut self, value: T) -> bool {
if self.available < self.data.len() {
self.data[self.write_index] = value;
self.write_index = (self.write_index + 1) % self.data.len();
self.available = (self.available + 1).min(self.data.len());
true
} else {
false
}
}
pub fn push_unchecked(&mut self, value: T) {
self.data[self.write_index] = value;
self.write_index = (self.write_index + 1) % self.data.len();
self.available = (self.available + 1).min(self.data.len());
}
pub fn push_from_iter<I: Iterator<Item = T>>(&mut self, mut iter: I) -> usize {
let mut len = 0;
while len < self.data.len() - self.available {
if let Some(value) = iter.next() {
self.data[self.write_index] = value;
self.write_index = (self.write_index + 1) % self.data.len();
len += 1;
} else {
break;
}
}
self.available += len;
len
}
pub fn push_from_iter_unchecked<I: Iterator<Item = T>>(&mut self, iter: I) -> usize {
let mut len = 0;
for value in iter {
self.data[self.write_index] = value;
self.write_index = (self.write_index + 1) % self.data.len();
len += 1;
}
self.available = (self.available + len).min(self.data.len());
len
}
pub fn chunks_exact(&mut self, chunk_size: usize) -> ChunksExact<T> {
assert_eq!(self.read_index % chunk_size, 0);
assert_eq!(self.data.len() % chunk_size, 0);
ChunksExact {
ringbuf: self,
chunk_size,
}
}
pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<T> {
assert_eq!(self.read_index % chunk_size, 0);
assert_eq!(self.data.len() % chunk_size, 0);
ChunksExactMut {
ringbuf: self,
chunk_size,
}
}
}
pub struct ChunksExact<'a, T> {
ringbuf: &'a mut RingBuf<T>,
chunk_size: usize,
}
impl<'a, T> Iterator for ChunksExact<'a, T> {
type Item = &'a [T];
fn next(&mut self) -> Option<Self::Item> {
if self.ringbuf.available >= self.chunk_size {
let read_index = self.ringbuf.read_index;
self.ringbuf.read_index =
(self.ringbuf.read_index + self.chunk_size) % self.ringbuf.data.len();
self.ringbuf.available -= self.chunk_size;
let ret: &[T] = &self.ringbuf.data[read_index..read_index + self.chunk_size];
let ret: &'a [T] = unsafe { std::mem::transmute(ret) };
Some(ret)
} else {
None
}
}
}
pub struct ChunksExactMut<'a, T> {
ringbuf: &'a mut RingBuf<T>,
chunk_size: usize,
}
impl<'a, T> Iterator for ChunksExactMut<'a, T> {
type Item = &'a mut [T];
fn next(&mut self) -> Option<Self::Item> {
if self.ringbuf.available >= self.chunk_size {
let read_index = self.ringbuf.read_index;
self.ringbuf.read_index =
(self.ringbuf.read_index + self.chunk_size) % self.ringbuf.data.len();
self.ringbuf.available -= self.chunk_size;
let ret: &mut [T] = &mut self.ringbuf.data[read_index..read_index + self.chunk_size];
let ret: &'a mut [T] = unsafe { std::mem::transmute(ret) };
Some(ret)
} else {
None
}
}
}