use super::{DstArray, DstBuf, check_fat_pointer, decompose_pointer, list_push_gen};
use crate::{ConstInit, MaybeUninit, MemAligned, PhantomData, Ptr};
#[doc = crate::_tags!(data_structure)]
#[doc = crate::_doc_location!("data/layout/dst")]
pub type DstStackUsize<DST , const CAP: usize> = DstStack<DST, DstArray<usize, CAP>>;
#[doc = crate::_tags!(data_structure)]
#[doc = crate::_doc_location!("data/layout/dst")]
pub struct DstStack<DST: ?Sized, BUF: DstBuf> {
_pd: PhantomData<*const DST>,
next_ofs: usize,
data: BUF,
}
#[doc = crate::_tags!(iterator)]
#[doc = crate::_doc_location!("data/layout/dst")]
#[derive(Debug)]
pub struct DstStackIter<'a, DST: 'a + ?Sized, BUF: 'a + DstBuf>(&'a DstStack<DST, BUF>, usize);
#[doc = crate::_tags!(iterator)]
#[doc = crate::_doc_location!("data/layout/dst")]
#[derive(Debug)]
pub struct DstStackIterMut<'a, DST: 'a + ?Sized, BUF: 'a + DstBuf>(
&'a mut DstStack<DST, BUF>,
usize,
);
impl<DST: ?Sized, BUF: DstBuf> DstStack<DST, BUF> {
#[must_use] #[rustfmt::skip]
pub fn new() -> Self where BUF: Default { Self::with_buffer(BUF::default()) }
#[must_use] #[rustfmt::skip]
pub const fn new_const() -> Self where BUF: ConstInit { Self::with_buffer(BUF::INIT) }
#[must_use] #[rustfmt::skip]
pub const fn with_buffer(buffer: BUF) -> Self {
DstStack { _pd: PhantomData, next_ofs: 0, data: buffer }
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.next_ofs == 0
}
pub fn push<VAL, F: FnOnce(&VAL) -> &DST>(&mut self, v: VAL, f: F) -> Result<(), VAL>
where
(VAL, BUF::Inner): MemAligned,
{
<(VAL, BUF::Inner) as MemAligned>::assert_compatibility();
unsafe {
match self.push_inner(check_fat_pointer(&v, f)) {
Ok(pii) => {
Ptr::write(pii.data.as_mut_ptr() as *mut VAL, v);
Ok(())
}
Err(()) => Err(v),
}
}
}
#[must_use]
pub fn top(&self) -> Option<&DST> {
self.top_raw().map(|x| unsafe { &*x })
}
#[must_use]
pub fn top_mut(&mut self) -> Option<&mut DST> {
self.top_raw_mut().map(|x| unsafe { &mut *x })
}
pub fn pop(&mut self) {
if let Some(ptr) = self.top_raw_mut() {
assert!(self.next_ofs > 0);
let words = unsafe {
let size = size_of_val(&*ptr);
Ptr::drop_in_place(ptr);
BUF::round_to_words(size)
};
self.next_ofs -= words + Self::meta_words();
}
}
#[must_use]
pub const fn iter(&self) -> DstStackIter<'_, DST, BUF> {
DstStackIter(self, self.next_ofs)
}
#[must_use]
pub fn iter_mut(&mut self) -> DstStackIterMut<'_, DST, BUF> {
DstStackIterMut(self, self.next_ofs)
}
}
impl<BUF: DstBuf> DstStack<str, BUF> {
pub fn push_str(&mut self, string: &str) -> Result<(), ()> {
unsafe {
self.push_inner(string).map(|pii| {
Ptr::copy(
string.as_bytes().as_ptr(),
pii.data.as_mut_ptr() as *mut u8,
string.len(),
);
})
}
}
}
impl<BUF: DstBuf, DST: Clone> DstStack<[DST], BUF>
where
(DST, BUF::Inner): MemAligned,
{
pub fn push_cloned(&mut self, slice: &[DST]) -> Result<(), ()> {
<(DST, BUF::Inner) as MemAligned>::assert_compatibility();
self.push_from_iter(slice.iter().cloned())
}
pub fn push_copied(&mut self, slice: &[DST]) -> Result<(), ()>
where
DST: Copy,
{
<(DST, BUF::Inner) as MemAligned>::assert_compatibility();
unsafe {
self.push_inner(slice).map(|pii| {
Ptr::copy(
slice.as_ptr() as *const u8,
pii.data.as_mut_ptr() as *mut u8,
size_of_val(slice),
);
})
}
}
}
impl<BUF: DstBuf, DST> DstStack<[DST], BUF>
where
(DST, BUF::Inner): MemAligned,
{
pub fn push_from_iter(
&mut self,
mut iter: impl ExactSizeIterator<Item = DST>,
) -> Result<(), ()> {
<(DST, BUF::Inner) as MemAligned>::assert_compatibility();
unsafe {
let pii = self.push_inner_raw(iter.len() * size_of::<DST>(), &[0])?;
list_push_gen(
pii.meta,
pii.data,
iter.len(),
|_| iter.next().unwrap(),
pii.reset_slot,
pii.reset_value,
);
Ok(())
}
}
}
struct PushInnerInfo<'a, DInner> {
data: &'a mut [MaybeUninit<DInner>],
meta: &'a mut [MaybeUninit<DInner>],
reset_slot: &'a mut usize,
reset_value: usize,
}
impl<DST: ?Sized, BUF: DstBuf> DstStack<DST, BUF> {
#[must_use]
fn meta_words() -> usize {
BUF::round_to_words(size_of::<&DST>() - size_of::<usize>())
}
#[must_use]
unsafe fn raw_at(&self, ofs: usize) -> *mut DST {
let dar = self.data.as_ref();
let meta = &dar[dar.len() - ofs..];
let mw = Self::meta_words();
let (meta, data) = meta.split_at(mw);
unsafe { super::make_fat_ptr(data.as_ptr() as *mut (), meta) }
}
#[must_use]
unsafe fn raw_at_mut(&mut self, ofs: usize) -> *mut DST {
let dar = self.data.as_mut();
let ofs = dar.len() - ofs;
let meta = &mut dar[ofs..];
let mw = Self::meta_words();
let (meta, data) = meta.split_at_mut(mw);
unsafe { super::make_fat_ptr(data.as_mut_ptr() as *mut (), meta) }
}
#[must_use]
fn top_raw(&self) -> Option<*mut DST> {
if self.next_ofs == 0 {
None
} else {
Some(unsafe { self.raw_at(self.next_ofs) })
}
}
#[must_use]
fn top_raw_mut(&mut self) -> Option<*mut DST> {
if self.next_ofs == 0 {
None
} else {
Some(unsafe { self.raw_at_mut(self.next_ofs) })
}
}
unsafe fn push_inner(&mut self, fat_ptr: &DST) -> Result<PushInnerInfo<'_, BUF::Inner>, ()> {
let bytes = size_of_val(fat_ptr);
let (_data_ptr, len, v) = decompose_pointer(fat_ptr);
unsafe { self.push_inner_raw(bytes, &v[..len]) }
}
unsafe fn push_inner_raw(
&mut self,
bytes: usize,
metadata: &[usize],
) -> Result<PushInnerInfo<'_, BUF::Inner>, ()> {
assert!(BUF::round_to_words(size_of_val(metadata)) == Self::meta_words());
let words = BUF::round_to_words(bytes) + Self::meta_words();
let req_space = self.next_ofs + words;
if req_space > self.data.as_ref().len() {
let old_len = self.data.as_ref().len();
if self.data.extend(req_space).is_ok() {
let new_len = self.data.as_ref().len();
self.data.as_mut().rotate_right(new_len - old_len);
}
}
if req_space <= self.data.as_ref().len() {
let prev_next_ofs = self.next_ofs;
self.next_ofs += words;
let len = self.data.as_ref().len();
let slot = &mut self.data.as_mut()[len - self.next_ofs..][..words];
let (meta, rv) = slot.split_at_mut(Self::meta_words());
super::store_metadata(meta, metadata);
Ok(PushInnerInfo {
meta,
data: rv,
reset_slot: &mut self.next_ofs,
reset_value: prev_next_ofs,
})
} else {
Err(())
}
}
}
mod core_impls {
use super::{DstBuf, DstStack, DstStackIter, DstStackIterMut};
use core::{fmt, iter, ops};
impl<DST: ?Sized, BUF: DstBuf> ops::Drop for DstStack<DST, BUF> {
fn drop(&mut self) {
while !self.is_empty() {
self.pop();
}
}
}
impl<DST: ?Sized, BUF: DstBuf + Default> Default for DstStack<DST, BUF> {
fn default() -> Self {
DstStack::new()
}
}
macro_rules! impl_trait {
( $t:path; $($body:tt)* ) => {
impl<BUF: DstBuf, DST: ?Sized> $t for DstStack<DST, BUF> where DST: $t { $( $body )* }
}
}
impl_trait! { fmt::Debug;
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("[")?;
for v in self.iter() {
v.fmt(f)?;
f.write_str(",")?;
}
f.write_str("]")?;
Ok( () )
}
}
impl<'a, DST: 'a + ?Sized, BUF: 'a + DstBuf> iter::Iterator for DstStackIter<'a, DST, BUF> {
type Item = &'a DST;
fn next(&mut self) -> Option<&'a DST> {
if self.1 == 0 {
None
} else {
let rv = unsafe { &*self.0.raw_at(self.1) };
self.1 -= DstStack::<DST, BUF>::meta_words() + BUF::round_to_words(size_of_val(rv));
Some(rv)
}
}
}
impl<'a, DST: 'a + ?Sized, BUF: 'a + DstBuf> iter::Iterator for DstStackIterMut<'a, DST, BUF> {
type Item = &'a mut DST;
fn next(&mut self) -> Option<&'a mut DST> {
if self.1 == 0 {
None
} else {
let rv = unsafe { &mut *self.0.raw_at_mut(self.1) };
self.1 -= DstStack::<DST, BUF>::meta_words() + BUF::round_to_words(size_of_val(rv));
Some(rv)
}
}
}
}