#![cfg_attr(not(test), no_std)]
use core::{fmt, hash::Hash, iter::FusedIterator, ops::Range};
#[derive(Clone, Copy)]
pub struct Stack<'a, T> {
inner: _Stack<'a, T>,
}
impl<T, O> PartialEq<Stack<'_, O>> for Stack<'_, T>
where
T: PartialEq<O>,
{
fn eq(&self, other: &Stack<O>) -> bool {
self.iter().eq(other.iter())
}
}
impl<T, O> PartialEq<[O]> for Stack<'_, T>
where
T: PartialEq<O>,
{
fn eq(&self, other: &[O]) -> bool {
self.iter().eq(other.iter())
}
}
impl<T, O> PartialEq<Stack<'_, O>> for [T]
where
T: PartialEq<O>,
{
fn eq(&self, other: &Stack<O>) -> bool {
self.iter().eq(other.iter())
}
}
impl<const N: usize, T, O> PartialEq<[O; N]> for Stack<'_, T>
where
T: PartialEq<O>,
{
fn eq(&self, other: &[O; N]) -> bool {
self.iter().eq(other.iter())
}
}
impl<const N: usize, T, O> PartialEq<Stack<'_, O>> for [T; N]
where
T: PartialEq<O>,
{
fn eq(&self, other: &Stack<O>) -> bool {
self.iter().eq(other.iter())
}
}
impl<T, O> PartialOrd<Stack<'_, O>> for Stack<'_, T>
where
T: PartialOrd<O>,
{
fn partial_cmp(&self, other: &Stack<'_, O>) -> Option<core::cmp::Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<T> Ord for Stack<'_, T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.iter().cmp(other.iter())
}
}
impl<T> Eq for Stack<'_, T> where T: Eq {}
impl<T> Hash for Stack<'_, T>
where
T: Hash,
{
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
state.write_usize(self.len());
for i in self {
i.hash(state)
}
}
}
impl<T> fmt::Debug for Stack<'_, T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self).finish()
}
}
impl<'a, T> Stack<'a, T> {
pub const fn new() -> Self {
Self {
inner: _Stack::Bottom,
}
}
pub const fn of(item: T) -> Self {
Self {
inner: _Stack::Top {
head: item,
tail: Self::EMPTY_REF,
},
}
}
pub const fn pushed(&'a self, item: T) -> Self {
Self {
inner: _Stack::Top {
head: item,
tail: self,
},
}
}
pub const fn len(&self) -> usize {
match self.inner {
_Stack::Bottom => 0,
_Stack::Top { head: _, tail } => 1 + tail.len(),
}
}
pub const fn is_empty(&self) -> bool {
matches!(self.inner, _Stack::Bottom)
}
pub const fn get(&self, ix: usize) -> Option<&T> {
let mut current = self;
let Some(mut depth) = self.len().checked_sub(ix + 1) else {
return None;
};
while let Some(next_depth) = depth.checked_sub(1) {
depth = next_depth;
match current.inner {
_Stack::Bottom => return None,
_Stack::Top { head: _, tail } => current = tail,
}
}
match ¤t.inner {
_Stack::Bottom => None,
_Stack::Top { head, tail: _ } => Some(head),
}
}
pub const fn first(&self) -> Option<&T> {
self.get(0)
}
pub const fn last(&self) -> Option<&T> {
match &self.inner {
_Stack::Bottom => None,
_Stack::Top { head, tail: _ } => Some(head),
}
}
pub fn last_mut(&mut self) -> Option<&mut T> {
match &mut self.inner {
_Stack::Bottom => None,
_Stack::Top { head, tail: _ } => Some(head),
}
}
pub fn split_last(&self) -> Option<(&T, &'a Self)> {
match &self.inner {
_Stack::Bottom => None,
_Stack::Top { head, tail } => Some((head, tail)),
}
}
pub fn into_split_last(self) -> Option<(T, &'a Self)> {
match self.inner {
_Stack::Bottom => None,
_Stack::Top { head, tail } => Some((head, tail)),
}
}
pub fn iter(&'a self) -> Iter<'a, T> {
Iter {
inner: self,
ix: 0..self.len(),
}
}
pub fn with<R>(&self, item: T, f: impl FnOnce(&Stack<'_, T>) -> R) -> R {
f(&self.pushed(item))
}
pub fn with_all<R>(
&self,
items: impl IntoIterator<Item = T>,
f: impl FnOnce(&Stack<'_, T>) -> R,
) -> R {
let mut chain = items.into_iter();
match chain.next() {
Some(head) => self.pushed(head).with_all(chain, f),
None => f(self),
}
}
pub fn chained(&'a self, iter: impl IntoIterator<Item = &'a mut Self>) -> &'a Self {
let mut curr = self;
for it in iter {
match &mut it.inner {
_Stack::Bottom => {}
_Stack::Top { head: _, tail } => *tail = curr,
}
curr = it;
}
curr
}
pub const EMPTY_REF: &'a Self = &Self {
inner: _Stack::Bottom,
};
}
impl<'a, T> Default for Stack<'a, T> {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Copy)]
enum _Stack<'a, T> {
Bottom,
Top { head: T, tail: &'a Stack<'a, T> },
}
pub struct Iter<'a, T> {
inner: &'a Stack<'a, T>,
ix: Range<usize>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.inner.get(self.ix.next()?)
}
}
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.get(self.ix.next_back()?)
}
}
impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
impl<'a, T> FusedIterator for Iter<'a, T> {}
impl<'a, T> IntoIterator for &'a Stack<'a, T> {
type Item = &'a T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[macro_export]
macro_rules! stack {
([$($expr:expr),* $(,)?] in $ident:ident) => {{
$ident = [$($expr),*].map($crate::Stack::of);
$crate::Stack::EMPTY_REF.chained($ident.iter_mut())
}};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn on_chained() {
Stack::of(String::from("mary")).with_all(
["had".into(), "a".into(), "little".into(), "lamb".into()],
|actual| {
let mut storage;
let expected = stack![["mary", "had", "a", "little", "lamb"] in storage];
assert_eq!(actual, expected)
},
);
}
#[test]
fn get() {
Stack::of(String::from("mary")).with_all(
["had".into(), "a".into(), "little".into(), "lamb".into()],
|it| {
assert_eq!(it.get(0).unwrap(), "mary");
assert_eq!(it.get(1).unwrap(), "had");
assert_eq!(it.get(2).unwrap(), "a");
assert_eq!(it.get(3).unwrap(), "little");
assert_eq!(it.get(4).unwrap(), "lamb");
assert_eq!(it.get(5), None);
},
);
}
#[test]
fn iter() {
Stack::of(String::from("mary")).with_all(
["had".into(), "a".into(), "little".into(), "lamb".into()],
|it| {
assert_eq!(
it.iter().collect::<Vec<_>>(),
["mary", "had", "a", "little", "lamb",]
)
},
);
}
#[test]
fn rev() {
Stack::of(String::from("mary")).with_all(
["had".into(), "a".into(), "little".into(), "lamb".into()],
|it| {
assert_eq!(
it.iter().rev().collect::<Vec<_>>(),
["lamb", "little", "a", "had", "mary",]
)
},
);
}
}