pub trait PrefixBuffer {
fn as_slice(&self) -> &[u8];
fn as_slice_mut(&mut self) -> &mut [u8];
fn available(&self) -> usize;
fn len(&self) -> usize;
fn reserve(&mut self, size: usize) -> &mut [u8];
fn take(&mut self, amount: usize);
fn view(&mut self) -> BufferView<'_>;
fn take_u32(&mut self) -> u32 {
let size = std::mem::size_of::<u32>();
assert!(size <= self.len(), "You can only take as much as you have");
let result = u32::from_le_bytes(self.as_slice()[0..size].try_into().unwrap());
self.take(size);
result
}
fn reset(&mut self) {
self.take(self.len());
}
fn set(&mut self, value: &[u8]) {
self.reset();
self.prefix(value);
}
fn prefix(&mut self, value: &[u8]) -> &mut Self {
assert!(
value.len() <= self.available(),
"You can only prefix as much as you have available"
);
self.reserve(value.len()).copy_from_slice(value);
self
}
fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub struct BufferView<'a> {
head: usize,
data: &'a mut [u8],
}
impl<'a> BufferView<'a> {
pub fn new(data: &'a mut [u8]) -> Self {
Self {
head: data.len(),
data,
}
}
pub fn with_available(available: usize, data: &'a mut [u8]) -> BufferView<'a> {
assert!(
available <= data.len(),
"available must be less than or equal to the length of the slice"
);
Self {
head: available,
data,
}
}
pub fn with_prefix(data: &'a mut [u8], value: &[u8]) -> Self {
assert!(
value.len() <= data.len(),
"the prefix must be smaller than the buffer"
);
let head = data.len() - value.len();
data[head..].copy_from_slice(value);
Self { head, data }
}
}
impl PrefixBuffer for BufferView<'_> {
fn available(&self) -> usize {
debug_assert!(self.head <= self.data.len());
self.head
}
fn as_slice(&self) -> &[u8] {
debug_assert!(self.head <= self.data.len());
&self.data[self.head..]
}
fn as_slice_mut(&mut self) -> &mut [u8] {
debug_assert!(self.head <= self.data.len());
&mut self.data[self.head..]
}
fn len(&self) -> usize {
debug_assert!(self.head <= self.data.len());
self.data.len() - self.head
}
fn reserve(&mut self, size: usize) -> &mut [u8] {
assert!(
size <= self.head,
"You can only reserve as much as you have available"
);
let head = self.head;
let new_head = head - size;
let head = self.head;
let result = &mut self.data[new_head..head];
self.head = new_head;
result
}
fn take(&mut self, amount: usize) {
assert!(
self.head + amount <= self.data.len(),
"You can only take as much as you have"
);
self.head += amount;
}
fn view(&mut self) -> BufferView<'_> {
BufferView {
head: self.head,
data: self.data,
}
}
}
pub struct StaticBuffer<const SIZE: usize> {
head: usize,
tail: usize,
data: [u8; SIZE],
}
impl<const SIZE: usize> StaticBuffer<SIZE> {
pub fn new() -> Self {
Self {
head: SIZE,
tail: SIZE,
data: [0; SIZE],
}
}
pub fn with(value: &[u8]) -> Self {
let mut this = Self {
head: SIZE,
tail: SIZE,
data: [0; SIZE],
};
this.set(value);
this
}
pub fn keep(&mut self, size: usize) {
let tail = self.head + size;
assert!(
tail <= self.tail,
"You can only keep as much as you have. size is {} but len() is {}",
size,
self.len()
);
self.tail = tail;
}
}
impl<const SIZE: usize> PrefixBuffer for StaticBuffer<SIZE> {
fn available(&self) -> usize {
debug_assert!(self.head <= self.tail);
self.head
}
fn as_slice(&self) -> &[u8] {
debug_assert!(self.head <= self.tail);
&self.data[self.head..self.tail]
}
fn as_slice_mut(&mut self) -> &mut [u8] {
debug_assert!(self.head <= self.tail);
&mut self.data[self.head..self.tail]
}
fn len(&self) -> usize {
debug_assert!(self.head <= self.tail);
self.tail - self.head
}
fn reserve(&mut self, size: usize) -> &mut [u8] {
assert!(
size <= self.head,
"You can only reserve as much as you have available"
);
let head = self.head;
let new_head = head - size;
let head = self.head;
let result = &mut self.data[new_head..head];
self.head = new_head;
result
}
fn take(&mut self, amount: usize) {
assert!(
self.head + amount <= self.tail,
"You can only take as much as you have"
);
self.head += amount;
}
fn reset(&mut self) {
self.head = self.data.len();
self.tail = self.data.len();
}
fn view(&mut self) -> BufferView<'_> {
BufferView::with_available(self.head, &mut self.data[..self.tail])
}
}
impl<const SIZE: usize> Default for StaticBuffer<SIZE> {
fn default() -> Self {
Self::new()
}
}
pub struct OwnedBuffer {
head: usize,
tail: usize,
data: Box<[u8]>,
}
impl OwnedBuffer {
pub fn new(size: usize) -> Self {
Self {
head: size,
tail: size,
data: vec![0; size].into_boxed_slice(),
}
}
pub fn with(size: usize, value: &[u8]) -> Self {
let mut this = Self::new(size);
this.set(value);
this
}
pub fn keep(&mut self, size: usize) {
let tail = self.head + size;
assert!(
tail <= self.tail,
"You can only keep as much as you have. size is {} but len() is {}",
size,
self.len()
);
self.tail = tail;
}
}
impl PrefixBuffer for OwnedBuffer {
fn available(&self) -> usize {
debug_assert!(self.head <= self.tail);
self.head
}
fn as_slice(&self) -> &[u8] {
debug_assert!(self.head <= self.tail);
&self.data[self.head..self.tail]
}
fn as_slice_mut(&mut self) -> &mut [u8] {
debug_assert!(self.head <= self.tail);
&mut self.data[self.head..self.tail]
}
fn len(&self) -> usize {
debug_assert!(self.head <= self.tail);
self.tail - self.head
}
fn reserve(&mut self, size: usize) -> &mut [u8] {
assert!(
size <= self.head,
"You can only reserve as much as you have available"
);
let head = self.head;
let new_head = head - size;
let head = self.head;
let result = &mut self.data[new_head..head];
self.head = new_head;
result
}
fn take(&mut self, amount: usize) {
assert!(
self.head + amount <= self.tail,
"You can only take as much as you have"
);
self.head += amount;
}
fn reset(&mut self) {
self.head = self.data.len();
self.tail = self.data.len();
}
fn view(&mut self) -> BufferView<'_> {
BufferView::with_available(self.head, &mut self.data[..self.tail])
}
}
#[cfg(test)]
mod test {
use crate::{BufferView, OwnedBuffer, StaticBuffer, prefix_buffer::PrefixBuffer};
pub fn buffer_impl_tests<B: PrefixBuffer>(mut buffer: B, size: usize) {
let assert_buffer = |buffer: &B, expected: &[u8]| {
assert_eq!(buffer.len(), expected.len());
assert_eq!(buffer.as_slice(), expected);
assert_eq!(buffer.available(), size - buffer.len());
assert_eq!(buffer.is_empty(), buffer.len() == 0);
};
buffer.prefix(&[1, 2, 3]);
assert_buffer(&buffer, &[1, 2, 3]);
buffer.prefix(&[4, 5, 6]);
assert_buffer(&buffer, &[4, 5, 6, 1, 2, 3]);
buffer.reset();
assert_buffer(&buffer, &[]);
buffer.prefix(&[4, 5, 6]);
assert_buffer(&buffer, &[4, 5, 6]);
buffer.prefix(&[1, 2, 3]);
assert_buffer(&buffer, &[1, 2, 3, 4, 5, 6]);
buffer.take(2);
assert_buffer(&buffer, &[3, 4, 5, 6]);
buffer.reset();
assert_buffer(&buffer, &[]);
let reserved = buffer.reserve(3);
reserved.copy_from_slice(&[1, 2, 3]);
assert_buffer(&buffer, &[1, 2, 3]);
buffer.set(&[1, 0, 0, 0, 5]);
assert_eq!(buffer.as_slice(), &[1, 0, 0, 0, 5]);
let value = buffer.take_u32();
assert_buffer(&buffer, &[5]);
assert_eq!(value, 1);
}
#[test]
pub fn buffer_tests() {
let mut buffer = [0; 768];
let len = buffer.len();
let view = BufferView::new(&mut buffer);
buffer_impl_tests(view, len);
}
#[test]
pub fn owned_buffer_tests() {
const SIZE: usize = 1024;
let mut buffer = OwnedBuffer::new(SIZE);
buffer.set(b"abcd");
buffer.keep(2);
assert_eq!(buffer.as_slice(), b"ab");
buffer.reset();
buffer_impl_tests(buffer.view(), SIZE);
buffer_impl_tests(buffer, SIZE);
let mut buffer = OwnedBuffer::with(SIZE, b"abcd");
assert_eq!(buffer.as_slice(), b"abcd");
buffer.as_slice_mut().copy_from_slice(b"1234");
assert_eq!(buffer.as_slice(), b"1234");
}
#[test]
pub fn static_buffer_tests() {
const SIZE: usize = 1023;
let mut buffer = StaticBuffer::<1023>::default();
buffer.set(b"abcd");
buffer.keep(2);
assert_eq!(buffer.as_slice(), b"ab");
buffer.reset();
buffer_impl_tests(buffer.view(), SIZE);
buffer_impl_tests(buffer, SIZE);
let mut buffer = StaticBuffer::<1023>::with(b"abcd");
assert_eq!(buffer.as_slice(), b"abcd");
buffer.as_slice_mut().copy_from_slice(b"1234");
assert_eq!(buffer.as_slice(), b"1234");
}
#[test]
#[should_panic(expected = "You can only keep as much as you have. size is 21 but len() is 20")]
pub fn owned_buffer_keep_too_much_test() {
let mut buffer = OwnedBuffer::new(1024);
buffer.reserve(20);
buffer.keep(21);
}
#[test]
pub fn buffer_view_tests() {
let mut buffer = [0; 256];
let mut view = BufferView::with_prefix(&mut buffer, b"abcd");
assert_eq!(view.as_slice(), b"abcd");
view.as_slice_mut().copy_from_slice(b"1234");
assert_eq!(view.as_slice(), b"1234");
let mut view2 = view.view();
view2.prefix(b"5678");
assert_eq!(view.as_slice(), b"1234");
}
}