use core::borrow::{Borrow, BorrowMut};
use core::{cmp, ptr};
pub struct Buffer<S: BorrowMut<[u8]>> {
store: S,
rpos: usize,
wpos: usize,
}
impl<S: BorrowMut<[u8]>> Buffer<S> {
pub fn new(store: S) -> Self {
Self {
store,
rpos: 0,
wpos: 0,
}
}
pub fn clear(&mut self) {
self.rpos = 0;
self.wpos = 0;
}
pub fn available_read(&self) -> usize {
self.wpos - self.rpos
}
pub fn available_write(&self) -> usize {
self.available_write_without_discard() + self.rpos
}
fn available_write_without_discard(&self) -> usize {
self.store.borrow().len() - self.wpos
}
pub fn write(&mut self, data: &[u8]) -> usize {
if data.len() > self.available_write_without_discard() && self.rpos > 0 {
self.discard_already_read_data();
}
let count = cmp::min(self.available_write_without_discard(), data.len());
if count == 0 {
return 0;
}
self.store.borrow_mut()[self.wpos..self.wpos + count].copy_from_slice(&data[..count]);
self.wpos += count;
count
}
pub fn write_all<E>(
&mut self,
max_count: usize,
f: impl FnOnce(&mut [u8]) -> Result<usize, E>,
) -> Result<usize, E> {
if max_count > self.available_write_without_discard() {
if max_count > self.available_write() {
return Ok(0);
}
self.discard_already_read_data();
}
assert!(self.available_write_without_discard() >= max_count);
f(&mut self.store.borrow_mut()[self.wpos..self.wpos + max_count]).map(|count| {
self.wpos += count;
count
})
}
pub fn read<E>(
&mut self,
max_count: usize,
f: impl FnOnce(&[u8]) -> Result<usize, E>,
) -> Result<usize, E> {
let count = cmp::min(max_count, self.available_read());
f(&self.store.borrow()[self.rpos..self.rpos + count]).map(|count| {
self.rpos += count;
count
})
}
fn discard_already_read_data(&mut self) {
let data = self.store.borrow_mut();
if self.rpos != data.len() {
unsafe {
ptr::copy(
&data[self.rpos] as *const u8,
&mut data[0] as *mut u8,
self.available_read(),
);
}
}
self.wpos -= self.rpos;
self.rpos = 0;
}
}
pub struct DefaultBufferStore([u8; 128]);
impl Default for DefaultBufferStore {
fn default() -> Self {
Self([0u8; 128])
}
}
impl Borrow<[u8]> for DefaultBufferStore {
fn borrow(&self) -> &[u8] {
&self.0
}
}
impl BorrowMut<[u8]> for DefaultBufferStore {
fn borrow_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
#[cfg(test)]
mod tests {
use core::convert::Infallible;
extern crate std;
const DATA: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
const LEN: usize = 5;
type Buf = crate::buffer::Buffer<[u8; LEN]>;
#[test]
fn write() {
let mut b = Buf::new([0; LEN]);
assert_eq!(b.write(&DATA[0..2]), 2);
assert_eq!(b.available_write(), LEN - 2);
assert_eq!(b.available_read(), 2);
assert_eq!(b.write(&DATA[0..5]), 3);
assert_eq!(b.available_write(), 0);
assert_eq!(b.available_read(), LEN);
}
#[test]
fn read() {
let mut b = Buf::new([0; LEN]);
assert_eq!(b.write(&DATA[0..4]), 4);
b.read(3, |data| {
assert_eq!(data, &DATA[0..3]);
Ok::<usize, Infallible>(3)
})
.unwrap();
b.read(1, |data| {
assert_eq!(data, &DATA[3..4]);
Ok::<usize, Infallible>(1)
})
.unwrap();
b.read(1, |data| {
assert_eq!(data, &[]);
Ok::<usize, Infallible>(1)
})
.unwrap();
}
#[test]
fn clear() {
let mut b = Buf::new([0; LEN]);
b.write(&DATA[0..2]);
b.clear();
assert_eq!(b.available_write(), LEN);
assert_eq!(b.available_read(), 0);
}
#[test]
fn discard() {
let mut b = Buf::new([0; LEN]);
assert_eq!(b.write(&DATA[0..4]), 4);
b.read(2, |data| {
assert_eq!(data, &DATA[0..2]);
Ok::<usize, Infallible>(2)
})
.unwrap();
assert_eq!(b.write(&DATA[4..7]), 3);
b.read(5, |data| {
assert_eq!(data, &DATA[2..7]);
Ok::<usize, Infallible>(5)
})
.unwrap();
assert_eq!(b.available_read(), 0);
}
}