pub type LIFOVecEntry<'a, T> = LIFOEntry<'a, Vec<T>>;
pub struct LIFOEntry<'a, C: ?Sized>(&'a mut C);
impl<'a, C: ?Sized + Stack> LIFOEntry<'a, C> {
pub unsafe fn new(stack: &'a mut C) -> Self {
Self(stack)
}
pub fn pop_pointee(self) -> C::Item {
let LIFOEntry(stack) = self;
unsafe { stack.s_pop_unchecked() }
}
}
impl<'a, C: ?Sized + Stack> std::ops::Deref for LIFOEntry<'a, C> {
type Target = C::Item;
fn deref(&self) -> &Self::Target {
let LIFOEntry(stack) = self;
unsafe { stack.lifo_ref_unchecked() }
}
}
impl<'a, C: ?Sized + Stack> std::ops::DerefMut for LIFOEntry<'a, C> {
fn deref_mut(&mut self) -> &mut Self::Target {
let LIFOEntry(stack) = self;
unsafe { stack.lifo_mut_unchecked() }
}
}
pub trait Stack {
type Item;
fn s_is_empty(&self) -> bool;
fn s_push(&mut self, item: Self::Item);
fn s_push_checked(&mut self, item: Self::Item) -> Option<()> {
self.s_push(item);
Some(())
}
fn lifo_push(&mut self, item: Self::Item) -> LIFOEntry<Self>;
fn s_pop(&mut self) -> Option<Self::Item>;
#[inline]
unsafe fn s_pop_unchecked(&mut self) -> Self::Item {
self.s_pop().unwrap_unchecked()
}
#[inline]
fn lifo(&mut self) -> Option<LIFOEntry<Self>> {
if self.s_is_empty() {
None
} else {
Some(unsafe { LIFOEntry::new(self) })
}
}
#[inline]
unsafe fn lifo_unchecked(&mut self) -> LIFOEntry<Self> {
self.lifo().unwrap_unchecked()
}
fn lifo_ref(&self) -> Option<&Self::Item>;
#[inline]
unsafe fn lifo_ref_unchecked(&self) -> &Self::Item {
self.lifo_ref().unwrap_unchecked()
}
fn lifo_mut(&mut self) -> Option<&mut Self::Item>;
#[inline]
unsafe fn lifo_mut_unchecked(&mut self) -> &mut Self::Item {
self.lifo_mut().unwrap_unchecked()
}
}
impl<T> Stack for Vec<T> {
type Item = T;
#[inline]
fn s_is_empty(&self) -> bool {
self.is_empty()
}
#[inline]
fn s_push(&mut self, item: Self::Item) {
self.push(item);
}
#[inline]
fn lifo_push(&mut self, item: Self::Item) -> LIFOEntry<Self> {
self.push(item);
unsafe { self.lifo_unchecked() }
}
#[inline]
fn s_pop(&mut self) -> Option<Self::Item> {
self.pop()
}
#[inline]
fn lifo_ref(&self) -> Option<&Self::Item> {
self.last()
}
#[inline]
fn lifo_mut(&mut self) -> Option<&mut Self::Item> {
self.last_mut()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_or_insert() {
let mut stack = vec![1, 2, 3];
let mut entry = stack.lifo_push(4);
assert_eq!(*entry, 4);
*entry = 5;
assert_eq!(*entry, 5);
drop(entry);
assert_eq!(stack, vec![1, 2, 3, 5]);
let entry = stack.lifo().unwrap();
assert_eq!(entry.pop_pointee(), 5);
assert_eq!(stack, vec![1, 2, 3]);
}
}