use core::fmt;
use super::{
Buffer, Error, ErrorKind, MarkerBack, MarkerFront, StaticBuffer, Tracking,
};
use core::cell::{RefCell, UnsafeCell};
use core::mem::{size_of, uninitialized};
pub(crate) struct MarkerStacks<TrackingT>
where
TrackingT: Tracking,
{
pub(crate) data: TrackingT,
pub(crate) front: usize,
pub(crate) back: usize,
}
impl<TrackingT> fmt::Debug for MarkerStacks<TrackingT>
where
TrackingT: Tracking,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "MarkerStacks {{ ... }}")
}
}
pub struct Scratchpad<BufferT, TrackingT>
where
BufferT: Buffer,
TrackingT: Tracking,
{
pub(crate) buffer: UnsafeCell<BufferT>,
pub(crate) markers: RefCell<MarkerStacks<TrackingT>>,
}
impl<BufferT, TrackingT> Scratchpad<BufferT, TrackingT>
where
BufferT: Buffer,
TrackingT: Tracking,
{
#[inline(always)]
#[cfg(feature = "unstable")]
pub const fn new(buffer: BufferT, tracking: TrackingT) -> Self {
Scratchpad {
buffer: UnsafeCell::new(buffer),
markers: RefCell::new(MarkerStacks {
data: tracking,
front: 0,
back: ::core::usize::MAX, }),
}
}
#[inline(always)]
#[cfg(not(feature = "unstable"))]
pub fn new(buffer: BufferT, tracking: TrackingT) -> Self {
Scratchpad {
buffer: UnsafeCell::new(buffer),
markers: RefCell::new(MarkerStacks {
back: tracking.capacity(),
data: tracking,
front: 0,
}),
}
}
}
impl<BufferT, TrackingT> Scratchpad<BufferT, TrackingT>
where
BufferT: StaticBuffer,
TrackingT: Tracking + StaticBuffer,
{
#[inline(always)]
pub fn static_new() -> Self {
Scratchpad {
buffer: unsafe { uninitialized() },
markers: RefCell::new(MarkerStacks {
data: unsafe { uninitialized() },
front: 0,
back: size_of::<TrackingT>() / size_of::<usize>(),
}),
}
}
}
impl<BufferT, TrackingT> Scratchpad<BufferT, TrackingT>
where
BufferT: Buffer,
TrackingT: Tracking,
{
pub fn mark_front<'scratchpad>(
&'scratchpad self,
) -> Result<MarkerFront<'scratchpad, BufferT, TrackingT>, Error<()>> {
let mut markers = self.markers.borrow_mut();
#[cfg(feature = "unstable")]
{
if markers.back == ::core::usize::MAX {
markers.back = markers.data.capacity();
}
}
let index = markers.front;
if index == markers.back {
return Err(Error::new(ErrorKind::MarkerLimit, ()));
}
let buffer_offset = if index == 0 {
0
} else {
markers.data.get(index - 1)
};
markers.data.set(index, buffer_offset);
markers.front = index + 1;
Ok(MarkerFront {
scratchpad: self,
index,
})
}
pub fn mark_back<'scratchpad>(
&'scratchpad self,
) -> Result<MarkerBack<'scratchpad, BufferT, TrackingT>, Error<()>> {
let mut markers = self.markers.borrow_mut();
#[cfg(feature = "unstable")]
{
if markers.back == ::core::usize::MAX {
markers.back = markers.data.capacity();
}
}
let mut index = markers.back;
if index == markers.front {
return Err(Error::new(ErrorKind::MarkerLimit, ()));
}
let buffer_offset = if index == markers.data.capacity() {
unsafe { (*self.buffer.get()).as_bytes().len() }
} else {
markers.data.get(index)
};
index -= 1;
markers.data.set(index, buffer_offset);
markers.back = index;
Ok(MarkerBack {
scratchpad: self,
index,
})
}
}
impl<BufferT, TrackingT> fmt::Debug for Scratchpad<BufferT, TrackingT>
where
BufferT: Buffer,
TrackingT: Tracking,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Scratchpad {{ buffer.len = {}, markers: {:?} }}",
unsafe { &*self.buffer.get() }.as_bytes().len(),
self.markers.borrow(),
)
}
}