From a44c9d9adbf296074341493d67fdeca5dad6c0b5 Mon Sep 17 00:00:00 2001 From: "Aode (lion)" Date: Mon, 30 May 2022 19:20:30 -0500 Subject: [PATCH] Stackful list --- .gitignore | 2 + Cargo.toml | 12 ++ src/lib.rs | 526 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 540 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..53a9fc7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "stackful-list" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = ["std"] +std = ["alloc"] +alloc = [] + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..eda1fb9 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,526 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "alloc")] +extern crate alloc; + +use core::ops::{Deref, DerefMut}; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +pub trait Node { + type Value; + + fn value_ref(&self) -> &Self::Value; + fn value_mut(&mut self) -> &mut Self::Value; + fn next(&mut self) -> Option<&mut dyn Node>; + fn next_immutable(&self) -> Option<&dyn Node>; +} + +pub trait ReverseOnto { + type Output; + + fn reverse_onto(self, input: Input) -> Self::Output; +} + +pub trait PrependOnto { + type Output; + + fn prepend_onto(self, input: Input) -> Self::Output; +} + +pub trait PopBack { + type Output; + + fn pop_back(self) -> Self::Output; +} + +pub fn new() -> Empty { + Empty +} + +#[derive(Clone, Debug)] +pub struct Empty; + +#[derive(Clone, Debug)] +pub struct ListNode { + value: T, + next: N, +} + +pub struct Iter<'a, T> { + node: Option<&'a dyn Node>, +} + +pub type Reversed = >::Output; +pub type Prepend = >::Output; +pub type PushBack = Prepend>; + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + let node = self.node.take()?; + let value = node.value_ref(); + self.node = node.next_immutable(); + Some(value) + } +} + +impl Deref for ListNode { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +impl DerefMut for ListNode { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.value + } +} + +impl AsRef for ListNode { + fn as_ref(&self) -> &T { + &self.value + } +} + +impl AsMut for ListNode { + fn as_mut(&mut self) -> &mut T { + &mut self.value + } +} + +impl Empty { + pub fn push_front(self, value: T) -> ListNode { + ListNode { value, next: Empty } + } + + pub fn push_back(self, value: T) -> ListNode { + ListNode { value, next: Empty } + } + + pub fn prepend(self, other: L) -> Prepend + where + L: PrependOnto, + { + other.prepend_onto(self) + } + + pub fn append(self, other: L) -> Prepend + where + Self: PrependOnto, + { + self.prepend_onto(other) + } + + pub fn reverse(self) -> Self { + Empty + } + + pub fn is_empty(&self) -> bool { + true + } +} + +impl ListNode { + pub fn push_front(self, value: T) -> ListNode { + ListNode { value, next: self } + } + + pub fn push_front_borrowed(&mut self, value: T) -> ListNode { + ListNode { value, next: self } + } + + pub fn pop_front(self) -> N { + self.next + } + + pub fn push_back(self, value: T) -> PushBack + where + Self: PrependOnto>, + { + self.prepend_onto(new().push_front(value)) + } + + pub fn pop_back(self) -> ::Output + where + Self: PopBack, + { + PopBack::pop_back(self) + } + + pub fn prepend(self, other: L) -> Prepend + where + L: PrependOnto, + { + other.prepend_onto(self) + } + + pub fn append(self, other: L) -> Prepend + where + Self: PrependOnto, + { + self.prepend_onto(other) + } + + pub fn split(self) -> (T, N) { + (self.value, self.next) + } + + pub fn iter(&self) -> Iter<'_, T> + where + N: Node, + { + Iter { + node: Some(self as &dyn Node), + } + } + + pub fn reverse(self) -> Reversed + where + Self: ReverseOnto, + { + self.reverse_onto(Empty) + } + + pub fn is_empty(&self) -> bool { + false + } +} + +impl<'a, N> IntoIterator for &'a ListNode +where + N: Node, +{ + type IntoIter = Iter<'a, N::Value>; + type Item = &'a N::Value; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl Node for ListNode +where + N: Node, +{ + type Value = T; + + fn value_ref(&self) -> &Self::Value { + &self.value + } + + fn value_mut(&mut self) -> &mut Self::Value { + &mut self.value + } + + fn next(&mut self) -> Option<&mut dyn Node> { + Some(&mut self.next) + } + + fn next_immutable(&self) -> Option<&dyn Node> { + Some(&self.next) + } +} + +impl Node for ListNode { + type Value = T; + + fn value_ref(&self) -> &Self::Value { + &self.value + } + + fn value_mut(&mut self) -> &mut Self::Value { + &mut self.value + } + + fn next(&mut self) -> Option<&mut dyn Node> { + None + } + + fn next_immutable(&self) -> Option<&dyn Node> { + None + } +} + +impl<'a, N> Node for &'a mut N +where + N: Node + ?Sized, +{ + type Value = N::Value; + + fn value_ref(&self) -> &Self::Value { + N::value_ref(self) + } + + fn value_mut(&mut self) -> &mut Self::Value { + N::value_mut(self) + } + + fn next(&mut self) -> Option<&mut dyn Node> { + N::next(self) + } + + fn next_immutable(&self) -> Option<&dyn Node> { + N::next_immutable(self) + } +} + +impl ReverseOnto for Empty { + type Output = Input; + + fn reverse_onto(self, input: Input) -> Self::Output { + input + } +} + +impl ReverseOnto for ListNode +where + N: ReverseOnto>, +{ + type Output = N::Output; + + fn reverse_onto(self, input: Input) -> Self::Output { + let ListNode { value, next } = self; + + next.reverse_onto(ListNode { value, next: input }) + } +} + +impl PrependOnto for Empty { + type Output = Input; + + fn prepend_onto(self, input: Input) -> Self::Output { + input + } +} + +impl PrependOnto for ListNode +where + N: PrependOnto, +{ + type Output = ListNode; + + fn prepend_onto(self, input: Input) -> Self::Output { + let ListNode { value, next } = self; + + ListNode { + value, + next: next.prepend_onto(input), + } + } +} + +impl PopBack for ListNode { + type Output = Empty; + + fn pop_back(self) -> Self::Output { + self.next + } +} + +impl PopBack for ListNode +where + N: PopBack, +{ + type Output = ListNode; + + fn pop_back(self) -> Self::Output { + let ListNode { value, next } = self; + + ListNode { + value, + next: next.pop_back(), + } + } +} + +#[cfg(feature = "alloc")] +impl Node for Box +where + N: Node + ?Sized, +{ + type Value = N::Value; + + fn value_ref(&self) -> &Self::Value { + N::value_ref(self) + } + + fn value_mut(&mut self) -> &mut Self::Value { + N::value_mut(self) + } + + fn next(&mut self) -> Option<&mut dyn Node> { + N::next(self) + } + + fn next_immutable(&self) -> Option<&dyn Node> { + N::next_immutable(self) + } +} + +#[cfg(test)] +mod std_tests { + use super::{new, Node}; + + #[test] + fn construct_list() { + let mut list = new() + .push_front(5) + .push_front(4) + .push_front(3) + .push_front(2) + .push_front(1) + .push_front(0); + + let mut next = Some(&mut list as &mut dyn Node); + + let mut out = [0; 6]; + let mut index = 0; + while let Some(node) = next { + out[index] = *node.value_ref(); + index += 1; + next = node.next(); + } + + assert_eq!(out, [0, 1, 2, 3, 4, 5]); + + let mut out = [0; 6]; + for (index, item) in list.iter().enumerate() { + out[index] = *item; + } + + assert_eq!(out, [0, 1, 2, 3, 4, 5]); + + let mut list = list.pop_front(); + + next = Some(&mut list as &mut dyn Node); + + let mut out = [0; 5]; + let mut index = 0; + while let Some(node) = next { + out[index] = *node.value_ref(); + index += 1; + next = node.next(); + } + + assert_eq!(out, [1, 2, 3, 4, 5]); + + let mut out = [0; 5]; + for (index, item) in list.iter().enumerate() { + out[index] = *item; + } + + assert_eq!(out, [1, 2, 3, 4, 5]); + + let list = list.reverse(); + + let mut out = [0; 5]; + for (index, item) in list.iter().enumerate() { + out[index] = *item; + } + + assert_eq!(out, [5, 4, 3, 2, 1]); + + let second_list = new() + .push_front(9) + .push_front(8) + .push_front(7) + .push_front(6); + + let list = list.prepend(second_list); + + let mut out = [0; 9]; + for (index, item) in list.iter().enumerate() { + out[index] = *item; + } + + assert_eq!(out, [6, 7, 8, 9, 5, 4, 3, 2, 1]); + + let third_list = new() + .push_front(10) + .push_front(11) + .push_front(12) + .push_front(13); + + let list = list.append(third_list); + + let mut out = [0; 13]; + for (index, item) in list.iter().enumerate() { + out[index] = *item; + } + + assert_eq!(out, [6, 7, 8, 9, 5, 4, 3, 2, 1, 13, 12, 11, 10]); + + let list = list.push_back(0); + + let mut out = [0; 14]; + for (index, item) in list.iter().enumerate() { + out[index] = *item; + } + + assert_eq!(out, [6, 7, 8, 9, 5, 4, 3, 2, 1, 13, 12, 11, 10, 0]); + + let list = list.pop_back(); + + let mut out = [0; 13]; + for (index, item) in list.iter().enumerate() { + out[index] = *item; + } + + assert_eq!(out, [6, 7, 8, 9, 5, 4, 3, 2, 1, 13, 12, 11, 10]); + } + + #[test] + fn construct_list_borroed() { + let mut list = new().push_front(5); + let mut list = list.push_front_borrowed(4); + let mut list = list.push_front_borrowed(3); + let mut list = list.push_front_borrowed(2); + let mut list = list.push_front_borrowed(1); + let mut list = list.push_front_borrowed(0); + + let mut next = Some(&mut list as &mut dyn Node); + + let mut out = [0; 6]; + let mut index = 0; + while let Some(node) = next { + out[index] = *node.value_ref(); + index += 1; + next = node.next(); + } + + assert_eq!(out, [0, 1, 2, 3, 4, 5]); + + let mut out = [0; 6]; + for (index, item) in list.iter().enumerate() { + out[index] = *item; + } + + assert_eq!(out, [0, 1, 2, 3, 4, 5]); + + let mut list = list.pop_front(); + + next = Some(&mut list as &mut dyn Node); + + let mut out = [0; 5]; + let mut index = 0; + while let Some(node) = next { + out[index] = *node.value_ref(); + index += 1; + next = node.next(); + } + + assert_eq!(out, [1, 2, 3, 4, 5]); + + let mut out = [0; 5]; + for (index, item) in list.iter().enumerate() { + out[index] = *item; + } + + assert_eq!(out, [1, 2, 3, 4, 5]); + } +}