use core::cell::Cell;
pub struct RxQueue<const N: usize> {
buf: [Cell<u8>; N],
head: Cell<u16>,
tail: Cell<u16>,
dropped: Cell<u8>,
}
impl<const N: usize> RxQueue<N> {
const VALID: () = assert!(
N.is_power_of_two() && N <= 256,
"RxQueue capacity must be a power of two, at most 256"
);
pub const fn new() -> Self {
let () = Self::VALID;
RxQueue {
buf: [const { Cell::new(0) }; N],
head: Cell::new(0),
tail: Cell::new(0),
dropped: Cell::new(0),
}
}
pub fn len(&self) -> usize {
self.head.get().wrapping_sub(self.tail.get()) as usize
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn push(&self, byte: u8) -> bool {
if self.len() == N {
self.dropped.set(self.dropped.get().saturating_add(1));
return false;
}
let head = self.head.get();
self.buf[(head as usize) & (N - 1)].set(byte);
self.head.set(head.wrapping_add(1));
true
}
pub fn pop(&self) -> Option<u8> {
if self.is_empty() {
return None;
}
let tail = self.tail.get();
let byte = self.buf[(tail as usize) & (N - 1)].get();
self.tail.set(tail.wrapping_add(1));
Some(byte)
}
pub fn dropped(&self) -> u8 {
self.dropped.get()
}
}