#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(all(feature = "unstable", not(feature = "std")), feature(alloc))]
#![cfg_attr(feature = "unstable", feature(const_fn))]
#[cfg(all(feature = "unstable", not(feature = "std")))]
extern crate alloc;
#[cfg(feature = "std")]
extern crate core;
#[cfg(test)]
extern crate arrayvec;
use core::fmt;
use core::ptr;
use core::slice;
use core::cell::{RefCell, UnsafeCell};
use core::marker::PhantomData;
use core::mem::{align_of, forget, transmute, uninitialized};
use core::ops::{Deref, DerefMut};
#[cfg(feature = "std")]
use std::boxed::Box;
#[cfg(feature = "std")]
use std::vec::Vec;
#[cfg(all(feature = "unstable", not(feature = "std")))]
use alloc::boxed::Box;
#[cfg(all(feature = "unstable", not(feature = "std")))]
use alloc::vec::Vec;
pub use core::mem::size_of;
#[macro_export]
macro_rules! array_len_for_bytes {
($element:ty, $bytes:expr) => {
($bytes + $crate::size_of::<$element>() - 1)
/ $crate::size_of::<$element>()
};
($element:ty, $bytes:expr,) => {
array_len_for_bytes!($element, $bytes)
};
}
#[macro_export]
macro_rules! array_type_for_bytes {
($element:ty, $bytes:expr) => {
[$element; array_len_for_bytes!($element, $bytes)]
};
($element:ty, $bytes:expr,) => {
array_type_for_bytes!($element, $bytes)
};
}
#[macro_export]
macro_rules! array_len_for_markers {
($element:ty, $marker_count:expr) => {
array_len_for_bytes!(
$element,
$marker_count * $crate::size_of::<usize>(),
)
};
($element:ty, $marker_count:expr,) => {
array_len_for_markers!($element, $marker_count)
};
}
#[macro_export]
macro_rules! array_type_for_markers {
($element:ty, $marker_count:expr) => {
[$element; array_len_for_markers!($element, $marker_count)]
};
($element:ty, $marker_count:expr,) => {
array_type_for_markers!($element, $marker_count)
};
}
#[macro_export]
macro_rules! cache_aligned_zeroed {
() => {
$crate::CacheAligned([0; $crate::CACHE_ALIGNMENT])
};
}
#[macro_export]
macro_rules! cache_aligned_zeroed_for_bytes {
($bytes:expr) => {
[cache_aligned_zeroed!();
array_len_for_bytes!($crate::CacheAligned, $bytes)]
};
($bytes:expr,) => {
cache_aligned_zeroed_for_bytes!($bytes)
};
}
#[macro_export]
macro_rules! cache_aligned_zeroed_for_markers {
($marker_count:expr) => {
[cache_aligned_zeroed!();
array_len_for_markers!($crate::CacheAligned, $marker_count)]
};
($marker_count:expr,) => {
cache_aligned_zeroed_for_markers!($marker_count)
};
}
pub const CACHE_ALIGNMENT: usize = 64;
#[derive(Debug, PartialEq)]
pub enum Error {
MarkerLimit,
MarkerLocked,
InsufficientMemory,
Overflow,
}
impl fmt::Display for Error {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Error::MarkerLimit => {
write!(f, "scratchpad marker limit reached")
}
&Error::MarkerLocked => {
write!(f, "marker is not the most recent active marker")
}
&Error::InsufficientMemory => {
write!(f, "insufficient allocation buffer space")
}
&Error::Overflow => write!(f, "integer overflow"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {
fn description(&self) -> &str {
match self {
&Error::MarkerLimit => "scratchpad marker limit reached",
&Error::MarkerLocked => {
"marker is not the most recent active marker"
}
&Error::InsufficientMemory => {
"insufficient allocation buffer space"
}
&Error::Overflow => "integer overflow",
}
}
}
#[derive(Clone, Copy)]
#[repr(align(64))]
pub struct CacheAligned(pub [u8; CACHE_ALIGNMENT]);
impl fmt::Debug for CacheAligned {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "CacheAligned {{ ... }}")
}
}
pub unsafe trait ByteData: Sized {}
unsafe impl ByteData for u8 {}
unsafe impl ByteData for u16 {}
unsafe impl ByteData for u32 {}
unsafe impl ByteData for u64 {}
#[cfg(feature = "nightly")]
unsafe impl ByteData for u128 {}
unsafe impl ByteData for usize {}
unsafe impl ByteData for i8 {}
unsafe impl ByteData for i16 {}
unsafe impl ByteData for i32 {}
unsafe impl ByteData for i64 {}
#[cfg(feature = "nightly")]
unsafe impl ByteData for i128 {}
unsafe impl ByteData for isize {}
unsafe impl ByteData for CacheAligned {}
pub trait Buffer {
fn as_bytes(&self) -> &[u8];
fn as_bytes_mut(&mut self) -> &mut [u8];
}
pub unsafe trait StaticBuffer: Buffer {}
impl<'a, T> Buffer for &'a mut [T]
where
T: ByteData,
{
#[inline]
fn as_bytes(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(
self.as_ptr() as *const u8,
self.len() * size_of::<T>(),
)
}
}
#[inline]
fn as_bytes_mut(&mut self) -> &mut [u8] {
unsafe {
slice::from_raw_parts_mut(
self.as_mut_ptr() as *mut u8,
self.len() * size_of::<T>(),
)
}
}
}
#[cfg(any(feature = "std", feature = "unstable"))]
impl<T> Buffer for Box<[T]>
where
T: ByteData,
{
#[inline]
fn as_bytes(&self) -> &[u8] {
let data = self.as_ref();
unsafe {
slice::from_raw_parts(
data.as_ptr() as *const u8,
data.len() * size_of::<T>(),
)
}
}
#[inline]
fn as_bytes_mut(&mut self) -> &mut [u8] {
let data = self.as_mut();
unsafe {
slice::from_raw_parts_mut(
data.as_mut_ptr() as *mut u8,
data.len() * size_of::<T>(),
)
}
}
}
macro_rules! generate_buffer_impl {
($size:expr) => {
impl<T> Buffer for [T; $size]
where
T: ByteData,
{
#[inline]
fn as_bytes(&self) -> &[u8] {
let data = &self[..];
unsafe { slice::from_raw_parts (
data.as_ptr() as *const u8,
data.len() * size_of::<T>(),
) }
}
#[inline]
fn as_bytes_mut(&mut self) -> &mut [u8] {
let data = &mut self[..];
unsafe { slice::from_raw_parts_mut (
data.as_mut_ptr() as *mut u8,
data.len() * size_of::<T>(),
) }
}
}
unsafe impl<T> StaticBuffer for [T; $size]
where
T: ByteData,
{}
};
($size:expr, $($other:tt)*) => {
generate_buffer_impl!($size);
generate_buffer_impl!($($other)*);
};
() => {};
}
generate_buffer_impl!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
generate_buffer_impl!(11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
generate_buffer_impl!(21, 22, 23, 24, 25, 26, 27, 28, 29, 30);
generate_buffer_impl!(31, 32, 33, 34, 35, 36, 37, 38, 39, 40);
generate_buffer_impl!(41, 42, 43, 44, 45, 46, 47, 48, 49, 50);
generate_buffer_impl!(51, 52, 53, 54, 55, 56, 57, 58, 59, 60);
generate_buffer_impl!(61, 62, 63, 64);
generate_buffer_impl!(0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000);
generate_buffer_impl!(0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000);
generate_buffer_impl!(0x100000, 0x200000, 0x400000, 0x800000, 0x1000000);
generate_buffer_impl!(0x2000000, 0x4000000, 0x8000000, 0x10000000);
generate_buffer_impl!(0x20000000, 0x40000000);
pub trait Tracking: Sized {
fn capacity(&self) -> usize;
fn set(&mut self, index: usize, value: usize);
fn get(&self, index: usize) -> usize;
}
impl<T> Tracking for T
where
T: Buffer,
{
#[inline]
fn capacity(&self) -> usize {
self.as_bytes().len() / size_of::<usize>()
}
#[inline]
fn set(&mut self, index: usize, value: usize) {
let bytes = self.as_bytes_mut();
let contents = unsafe {
slice::from_raw_parts_mut(
bytes.as_mut_ptr() as *mut usize,
bytes.len() / size_of::<usize>(),
)
};
contents[index] = value;
}
#[inline]
fn get(&self, index: usize) -> usize {
let bytes = self.as_bytes();
let contents = unsafe {
slice::from_raw_parts(
bytes.as_ptr() as *const usize,
bytes.len() / size_of::<usize>(),
)
};
contents[index]
}
}
struct MarkerStacks<TrackingT>
where
TrackingT: Tracking,
{
data: TrackingT,
front: usize,
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 Allocation<'marker, T>
where
T: ?Sized,
{
data: *mut T,
_phantom: PhantomData<&'marker ()>,
}
impl<'marker, T> Allocation<'marker, T>
where
T: Sized,
{
pub fn unwrap(self) -> T {
unsafe {
let value = ptr::read(self.data);
forget(self);
value
}
}
}
impl<'marker, T> Deref for Allocation<'marker, T>
where
T: ?Sized,
{
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { &*self.data }
}
}
impl<'marker, T> DerefMut for Allocation<'marker, T>
where
T: ?Sized,
{
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.data }
}
}
impl<'marker, T> Drop for Allocation<'marker, T>
where
T: ?Sized,
{
#[inline]
fn drop(&mut self) {
unsafe { ptr::drop_in_place(self.data) };
}
}
impl<'marker, T> fmt::Debug for Allocation<'marker, T>
where
T: ?Sized + fmt::Debug,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe { write!(f, "Allocation {{ data: {:?} }}", &*self.data) }
}
}
pub trait Marker {
#[inline]
fn allocate<'marker, T>(
&'marker self,
value: T,
) -> Result<Allocation<'marker, T>, Error> {
unsafe {
self.allocate_uninitialized::<T>()
.map(|allocation| {
ptr::write(allocation.data, value);
allocation
})
}
}
#[inline]
fn allocate_default<'marker, T: Default>(
&'marker self,
) -> Result<Allocation<'marker, T>, Error> {
self.allocate(Default::default())
}
#[inline]
unsafe fn allocate_uninitialized<'marker, T>(
&'marker self,
) -> Result<Allocation<'marker, T>, Error> {
let data = self.allocate_memory(align_of::<T>(), size_of::<T>(), 1)?;
Ok(Allocation {
data: data as *mut T,
_phantom: PhantomData,
})
}
#[inline]
fn allocate_array<'marker, T: Clone>(
&'marker self,
len: usize,
value: T,
) -> Result<Allocation<'marker, [T]>, Error> {
unsafe {
self.allocate_array_uninitialized(len)
.map(|allocation| {
let data = &mut *allocation.data;
debug_assert_eq!(data.len(), len);
for element in data.iter_mut() {
ptr::write(element, value.clone());
}
allocation
})
}
}
#[inline]
fn allocate_array_default<'marker, T: Default>(
&'marker self,
len: usize,
) -> Result<Allocation<'marker, [T]>, Error> {
unsafe {
self.allocate_array_uninitialized(len)
.map(|allocation| {
let data = &mut *allocation.data;
debug_assert_eq!(data.len(), len);
for element in data.iter_mut() {
ptr::write(element, Default::default());
}
allocation
})
}
}
#[inline]
fn allocate_array_with<'marker, T, F: FnMut(usize) -> T>(
&'marker self,
len: usize,
mut func: F,
) -> Result<Allocation<'marker, [T]>, Error> {
unsafe {
self.allocate_array_uninitialized(len)
.map(|allocation| {
let data = &mut *allocation.data;
debug_assert_eq!(data.len(), len);
for (index, element) in data.iter_mut().enumerate() {
ptr::write(element, func(index));
}
allocation
})
}
}
#[inline]
unsafe fn allocate_array_uninitialized<'marker, T>(
&'marker self,
len: usize,
) -> Result<Allocation<'marker, [T]>, Error> {
let data =
self.allocate_memory(align_of::<T>(), size_of::<T>(), len)?;
Ok(Allocation {
data: slice::from_raw_parts_mut(data as *mut T, len),
_phantom: PhantomData,
})
}
fn concat<'marker, IntoIteratorT, IteratorT, StrT>(
&'marker self,
strings: IntoIteratorT,
) -> Result<Allocation<'marker, str>, Error>
where
IntoIteratorT: IntoIterator<Item = StrT, IntoIter = IteratorT>,
IteratorT: Iterator<Item = StrT> + Clone,
StrT: AsRef<str>,
{
let iter = strings.into_iter();
let size = iter.clone().fold(0usize, |sum, item| {
sum + item.as_ref().as_bytes().len()
});
let mut result =
unsafe { self.allocate_array_uninitialized::<u8>(size)? };
let mut start = 0usize;
for item in iter {
let bytes = item.as_ref().as_bytes();
let end = start + bytes.len();
result[start..end].copy_from_slice(&bytes[..]);
start = end;
}
unsafe { Ok(transmute(result)) }
}
#[doc(hidden)]
unsafe fn allocate_memory(
&self,
alignment: usize,
size: usize,
len: usize,
) -> Result<*mut u8, Error>;
}
#[derive(Debug)]
pub struct MarkerFront<'scratchpad, BufferT, TrackingT>
where
BufferT: 'scratchpad + Buffer,
TrackingT: 'scratchpad + Tracking,
{
scratchpad: &'scratchpad Scratchpad<BufferT, TrackingT>,
index: usize,
}
impl<'scratchpad, BufferT, TrackingT> Marker
for MarkerFront<'scratchpad, BufferT, TrackingT>
where
BufferT: 'scratchpad + Buffer,
TrackingT: 'scratchpad + Tracking,
{
unsafe fn allocate_memory(
&self,
alignment: usize,
size: usize,
len: usize,
) -> Result<*mut u8, Error> {
let mut markers = self.scratchpad.markers.borrow_mut();
if markers.front != self.index + 1 {
return Err(Error::MarkerLocked);
}
let alignment_mask = alignment - 1;
debug_assert_eq!(alignment & alignment_mask, 0);
let size = size.checked_add(alignment_mask)
.ok_or(Error::Overflow)? & !alignment_mask;
let size = size * len;
let buffer = (*self.scratchpad.buffer.get()).as_bytes_mut();
let buffer_end_offset = if markers.back == markers.data.capacity() {
buffer.len()
} else {
markers.data.get(markers.back)
};
let buffer_start = buffer.as_mut_ptr() as usize;
let buffer_end = buffer_start + buffer_end_offset;
let start = buffer_start + markers.data.get(self.index);
debug_assert!(start <= buffer_end);
let start = start
.checked_add(alignment_mask)
.ok_or(Error::Overflow)? & !alignment_mask;
let end = start.checked_add(size).ok_or(Error::Overflow)?;
if end > buffer_end {
return Err(Error::InsufficientMemory);
}
markers.data.set(self.index, end - buffer_start);
Ok(start as *mut u8)
}
}
impl<'scratchpad, BufferT, TrackingT>
MarkerFront<'scratchpad, BufferT, TrackingT>
where
BufferT: 'scratchpad + Buffer,
TrackingT: 'scratchpad + Tracking,
{
#[inline(always)]
pub fn allocate<'marker, T>(
&'marker self,
value: T,
) -> Result<Allocation<'marker, T>, Error> {
Marker::allocate(self, value)
}
#[inline(always)]
pub fn allocate_default<'marker, T: Default>(
&'marker self,
) -> Result<Allocation<'marker, T>, Error> {
Marker::allocate_default(self)
}
#[inline(always)]
pub unsafe fn allocate_uninitialized<'marker, T>(
&'marker self,
) -> Result<Allocation<'marker, T>, Error> {
Marker::allocate_uninitialized(self)
}
#[inline(always)]
pub fn allocate_array<'marker, T: Clone>(
&'marker self,
len: usize,
value: T,
) -> Result<Allocation<'marker, [T]>, Error> {
Marker::allocate_array(self, len, value)
}
#[inline(always)]
pub fn allocate_array_default<'marker, T: Default>(
&'marker self,
len: usize,
) -> Result<Allocation<'marker, [T]>, Error> {
Marker::allocate_array_default(self, len)
}
#[inline(always)]
pub fn allocate_array_with<'marker, T, F: FnMut(usize) -> T>(
&'marker self,
len: usize,
func: F,
) -> Result<Allocation<'marker, [T]>, Error> {
Marker::allocate_array_with(self, len, func)
}
#[inline(always)]
pub unsafe fn allocate_array_uninitialized<'marker, T>(
&'marker self,
len: usize,
) -> Result<Allocation<'marker, [T]>, Error> {
Marker::allocate_array_uninitialized(self, len)
}
#[inline(always)]
pub fn concat<'marker, IntoIteratorT, IteratorT, StrT>(
&'marker self,
strings: IntoIteratorT,
) -> Result<Allocation<'marker, str>, Error>
where
IntoIteratorT: IntoIterator<Item = StrT, IntoIter = IteratorT>,
IteratorT: Iterator<Item = StrT> + Clone,
StrT: AsRef<str>,
{
Marker::concat(self, strings)
}
}
impl<'scratchpad, BufferT, TrackingT> Drop
for MarkerFront<'scratchpad, BufferT, TrackingT>
where
BufferT: 'scratchpad + Buffer,
TrackingT: 'scratchpad + Tracking,
{
fn drop(&mut self) {
let mut markers = self.scratchpad.markers.borrow_mut();
let mut front = markers.front;
debug_assert!(self.index < front);
let mut last_index = front - 1;
if self.index < last_index {
markers.data.set(self.index, core::usize::MAX);
return;
}
loop {
front = last_index;
if front == 0 {
break;
}
last_index -= 1;
if markers.data.get(last_index) != core::usize::MAX {
break;
}
}
markers.front = front;
}
}
#[derive(Debug)]
pub struct MarkerBack<'scratchpad, BufferT, TrackingT>
where
BufferT: 'scratchpad + Buffer,
TrackingT: 'scratchpad + Tracking,
{
scratchpad: &'scratchpad Scratchpad<BufferT, TrackingT>,
index: usize,
}
impl<'scratchpad, BufferT, TrackingT> Marker
for MarkerBack<'scratchpad, BufferT, TrackingT>
where
BufferT: 'scratchpad + Buffer,
TrackingT: 'scratchpad + Tracking,
{
unsafe fn allocate_memory(
&self,
alignment: usize,
size: usize,
len: usize,
) -> Result<*mut u8, Error> {
let mut markers = self.scratchpad.markers.borrow_mut();
if markers.back != self.index {
return Err(Error::MarkerLocked);
}
let alignment_mask = alignment - 1;
debug_assert_eq!(alignment & alignment_mask, 0);
let size = size.checked_add(alignment_mask)
.ok_or(Error::Overflow)? & !alignment_mask;
let size = size * len;
let buffer = (*self.scratchpad.buffer.get()).as_bytes_mut();
let buffer_start = buffer.as_mut_ptr() as usize;
let buffer_end = buffer_start + markers.data.get(self.index);
let start_min = if markers.front == 0 {
buffer_start
} else {
buffer_start + markers.data.get(markers.front - 1)
};
debug_assert!(start_min <= buffer_end);
let start = buffer_end
.checked_sub(size)
.ok_or(Error::Overflow)? & !alignment_mask;
if start < start_min {
return Err(Error::InsufficientMemory);
}
markers
.data
.set(self.index, start - buffer_start);
Ok(start as *mut u8)
}
}
impl<'scratchpad, BufferT, TrackingT>
MarkerBack<'scratchpad, BufferT, TrackingT>
where
BufferT: 'scratchpad + Buffer,
TrackingT: 'scratchpad + Tracking,
{
#[inline(always)]
pub fn allocate<'marker, T>(
&'marker self,
value: T,
) -> Result<Allocation<'marker, T>, Error> {
Marker::allocate(self, value)
}
#[inline(always)]
pub fn allocate_default<'marker, T: Default>(
&'marker self,
) -> Result<Allocation<'marker, T>, Error> {
Marker::allocate_default(self)
}
#[inline(always)]
pub unsafe fn allocate_uninitialized<'marker, T>(
&'marker self,
) -> Result<Allocation<'marker, T>, Error> {
Marker::allocate_uninitialized(self)
}
#[inline(always)]
pub fn allocate_array<'marker, T: Clone>(
&'marker self,
len: usize,
value: T,
) -> Result<Allocation<'marker, [T]>, Error> {
Marker::allocate_array(self, len, value)
}
#[inline(always)]
pub fn allocate_array_default<'marker, T: Default>(
&'marker self,
len: usize,
) -> Result<Allocation<'marker, [T]>, Error> {
Marker::allocate_array_default(self, len)
}
#[inline(always)]
pub fn allocate_array_with<'marker, T, F: FnMut(usize) -> T>(
&'marker self,
len: usize,
func: F,
) -> Result<Allocation<'marker, [T]>, Error> {
Marker::allocate_array_with(self, len, func)
}
#[inline(always)]
pub unsafe fn allocate_array_uninitialized<'marker, T>(
&'marker self,
len: usize,
) -> Result<Allocation<'marker, [T]>, Error> {
Marker::allocate_array_uninitialized(self, len)
}
#[inline(always)]
pub fn concat<'marker, IntoIteratorT, IteratorT, StrT>(
&'marker self,
strings: IntoIteratorT,
) -> Result<Allocation<'marker, str>, Error>
where
IntoIteratorT: IntoIterator<Item = StrT, IntoIter = IteratorT>,
IteratorT: Iterator<Item = StrT> + Clone,
StrT: AsRef<str>,
{
Marker::concat(self, strings)
}
}
impl<'scratchpad, BufferT, TrackingT> Drop
for MarkerBack<'scratchpad, BufferT, TrackingT>
where
BufferT: 'scratchpad + Buffer,
TrackingT: 'scratchpad + Tracking,
{
fn drop(&mut self) {
let mut markers = self.scratchpad.markers.borrow_mut();
let mut back = markers.back;
debug_assert!(self.index >= back);
if self.index > back {
markers.data.set(self.index, core::usize::MAX);
return;
}
let capacity = markers.data.capacity();
loop {
back += 1;
if back == capacity {
break;
}
if markers.data.get(back) != core::usize::MAX {
break;
}
}
markers.back = back;
}
}
pub struct Scratchpad<BufferT, TrackingT>
where
BufferT: Buffer,
TrackingT: Tracking,
{
buffer: UnsafeCell<BufferT>,
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::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::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(),
)
}
}
#[cfg(any(feature = "std", feature = "unstable"))]
#[inline]
pub unsafe fn uninitialized_boxed_slice<T>(len: usize) -> Box<[T]>
where
T: ByteData,
{
let mut buffer = Vec::with_capacity(len);
buffer.set_len(len);
buffer.into_boxed_slice()
}
#[cfg(any(feature = "std", feature = "unstable"))]
#[inline]
pub unsafe fn uninitialized_boxed_slice_for_bytes<T>(bytes: usize) -> Box<[T]>
where
T: ByteData,
{
uninitialized_boxed_slice(array_len_for_bytes!(T, bytes))
}
#[cfg(any(feature = "std", feature = "unstable"))]
#[inline]
pub unsafe fn uninitialized_boxed_slice_for_markers<T>(
marker_count: usize,
) -> Box<[T]>
where
T: ByteData,
{
uninitialized_boxed_slice(array_len_for_markers!(T, marker_count))
}
#[cfg(test)]
mod tests;