pub use generic_array::typenum::consts;
use core::{
cell::UnsafeCell,
marker::PhantomData,
mem::{size_of, MaybeUninit, forget},
ops::{Deref, DerefMut},
ptr::NonNull,
slice::from_raw_parts,
slice::from_raw_parts_mut,
};
use generic_array::{ArrayLength, GenericArray};
use cortex_m::interrupt::free;
use crate::{Error, Result};
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: size_of::<A>(),
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(&mut self, sz: usize) -> Result<GrantW<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 c = unsafe { (*inner.buf.get()).as_mut_ptr().cast::<u8>() };
let d =
unsafe { from_raw_parts_mut(c.offset(start as isize), sz) };
Ok(GrantW { buf: d, 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<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 c = unsafe { (*inner.buf.get()).as_ptr().cast::<u8>() };
let d = unsafe { from_raw_parts(c.offset(read as isize), sz) };
Ok(GrantR { buf: d, 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);
}
#[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();
assert!(len >= used);
let write = inner.write;
inner.reserve -= len - used;
let max = N::to_usize();
let last = inner.last;
if (inner.reserve < write) && (write != max) {
inner.last = write;
} else if write > last {
inner.last = max;
}
inner.write = inner.reserve;
})
}
}
impl<'a, N> GrantR<'a, N>
where
N: ArrayLength<u8>
{
pub fn release(mut self, used: usize) {
self.release_inner(used);
forget(self);
}
#[inline(always)]
fn release_inner(&mut self, used: usize) {
free(|_cs| {
let inner = unsafe { &mut self.bbq.as_mut().0 };
assert!(used <= self.buf.len());
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
}
}