use crate::{Error, Result};
use core::{
cell::UnsafeCell,
cmp::min,
marker::PhantomData,
mem::{forget, transmute, MaybeUninit},
ops::{Deref, DerefMut},
ptr::NonNull,
slice::from_raw_parts,
slice::from_raw_parts_mut,
};
use cortex_m::interrupt::free;
pub use generic_array::typenum::consts;
use generic_array::{ArrayLength, GenericArray};
pub struct BBBuffer<N: ArrayLength<u8>>(
#[doc(hidden)] pub ConstBBBuffer<GenericArray<u8, N>>,
);
unsafe impl<A> Sync for ConstBBBuffer<A> {}
impl<'a, N> BBBuffer<N>
where
N: ArrayLength<u8>,
{
pub fn try_split(&'a self) -> Result<(Producer<'a, N>, Consumer<'a, N>)> {
free(|_cs| {
if self.0.already_split {
return Err(Error::AlreadySplit);
} else {
unsafe {
let mu_ptr = self.0.buf.get();
(*mu_ptr).as_mut_ptr().write_bytes(0u8, 1);
let nn1 = NonNull::new_unchecked(self as *const _ as *mut _);
let nn2 = NonNull::new_unchecked(self as *const _ as *mut _);
Ok((
Producer {
bbq: nn1,
pd: PhantomData,
},
Consumer {
bbq: nn2,
pd: PhantomData,
},
))
}
}
})
}
}
pub struct ConstBBBuffer<A> {
buf: UnsafeCell<MaybeUninit<A>>,
write: usize,
read: usize,
last: usize,
reserve: usize,
read_in_progress: bool,
already_split: bool,
}
impl<A> ConstBBBuffer<A> {
pub const fn new() -> Self {
Self {
buf: UnsafeCell::new(MaybeUninit::uninit()),
write: 0,
read: 0,
last: 0,
reserve: 0,
read_in_progress: false,
already_split: false,
}
}
}
pub struct Producer<'a, N>
where
N: ArrayLength<u8>,
{
bbq: NonNull<BBBuffer<N>>,
pd: PhantomData<&'a ()>,
}
unsafe impl<'a, N> Send for Producer<'a, N> where N: ArrayLength<u8> {}
impl<'a, N> Producer<'a, N>
where
N: ArrayLength<u8>,
{
pub fn grant_exact(&mut self, sz: usize) -> Result<GrantW<'a, N>> {
free(|_cs| {
let inner = unsafe { &mut self.bbq.as_mut().0 };
let write = inner.write;
if inner.reserve != write {
return Err(Error::GrantInProgress);
}
let read = inner.read;
let max = N::to_usize();
let already_inverted = write < read;
let start = if already_inverted {
if (write + sz) < read {
write
} else {
return Err(Error::InsufficientSize);
}
} else {
if write + sz <= max {
write
} else {
if sz < read {
0
} else {
return Err(Error::InsufficientSize);
}
}
};
inner.reserve = start + sz;
let start_of_buf_ptr = inner.buf.get().cast::<u8>();
let grant_slice =
unsafe { from_raw_parts_mut(start_of_buf_ptr.offset(start as isize), sz) };
Ok(GrantW {
buf: grant_slice,
bbq: self.bbq,
})
})
}
pub fn grant_max_remaining(&mut self, mut sz: usize) -> Result<GrantW<'a, N>> {
free(|_cs| {
let inner = unsafe { &mut self.bbq.as_mut().0 };
let write = inner.write;
if inner.reserve != write {
return Err(Error::GrantInProgress);
}
let read = inner.read;
let max = N::to_usize();
let already_inverted = write < read;
let start = if already_inverted {
let remain = read - write - 1;
if remain != 0 {
sz = min(remain, sz);
write
} else {
return Err(Error::InsufficientSize);
}
} else {
if write != max {
sz = min(max - write, sz);
write
} else {
if read > 1 {
sz = min(read - 1, sz);
0
} else {
return Err(Error::InsufficientSize);
}
}
};
inner.reserve = start + sz;
let start_of_buf_ptr = inner.buf.get().cast::<u8>();
let grant_slice =
unsafe { from_raw_parts_mut(start_of_buf_ptr.offset(start as isize), sz) };
Ok(GrantW {
buf: grant_slice,
bbq: self.bbq,
})
})
}
}
pub struct Consumer<'a, N>
where
N: ArrayLength<u8>,
{
bbq: NonNull<BBBuffer<N>>,
pd: PhantomData<&'a ()>,
}
unsafe impl<'a, N> Send for Consumer<'a, N> where N: ArrayLength<u8> {}
impl<'a, N> Consumer<'a, N>
where
N: ArrayLength<u8>,
{
pub fn read(&mut self) -> Result<GrantR<'a, N>> {
free(|_cs| {
let inner = unsafe { &mut self.bbq.as_mut().0 };
if inner.read_in_progress {
return Err(Error::GrantInProgress);
}
let write = inner.write;
let last = inner.last;
let mut read = inner.read;
if (read == last) && (write < read) {
read = 0;
inner.read = 0;
}
let sz = if write < read {
last
} else {
write
} - read;
if sz == 0 {
return Err(Error::InsufficientSize);
}
inner.read_in_progress = true;
let start_of_buf_ptr = inner.buf.get().cast::<u8>();
let grant_slice = unsafe { from_raw_parts(start_of_buf_ptr.offset(read as isize), sz) };
Ok(GrantR {
buf: grant_slice,
bbq: self.bbq,
})
})
}
}
impl<N> BBBuffer<N>
where
N: ArrayLength<u8>,
{
pub fn capacity(&self) -> usize {
N::to_usize()
}
}
impl<N> BBBuffer<N>
where
N: ArrayLength<u8>,
{
pub fn new() -> Self {
Self(ConstBBBuffer::new())
}
}
#[derive(Debug, PartialEq)]
pub struct GrantW<'a, N>
where
N: ArrayLength<u8>,
{
buf: &'a mut [u8],
bbq: NonNull<BBBuffer<N>>,
}
#[derive(Debug, PartialEq)]
pub struct GrantR<'a, N>
where
N: ArrayLength<u8>,
{
buf: &'a [u8],
bbq: NonNull<BBBuffer<N>>,
}
impl<'a, N> GrantW<'a, N>
where
N: ArrayLength<u8>,
{
pub fn commit(mut self, used: usize) {
self.commit_inner(used);
forget(self);
}
pub fn buf(&mut self) -> &mut [u8] {
self.buf
}
pub unsafe fn as_static_mut_buf(&mut self) -> &'static mut [u8] {
transmute::<&mut [u8], &'static mut [u8]>(self.buf)
}
#[inline(always)]
fn commit_inner(&mut self, used: usize) {
free(|_cs| {
let inner = unsafe { &mut self.bbq.as_mut().0 };
let len = self.buf.len();
let used = min(len, used);
let write = inner.write;
inner.reserve -= len - used;
let max = N::to_usize();
let last = inner.last;
let new_write = inner.reserve;
if (new_write < write) && (write != max) {
inner.last = write;
} else if new_write > last {
inner.last = max;
}
inner.write = new_write;
})
}
}
impl<'a, N> GrantR<'a, N>
where
N: ArrayLength<u8>,
{
pub fn release(mut self, used: usize) {
self.release_inner(used);
forget(self);
}
pub fn buf(&self) -> &[u8] {
self.buf
}
pub unsafe fn as_static_buf(&self) -> &'static [u8] {
transmute::<&[u8], &'static [u8]>(self.buf)
}
#[inline(always)]
fn release_inner(&mut self, used: usize) {
free(|_cs| {
let inner = unsafe { &mut self.bbq.as_mut().0 };
let used = min(self.buf.len(), used);
inner.read += used;
inner.read_in_progress = false;
})
}
}
impl<'a, N> Drop for GrantW<'a, N>
where
N: ArrayLength<u8>,
{
fn drop(&mut self) {
self.commit_inner(0)
}
}
impl<'a, N> Drop for GrantR<'a, N>
where
N: ArrayLength<u8>,
{
fn drop(&mut self) {
self.release_inner(0)
}
}
impl<'a, N> Deref for GrantW<'a, N>
where
N: ArrayLength<u8>,
{
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.buf
}
}
impl<'a, N> DerefMut for GrantW<'a, N>
where
N: ArrayLength<u8>,
{
fn deref_mut(&mut self) -> &mut [u8] {
self.buf
}
}
impl<'a, N> Deref for GrantR<'a, N>
where
N: ArrayLength<u8>,
{
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.buf
}
}