use std::cell::RefCell;
use std::rc::Rc;
use dope_core::driver::ProvidedRingOps;
pub struct ProvidedRing {
inner: Rc<RefCell<Inner>>,
}
struct Inner {
buf_len: u32,
bufs: Vec<Box<[u8]>>,
free: Vec<u16>,
}
impl ProvidedRing {
pub(crate) fn new(entries: u16, buf_len: u32) -> Self {
let n = entries as usize;
let bufs = (0..n)
.map(|_| vec![0u8; buf_len as usize].into_boxed_slice())
.collect();
let free = (0..entries).rev().collect();
Self {
inner: Rc::new(RefCell::new(Inner {
buf_len,
bufs,
free,
})),
}
}
pub(crate) fn group(&self) -> (u16, u32) {
let inner = self.inner.borrow();
(Self::BGID, inner.buf_len)
}
const BGID: u16 = 0;
pub(crate) fn make_buf(&self, bid: u16, len: usize) -> ProvidedBuf {
let (ptr, _cap) = self.ptr_len(bid);
ProvidedBuf {
bid,
ptr,
len,
ring: self.inner.clone(),
released: false,
}
}
pub(crate) fn pop_free(&self) -> Option<u16> {
self.inner.borrow_mut().free.pop()
}
}
impl ProvidedRingOps for ProvidedRing {
fn ptr_len(&self, bid: u16) -> (*mut u8, usize) {
let inner = self.inner.borrow();
let buf = &inner.bufs[bid as usize];
(buf.as_ptr() as *mut u8, buf.len())
}
fn defer(&mut self, bid: u16) {
self.inner.borrow_mut().free.push(bid);
}
}
pub struct ProvidedBuf {
bid: u16,
ptr: *mut u8,
len: usize,
ring: Rc<RefCell<Inner>>,
released: bool,
}
impl ProvidedBuf {
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn as_slice(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
}
#[allow(clippy::should_implement_trait)]
pub fn as_mut(&mut self) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(self.ptr, self.len) }
}
}
impl AsRef<[u8]> for ProvidedBuf {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl Drop for ProvidedBuf {
fn drop(&mut self) {
if self.released {
return;
}
self.ring.borrow_mut().free.push(self.bid);
}
}