use std::collections::VecDeque;
use crate::locking::RawMutex;
use lock_api::RawMutex as RawMutexTrait;
pub struct DataBuffer<T, M = RawMutex> {
data: lock_api::Mutex<M, VecDeque<T>>,
capacity: usize,
preallocated: bool,
}
impl<T, M> DataBuffer<T, M>
where
M: RawMutexTrait,
{
pub const fn bounded(capacity: usize) -> Self {
assert!(capacity > 0, "data buffer capacity MUST be > 0");
Self {
data: lock_api::Mutex::const_new(M::INIT, VecDeque::new()),
capacity,
preallocated: false,
}
}
pub fn bounded_prealloc(capacity: usize) -> Self {
assert!(capacity > 0, "data buffer capacity MUST be > 0");
Self {
data: lock_api::Mutex::const_new(M::INIT, VecDeque::with_capacity(capacity)),
capacity,
preallocated: true,
}
}
pub fn try_push(&self, value: T) -> Option<T> {
let mut buf = self.data.lock();
if buf.len() >= self.capacity {
return Some(value);
}
buf.push_back(value);
None
}
pub fn force_push(&self, value: T) -> bool {
let mut buf = self.data.lock();
let mut res = true;
while buf.len() >= self.capacity {
buf.pop_front();
res = false;
}
buf.push_back(value);
res
}
pub fn len(&self) -> usize {
self.data.lock().len()
}
pub fn is_empty(&self) -> bool {
self.data.lock().is_empty()
}
pub fn take(&self) -> VecDeque<T> {
std::mem::replace(
&mut *self.data.lock(),
if self.preallocated {
VecDeque::with_capacity(self.capacity)
} else {
VecDeque::new()
},
)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_data_buffer() {
let buf: DataBuffer<_> = DataBuffer::bounded(3);
assert_eq!(buf.len(), 0);
buf.try_push(1);
assert_eq!(buf.len(), 1);
buf.try_push(2);
assert_eq!(buf.len(), 2);
buf.try_push(3);
assert_eq!(buf.len(), 3);
buf.try_push(4);
assert_eq!(buf.len(), 3);
assert_eq!(buf.take(), vec![1, 2, 3]);
assert!(buf.is_empty());
}
#[test]
fn test_data_buffer_other_mutex() {
let buf: DataBuffer<i32, parking_lot_rt::RawMutex> = DataBuffer::bounded(3);
assert_eq!(buf.len(), 0);
}
}