use core::{iter, marker, mem, ops, ptr};
mod impls;
pub struct Stack<T: ?Sized, D: ::DataBuf> {
_pd: marker::PhantomData<*const T>,
next_ofs: usize,
data: D,
}
impl<T: ?Sized, D: ::DataBuf> ops::Drop for Stack<T, D> {
fn drop(&mut self) {
while !self.is_empty() {
self.pop();
}
}
}
impl<T: ?Sized, D: ::DataBuf + Default> Default for Stack<T, D> {
fn default() -> Self {
Stack::new()
}
}
impl<T: ?Sized, D: ::DataBuf> Stack<T, D> {
pub fn new() -> Self
where
D: Default,
{
Self::with_buffer(D::default())
}
pub fn with_buffer(data: D) -> Self {
Stack {
_pd: marker::PhantomData,
next_ofs: 0,
data,
}
}
pub fn is_empty(&self) -> bool {
self.next_ofs == 0
}
fn meta_words() -> usize {
D::round_to_words(mem::size_of::<&T>() - mem::size_of::<usize>())
}
#[cfg(feature = "unsize")]
pub fn push<U: marker::Unsize<T>>(&mut self, v: U) -> Result<(), U>
where
(U, D::Inner): crate::AlignmentValid,
{
self.push_stable(v, |p| p)
}
pub fn push_stable<U, F: FnOnce(&U) -> &T>(&mut self, v: U, f: F) -> Result<(), U>
where
(U, D::Inner): crate::AlignmentValid,
{
<(U, D::Inner) as crate::AlignmentValid>::check();
unsafe {
match self.push_inner(crate::check_fat_pointer(&v, f)) {
Ok(pii) => {
ptr::write(pii.data.as_mut_ptr() as *mut U, v);
Ok(())
}
Err(_) => Err(v),
}
}
}
unsafe fn raw_at(&self, ofs: usize) -> *mut T {
let dar = self.data.as_ref();
let meta = &dar[dar.len() - ofs..];
let mw = Self::meta_words();
let (meta, data) = meta.split_at(mw);
super::make_fat_ptr(data.as_ptr() as *mut (), meta)
}
unsafe fn raw_at_mut(&mut self, ofs: usize) -> *mut T {
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);
super::make_fat_ptr(data.as_mut_ptr() as *mut (), meta)
}
fn top_raw(&self) -> Option<*mut T> {
if self.next_ofs == 0 {
None
} else {
Some(unsafe { self.raw_at(self.next_ofs) })
}
}
fn top_raw_mut(&mut self) -> Option<*mut T> {
if self.next_ofs == 0 {
None
} else {
Some(unsafe { self.raw_at_mut(self.next_ofs) })
}
}
pub fn top(&self) -> Option<&T> {
self.top_raw().map(|x| unsafe { &*x })
}
pub fn top_mut(&mut self) -> Option<&mut T> {
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 = mem::size_of_val(&*ptr);
ptr::drop_in_place(ptr);
D::round_to_words(size)
};
self.next_ofs -= words + Self::meta_words();
}
}
pub fn iter(&self) -> Iter<T, D> {
Iter(self, self.next_ofs)
}
pub fn iter_mut(&mut self) -> IterMut<T, D> {
IterMut(self, self.next_ofs)
}
}
struct PushInnerInfo<'a, DInner> {
data: &'a mut crate::BufSlice<DInner>,
meta: &'a mut crate::BufSlice<DInner>,
reset_slot: &'a mut usize,
reset_value: usize,
}
impl<T: ?Sized, D: ::DataBuf> Stack<T, D> {
unsafe fn push_inner(&mut self, fat_ptr: &T) -> Result<PushInnerInfo<D::Inner>, ()> {
let bytes = mem::size_of_val(fat_ptr);
let (_data_ptr, len, v) = crate::decompose_pointer(fat_ptr);
self.push_inner_raw(bytes, &v[..len])
}
unsafe fn push_inner_raw(&mut self, bytes: usize, metadata: &[usize]) -> Result<PushInnerInfo<D::Inner>, ()> {
assert!( D::round_to_words(mem::size_of_val(metadata)) == Self::meta_words() );
let words = D::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 let Ok(_) = self.data.extend(req_space) {
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(())
}
}
}
impl<D: ::DataBuf> Stack<str, D> {
pub fn push_str(&mut self, v: &str) -> Result<(), ()> {
unsafe {
self.push_inner(v)
.map(|pii| ptr::copy(v.as_bytes().as_ptr(), pii.data.as_mut_ptr() as *mut u8, v.len()))
}
}
}
impl<D: ::DataBuf, T: Clone> Stack<[T], D>
where
(T, D::Inner): crate::AlignmentValid,
{
pub fn push_cloned(&mut self, v: &[T]) -> Result<(), ()> {
<(T, D::Inner) as crate::AlignmentValid>::check();
self.push_from_iter(v.iter().cloned())
}
pub fn push_copied(&mut self, v: &[T]) -> Result<(), ()>
where
T: Copy,
{
<(T, D::Inner) as crate::AlignmentValid>::check();
unsafe {
self.push_inner(v).map(|pii| {
ptr::copy(
v.as_ptr() as *const u8,
pii.data.as_mut_ptr() as *mut u8,
mem::size_of_val(v),
)
})
}
}
}
impl<D: crate::DataBuf, T> Stack<[T], D>
where
(T, D::Inner): crate::AlignmentValid,
{
pub fn push_from_iter(&mut self, mut iter: impl ExactSizeIterator<Item=T>) -> Result<(),()> {
<(T, D::Inner) as crate::AlignmentValid>::check();
unsafe {
let pii = self.push_inner_raw(iter.len() * mem::size_of::<T>(), &[0])?;
crate::list_push_gen(pii.meta, pii.data, iter.len(), |_| iter.next().unwrap(), pii.reset_slot, pii.reset_value);
Ok( () )
}
}
}
pub struct Iter<'a, T: 'a + ?Sized, D: 'a + crate::DataBuf>(&'a Stack<T, D>, usize);
impl<'a, T: 'a + ?Sized, D: 'a + crate::DataBuf> iter::Iterator for Iter<'a, T, D> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
if self.1 == 0 {
None
} else {
let rv = unsafe { &*self.0.raw_at(self.1) };
self.1 -= Stack::<T, D>::meta_words() + D::round_to_words(mem::size_of_val(rv));
Some(rv)
}
}
}
pub struct IterMut<'a, T: 'a + ?Sized, D: 'a + crate::DataBuf>(&'a mut Stack<T, D>, usize);
impl<'a, T: 'a + ?Sized, D: 'a + crate::DataBuf> iter::Iterator for IterMut<'a, T, D> {
type Item = &'a mut T;
fn next(&mut self) -> Option<&'a mut T> {
if self.1 == 0 {
None
} else {
let rv = unsafe { &mut *self.0.raw_at_mut(self.1) };
self.1 -= Stack::<T, D>::meta_words() + D::round_to_words(mem::size_of_val(rv));
Some(rv)
}
}
}