use parking_lot::RwLock;
use std::fmt::Debug;
use std::sync::{Arc, Weak};
type Link<T> = Option<SharedNode<T>>;
type WeakLink<T> = Option<Weak<RwLock<Node<T>>>>;
pub type SharedNode<T> = Arc<RwLock<Node<T>>>;
#[derive(Debug)]
pub struct Node<T>
where
T: Debug,
{
pub element: T,
next: Link<T>,
prev: WeakLink<T>,
}
impl<T> Node<T>
where
T: Debug,
{
pub(crate) fn new(element: T) -> Self {
Self {
element,
next: None,
prev: None,
}
}
}
#[derive(Debug)]
pub struct LinkedList<T>
where
T: Debug,
{
head: Link<T>,
tail: Link<T>,
length: usize,
}
impl<T> LinkedList<T>
where
T: Debug,
{
pub fn new() -> Self {
Self {
head: None,
tail: None,
length: 0,
}
}
pub fn pop(&mut self) -> Option<SharedNode<T>> {
self.tail.take().map(|old_tail_node| {
self.tail = match old_tail_node.write().prev.take() {
None => None,
Some(prev_node) => Weak::upgrade(&prev_node),
};
match self.tail.as_mut() {
None => {
self.head = None;
}
Some(new_tail_node) => {
new_tail_node.write().next = None;
}
}
self.length -= 1;
old_tail_node
})
}
pub fn pop_front(&mut self) -> Option<SharedNode<T>> {
self.head.take().map(|old_head_node| {
self.head = old_head_node.write().next.clone();
match self.head.as_ref() {
None => {
self.tail = None;
}
Some(new_head_node) => {
new_head_node.write().prev = None;
}
}
self.length -= 1;
old_head_node
})
}
pub fn push(&mut self, element: T) -> SharedNode<T> {
let new_node = Arc::new(RwLock::new(Node::new(element)));
self.push_node(Arc::clone(&new_node));
new_node
}
pub fn push_node(&mut self, node: SharedNode<T>) {
node.write().prev = self.tail.as_ref().map(Arc::downgrade);
node.write().next = None;
match self.tail.as_ref() {
Some(tail_node) => {
tail_node.write().next = Some(Arc::clone(&node))
}
None => self.head = Some(Arc::clone(&node)),
}
self.tail = Some(node);
self.length += 1;
}
pub fn push_front(&mut self, element: T) -> SharedNode<T> {
let new_node = Arc::new(RwLock::new(Node::new(element)));
self.push_node_front(Arc::clone(&new_node));
new_node
}
pub fn push_node_front(&mut self, node: SharedNode<T>) {
node.write().prev = None;
node.write().next = self.head.clone();
match self.head.as_ref() {
Some(head_node) => {
head_node.write().prev = Some(Arc::downgrade(&node));
}
None => self.tail = Some(Arc::clone(&node)),
}
self.head = Some(node);
self.length += 1;
}
pub fn remove_node(&mut self, target_node: SharedNode<T>) {
let mutable_target = target_node.write();
let maybe_previous_node = match mutable_target.prev.as_ref() {
None => None,
Some(weak_prev) => Weak::upgrade(weak_prev),
};
match maybe_previous_node.clone() {
Some(previous_node) => {
previous_node.write().next = mutable_target.next.clone();
}
None => {
self.head = mutable_target.next.clone();
}
}
match mutable_target.next.as_ref() {
Some(next_node) => {
next_node.write().prev = mutable_target.prev.clone();
}
None => {
self.tail = maybe_previous_node;
}
}
self.length -= 1;
}
pub fn len(&self) -> usize {
self.length
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn iter(&self) -> NodeIter<T> {
NodeIter {
next: self.head.as_ref().cloned(),
}
}
pub fn head(&self) -> Link<T> {
self.head.as_ref().cloned()
}
pub fn tail(&self) -> Link<T> {
self.tail.as_ref().cloned()
}
}
impl<T> Drop for LinkedList<T>
where
T: Debug,
{
fn drop(&mut self) {
while self.pop_front().is_some() {}
}
}
pub struct NodeIter<T>
where
T: Debug,
{
next: Option<SharedNode<T>>,
}
impl<T> Iterator for NodeIter<T>
where
T: Debug,
{
type Item = SharedNode<T>;
fn next(&mut self) -> Option<Self::Item> {
self.next.take().map(|current_node| {
self.next = current_node.read().next.as_ref().map(Arc::clone);
current_node
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn single_threaded_empty_list_returns_zero_length() {
let list = LinkedList::<u64>::new();
assert_eq!(list.len(), 0);
}
#[test]
fn single_threaded_can_push_elements() {
let mut list = LinkedList::<u64>::new();
let mut pushed = list.push(1);
assert_eq!(pushed.read().element, 1);
assert_eq!(list.len(), 1);
pushed = list.push(2);
assert_eq!(pushed.read().element, 2);
assert_eq!(list.len(), 2);
pushed = list.push(3);
assert_eq!(pushed.read().element, 3);
assert_eq!(list.len(), 3);
}
#[test]
fn single_threaded_can_pop_elements() {
let mut list = LinkedList::<u64>::new();
list.push(1);
list.push(2);
list.push(3);
assert_eq!(list.len(), 3);
assert_eq!(list.pop().unwrap().read().element, 3);
assert_eq!(list.len(), 2);
assert_eq!(list.pop().unwrap().read().element, 2);
assert_eq!(list.len(), 1);
assert_eq!(list.pop().unwrap().read().element, 1);
assert_eq!(list.len(), 0);
assert!(list.pop().is_none());
}
#[test]
fn single_threaded_can_push_elements_to_the_front() {
let mut list = LinkedList::<u64>::new();
list.push_front(1);
assert_eq!(list.len(), 1);
list.push_front(2);
assert_eq!(list.len(), 2);
list.push_front(3);
assert_eq!(list.len(), 3);
}
#[test]
fn single_threaded_can_pop_elements_from_the_front() {
let mut list = LinkedList::<u64>::new();
list.push(1);
list.push(2);
list.push(3);
assert_eq!(list.len(), 3);
assert_eq!(list.pop_front().unwrap().read().element, 1);
assert_eq!(list.len(), 2);
assert_eq!(list.pop_front().unwrap().read().element, 2);
assert_eq!(list.len(), 1);
assert_eq!(list.pop_front().unwrap().read().element, 3);
assert_eq!(list.len(), 0);
assert!(list.pop_front().is_none());
}
#[test]
fn single_threaded_list_can_unlink_head() {
let mut list = LinkedList::<u64>::new();
let pushed = list.push(1);
list.push(2);
list.push(3);
list.remove_node(pushed);
assert_eq!(list.len(), 2);
assert_eq!(list.pop_front().unwrap().read().element, 2);
}
#[test]
fn single_threaded_list_can_unlink_tail() {
let mut list = LinkedList::<u64>::new();
list.push(1);
list.push(2);
let pushed = list.push(3);
list.remove_node(pushed);
assert_eq!(list.len(), 2);
assert_eq!(list.pop().unwrap().read().element, 2);
}
#[test]
fn single_threaded_list_can_unlink_node_from_middle() {
let mut list = LinkedList::<u64>::new();
list.push(1);
let pushed = list.push(2);
list.push(3);
list.remove_node(pushed);
assert_eq!(list.len(), 2);
assert_eq!(list.pop_front().unwrap().read().element, 1);
}
}