use core::fmt;
use core::ptr;
use super::{
Buffer, Error, ErrorKind, MarkerBack, MarkerFront, StaticBuffer, Tracking,
};
use core::cell::{Cell, UnsafeCell};
use core::mem::size_of;
#[cfg(not(any(stable_maybe_uninit, feature = "unstable")))]
use core::mem::uninitialized;
#[cfg(any(stable_maybe_uninit, feature = "unstable"))]
use core::mem::MaybeUninit;
use core::ops::{Deref, DerefMut};
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 {{ ... }}")
}
}
type BorrowFlag = usize;
const UNUSED: BorrowFlag = 0usize;
const WRITING: BorrowFlag = !0usize;
pub(crate) struct Ref<'a, T>
where
T: 'a,
{
cell: &'a RefCell<T>,
}
impl<'a, T> Drop for Ref<'a, T> {
#[inline]
fn drop(&mut self) {
let borrow = self.cell.borrow.get();
debug_assert_ne!(borrow, UNUSED);
debug_assert_ne!(borrow, WRITING);
self.cell.borrow.set(borrow - 1);
}
}
impl<'a, T> Deref for Ref<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { &*self.cell.value.get() }
}
}
impl<'a, T> fmt::Debug for Ref<'a, T>
where
T: fmt::Debug,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
pub(crate) struct RefMut<'a, T>
where
T: 'a,
{
cell: &'a RefCell<T>,
}
impl<'a, T> Drop for RefMut<'a, T> {
#[inline]
fn drop(&mut self) {
debug_assert_eq!(self.cell.borrow.get(), WRITING);
self.cell.borrow.set(UNUSED);
}
}
impl<'a, T> Deref for RefMut<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { &*self.cell.value.get() }
}
}
impl<'a, T> DerefMut for RefMut<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.cell.value.get() }
}
}
impl<'a, T> fmt::Debug for RefMut<'a, T>
where
T: fmt::Debug,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
pub(crate) struct RefCell<T> {
borrow: Cell<BorrowFlag>,
value: UnsafeCell<T>,
}
impl<T> RefCell<T> {
#[inline]
#[cfg(feature = "unstable")]
pub(crate) const fn new(value: T) -> Self {
RefCell {
borrow: Cell::new(UNUSED),
value: UnsafeCell::new(value),
}
}
#[inline]
#[cfg(not(feature = "unstable"))]
pub(crate) fn new(value: T) -> Self {
RefCell {
borrow: Cell::new(UNUSED),
value: UnsafeCell::new(value),
}
}
#[inline]
pub(crate) unsafe fn new_uninitialized_value_in_place(dst: *mut Self) {
ptr::write(&mut (*dst).borrow, Cell::new(UNUSED));
}
#[inline]
pub(crate) fn borrow(&self) -> Ref<T> {
let borrow = self.borrow.get();
assert_ne!(borrow, WRITING);
self.borrow.set(borrow + 1);
Ref { cell: self }
}
#[inline]
pub(crate) fn borrow_mut(&self) -> RefMut<T> {
assert_eq!(self.borrow.get(), UNUSED);
self.borrow.set(WRITING);
RefMut { cell: self }
}
#[inline]
pub(crate) fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.value.get() }
}
}
impl<T> fmt::Debug for RefCell<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RefCell")
.field("value", unsafe { &*self.value.get() })
.finish()
}
}
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 {
#[cfg(any(stable_maybe_uninit, feature = "unstable"))]
#[cfg_attr(
feature = "cargo-clippy",
allow(clippy::uninit_assumed_init)
)]
return Scratchpad {
buffer: unsafe { MaybeUninit::uninit().assume_init() },
markers: RefCell::new(MarkerStacks {
data: unsafe { MaybeUninit::uninit().assume_init() },
front: 0,
back: size_of::<TrackingT>() / size_of::<usize>(),
}),
};
#[cfg(not(any(stable_maybe_uninit, feature = "unstable")))]
return Scratchpad {
buffer: unsafe { uninitialized() },
markers: RefCell::new(MarkerStacks {
data: unsafe { uninitialized() },
front: 0,
back: size_of::<TrackingT>() / size_of::<usize>(),
}),
};
}
#[inline]
pub unsafe fn static_new_in_place(dst: *mut Self) {
RefCell::new_uninitialized_value_in_place(&mut (*dst).markers);
let markers = (*dst).markers.get_mut();
ptr::write(&mut markers.front, 0);
ptr::write(&mut markers.back, markers.data.capacity());
}
}
impl<BufferT, TrackingT> Scratchpad<BufferT, TrackingT>
where
BufferT: Buffer,
TrackingT: Tracking,
{
pub fn mark_front(
&self,
) -> Result<MarkerFront<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(
&self,
) -> Result<MarkerBack<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(),
)
}
}