use core::{iter, marker, mem, ops, ptr};
mod impls;
pub struct StackA<T: ?Sized, D: ::DataBuf> {
_pd: marker::PhantomData<*const T>,
next_ofs: usize,
data: D,
}
impl<T: ?Sized, D: ::DataBuf> ops::Drop for StackA<T, D> {
fn drop(&mut self) {
while !self.is_empty() {
self.pop();
}
}
}
impl<T: ?Sized, D: ::DataBuf + Default> Default for StackA<T, D> {
fn default() -> Self {
StackA::new()
}
}
impl<T: ?Sized, D: ::DataBuf> StackA<T, D> {
pub fn new() -> Self
where
D: Default,
{
Self::with_buffer(D::default())
}
pub fn with_buffer(data: D) -> Self {
StackA {
_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>())
}
unsafe fn push_inner(&mut self, fat_ptr: &T) -> Result<(&mut [D::Inner], &mut [D::Inner]), ()> {
let bytes = mem::size_of_val(fat_ptr);
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() {
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());
let mut ptr_raw: *const T = fat_ptr;
super::store_metadata(meta, &crate::ptr_as_slice(&mut ptr_raw)[1..]);
Ok((meta, rv))
} else {
Err(())
}
}
#[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((_, d)) => {
ptr::write(d.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();
super::make_fat_ptr(meta[mw..].as_ptr() as usize, &meta[..mw])
}
fn top_raw(&self) -> Option<*mut T> {
if self.next_ofs == 0 {
None
} else {
Some(unsafe { self.raw_at(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().map(|x| unsafe { &mut *x })
}
pub fn pop(&mut self) {
if let Some(ptr) = self.top_raw() {
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 + 1;
}
}
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)
}
}
impl<D: ::DataBuf> StackA<str, D> {
pub fn push_str(&mut self, v: &str) -> Result<(), ()> {
unsafe {
self.push_inner(v)
.map(|(_, d)| ptr::copy(v.as_bytes().as_ptr(), d.as_mut_ptr() as *mut u8, v.len()))
}
}
}
impl<D: ::DataBuf, T: Clone> StackA<[T], D> {
pub fn push_cloned(&mut self, v: &[T]) -> Result<(), ()> {
unsafe {
let (meta, d) = self.push_inner(v)?;
crate::list_push_cloned(meta, d, v);
}
Ok(())
}
pub fn push_copied(&mut self, v: &[T]) -> Result<(), ()>
where
T: Copy,
{
unsafe {
self.push_inner(v).map(|(_, d)| {
ptr::copy(
v.as_ptr() as *const u8,
d.as_mut_ptr() as *mut u8,
mem::size_of_val(v),
)
})
}
}
}
pub struct Iter<'a, T: 'a + ?Sized, D: 'a + crate::DataBuf>(&'a StackA<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 -= StackA::<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 StackA<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(self.1) };
self.1 -= StackA::<T, D>::meta_words() + D::round_to_words(mem::size_of_val(rv));
Some(rv)
}
}
}