#![allow(rustdoc::redundant_explicit_links)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, allow(unused_attributes))]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
#[cfg(any(feature = "std", test))]
extern crate std;
use core::marker::PhantomData;
use core::{
borrow::BorrowMut,
fmt,
mem::{self, MaybeUninit},
ptr::{self, null_mut},
};
use pointers::Pointer;
pub unsafe trait DListItem<Tag>: Sized {
fn get_node(&self) -> &mut DListNode<Tag>;
#[allow(unsafe_op_in_unsafe_fn)]
#[inline(always)]
unsafe fn get_node_from_ptr<'a>(p: *mut u8) -> &'a mut DListNode<Tag>
where
Self: 'a,
{
debug_assert!(!p.is_null());
(*(p as *const Self)).get_node()
}
}
#[repr(C)]
pub struct DListNode<Tag> {
prev: *mut u8,
next: *mut u8,
_phan: PhantomData<fn(&Tag)>,
}
unsafe impl<Tag> Send for DListNode<Tag> {}
impl<Tag> Default for DListNode<Tag> {
#[inline(always)]
fn default() -> Self {
Self { prev: null_mut(), next: null_mut(), _phan: Default::default() }
}
}
impl<Tag> fmt::Debug for DListNode<Tag> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(")?;
if !self.prev.is_null() {
write!(f, "prev: {:p} ", self.prev)?;
} else {
write!(f, "prev: none ")?;
}
if !self.next.is_null() {
write!(f, "next: {:p} ", self.next)?;
} else {
write!(f, "next: none ")?;
}
write!(f, ")")
}
}
#[repr(C)]
pub struct DLinkedList<P, Tag>
where
P: Pointer,
P::Target: DListItem<Tag>,
{
length: usize,
head: *mut u8,
tail: *mut u8,
_phan: PhantomData<fn(&P, &Tag)>,
}
unsafe impl<P, Tag> Send for DLinkedList<P, Tag>
where
P: Pointer,
P::Target: DListItem<Tag>,
{
}
impl<P: fmt::Debug, Tag> fmt::Debug for DLinkedList<P, Tag>
where
P: Pointer,
P::Target: DListItem<Tag>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{ length: {} ", self.length)?;
if !self.head.is_null() {
write!(f, "head: {:?} ", self.head)?;
} else {
write!(f, "head: none ")?;
}
if !self.tail.is_null() {
write!(f, "tail: {:?} ", self.tail)?;
} else {
write!(f, "tail: none ")?;
}
write!(f, "}}")
}
}
impl<P, Tag> DLinkedList<P, Tag>
where
P: Pointer,
P::Target: DListItem<Tag>,
{
#[inline(always)]
pub fn new() -> Self {
DLinkedList { length: 0, head: null_mut(), tail: null_mut(), _phan: Default::default() }
}
#[inline]
pub fn clear(&mut self) {
while self.pop_front().is_some() {}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.length
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.length == 0
}
#[inline(always)]
fn _remove_node(&mut self, item: *mut u8) -> bool {
let mut removed = false;
unsafe {
let node = <P::Target as DListItem<Tag>>::get_node_from_ptr(item);
if !node.prev.is_null() {
<P::Target as DListItem<Tag>>::get_node_from_ptr(node.prev).next = node.next;
removed = true;
} else if self.head == item {
self.head = node.next;
removed = true;
}
if !node.next.is_null() {
<P::Target as DListItem<Tag>>::get_node_from_ptr(node.next).prev = node.prev;
removed = true;
} else if self.tail == item {
self.tail = node.prev;
removed = true;
}
if removed {
node.next = null_mut();
node.prev = null_mut();
self.length -= 1;
}
}
removed
}
#[inline(always)]
pub unsafe fn remove_node(&mut self, item: *const P::Target) -> Option<P> {
unsafe { if self._remove_node(item as *mut u8) { Some(P::from_raw(item)) } else { None } }
}
#[inline(always)]
pub unsafe fn peak(&mut self, item: *const P::Target) {
assert!(!self.head.is_null());
if !ptr::eq(self.head, item as *mut u8) {
assert!(self._remove_node(item as *mut u8), "item is not in the list");
self.push_front_ptr(item);
}
}
#[inline]
pub fn push_front(&mut self, item: P) {
let ptr = item.into_raw();
self.push_front_ptr(ptr);
}
#[inline]
fn push_front_ptr(&mut self, ptr: *const P::Target) {
let node = unsafe { <P::Target as DListItem<Tag>>::get_node_from_ptr(ptr as *mut u8) };
let head = self.head;
node.next = head;
node.prev = null_mut();
if head.is_null() {
self.tail = ptr as *mut u8;
} else {
unsafe {
<P::Target as DListItem<Tag>>::get_node_from_ptr(head).prev = ptr as *mut u8;
}
}
self.head = ptr as *mut u8;
self.length += 1;
}
#[inline]
pub fn push_back(&mut self, item: P) {
let tail = self.tail;
let ptr = item.into_raw() as *mut u8;
unsafe {
let node = <P::Target as DListItem<Tag>>::get_node_from_ptr(ptr);
node.prev = tail;
node.next = null_mut();
if tail.is_null() {
self.head = ptr;
} else {
<P::Target as DListItem<Tag>>::get_node_from_ptr(tail).next = ptr;
}
}
self.tail = ptr;
self.length += 1;
}
pub fn pop_front(&mut self) -> Option<P> {
if !self.head.is_null() {
let head_ptr = self.head;
unsafe {
self._remove_node(head_ptr);
Some(P::from_raw(head_ptr as *const P::Target))
}
} else {
None
}
}
#[inline]
pub fn pop_back(&mut self) -> Option<P> {
if !self.tail.is_null() {
let tail_ptr = self.tail;
unsafe {
self._remove_node(tail_ptr);
Some(P::from_raw(tail_ptr as *const P::Target))
}
} else {
None
}
}
#[inline]
pub fn get_front_ptr(&self) -> *const P::Target {
self.head as *const P::Target
}
#[inline]
pub fn get_front(&self) -> Option<&P::Target> {
unsafe {
if !self.head.is_null() { Some(&(*(self.head as *const P::Target))) } else { None }
}
}
#[inline]
pub fn get_back_ptr(&self) -> *const P::Target {
self.tail as *const P::Target
}
#[inline]
pub fn get_back(&self) -> Option<&P::Target> {
unsafe {
if !self.tail.is_null() { Some(&(*(self.tail as *const P::Target))) } else { None }
}
}
#[inline(always)]
pub fn is_front(&self, node: &P::Target) -> bool {
if self.head.is_null() {
false
} else {
ptr::eq(self.head, node as *const P::Target as *mut u8)
}
}
#[inline(always)]
pub fn iter<'a>(&'a self) -> DLinkedListIter<'a, P, Tag> {
DLinkedListIter {
next_p: self.head,
len: self.len(),
_phan: Default::default(),
cur: MaybeUninit::uninit(),
}
}
#[inline(always)]
pub fn drain<'a>(&'a mut self) -> DLinkedListDrainer<'a, P, Tag> {
DLinkedListDrainer { list: self, _phan: Default::default() }
}
}
impl<P, Tag> Drop for DLinkedList<P, Tag>
where
P: Pointer,
P::Target: DListItem<Tag>,
{
fn drop(&mut self) {
if mem::needs_drop::<P>() {
self.drain().for_each(drop);
}
}
}
pub struct DLinkedListIter<'a, P, Tag>
where
P: Pointer,
P::Target: DListItem<Tag>,
{
next_p: *mut u8,
cur: MaybeUninit<P>,
len: usize,
_phan: PhantomData<&'a DLinkedList<P, Tag>>,
}
unsafe impl<'a, P, Tag> Send for DLinkedListIter<'a, P, Tag>
where
P: Pointer,
P::Target: DListItem<Tag>,
{
}
impl<'a, P, Tag> Iterator for DLinkedListIter<'a, P, Tag>
where
P: Pointer,
P::Target: DListItem<Tag>,
{
type Item = &'a P;
#[inline]
fn next(&mut self) -> Option<&'a P> {
if !self.next_p.is_null() {
self.len -= 1;
let cur = self.next_p;
unsafe {
self.next_p = <P::Target as DListItem<Tag>>::get_node_from_ptr(cur).next;
self.cur.write(P::from_raw(cur as *const P::Target));
return Some(mem::transmute::<&P, &P>(self.cur.assume_init_ref()));
}
}
None
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<'a, P, Tag> ExactSizeIterator for DLinkedListIter<'a, P, Tag>
where
P: Pointer,
P::Target: DListItem<Tag>,
{
}
pub type DLinkedListDrainer<'a, P, Tag> = Drainer<&'a mut DLinkedList<P, Tag>, P, Tag>;
pub type DLinkedListIntoIter<P, Tag> = Drainer<DLinkedList<P, Tag>, P, Tag>;
pub struct Drainer<L, P, Tag>
where
L: BorrowMut<DLinkedList<P, Tag>>,
P: Pointer,
P::Target: DListItem<Tag>,
{
list: L,
_phan: PhantomData<(P, Tag)>,
}
impl<L, P, Tag> Iterator for Drainer<L, P, Tag>
where
L: BorrowMut<DLinkedList<P, Tag>>,
P: Pointer,
P::Target: DListItem<Tag>,
{
type Item = P;
#[inline]
fn next(&mut self) -> Option<P> {
self.list.borrow_mut().pop_front()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let l = self.list.borrow().len();
(l, Some(l))
}
}
impl<L, P, Tag> ExactSizeIterator for Drainer<L, P, Tag>
where
L: BorrowMut<DLinkedList<P, Tag>>,
P: Pointer,
P::Target: DListItem<Tag>,
{
}
impl<'a, P, Tag> IntoIterator for &'a DLinkedList<P, Tag>
where
P: Pointer,
P::Target: DListItem<Tag>,
{
type Item = &'a P;
type IntoIter = DLinkedListIter<'a, P, Tag>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<P, Tag> IntoIterator for DLinkedList<P, Tag>
where
P: Pointer,
P::Target: DListItem<Tag>,
{
type Item = P;
type IntoIter = DLinkedListIntoIter<P, Tag>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
Drainer { list: self, _phan: Default::default() }
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::boxed::Box;
use std::cell::UnsafeCell;
use std::println;
use std::ptr::NonNull;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
pub struct TestTag;
#[derive(Debug)]
pub struct TestNode {
pub value: i64,
pub node: UnsafeCell<DListNode<TestTag>>,
}
static ACTIVE_NODE_COUNT: AtomicUsize = AtomicUsize::new(0);
impl Drop for TestNode {
fn drop(&mut self) {
ACTIVE_NODE_COUNT.fetch_sub(1, Ordering::SeqCst);
}
}
unsafe impl Send for TestNode {}
unsafe impl DListItem<TestTag> for TestNode {
fn get_node(&self) -> &mut DListNode<TestTag> {
unsafe { &mut *self.node.get() }
}
}
fn new_node(v: i64) -> TestNode {
ACTIVE_NODE_COUNT.fetch_add(1, Ordering::SeqCst);
TestNode { value: v, node: UnsafeCell::new(DListNode::default()) }
}
#[test]
fn test_push_back_box() {
let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
let node1 = Box::new(new_node(1));
l.push_back(node1);
let node2 = Box::new(new_node(2));
l.push_back(node2);
let node3 = Box::new(new_node(3));
l.push_back(node3);
assert_eq!(3, l.len());
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().value, 1);
assert_eq!(iter.next().unwrap().value, 2);
assert_eq!(iter.next().unwrap().value, 3);
assert!(iter.next().is_none());
{
let mut drain = l.drain();
assert_eq!(drain.next().unwrap().value, 1);
assert_eq!(drain.next().unwrap().value, 2);
assert_eq!(drain.next().unwrap().value, 3);
assert!(drain.next().is_none());
}
assert_eq!(l.len(), 0);
}
#[test]
fn test_push_back_arc() {
let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
let node1 = Arc::new(new_node(1));
l.push_back(node1);
let node2 = Arc::new(new_node(2));
l.push_back(node2);
let node3 = Arc::new(new_node(3));
l.push_back(node3);
assert_eq!(3, l.len());
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().value, 1);
assert_eq!(iter.next().unwrap().value, 2);
assert_eq!(iter.next().unwrap().value, 3);
assert!(iter.next().is_none());
{
let mut drain = l.drain();
assert_eq!(drain.next().unwrap().value, 1);
assert_eq!(drain.next().unwrap().value, 2);
assert_eq!(drain.next().unwrap().value, 3);
assert!(drain.next().is_none());
}
assert_eq!(l.len(), 0);
}
#[test]
fn test_push_front_box() {
let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
let node3 = Box::new(new_node(3));
l.push_front(node3);
let node2 = Box::new(new_node(2));
l.push_front(node2);
let node1 = Box::new(new_node(1));
l.push_front(node1);
assert_eq!(3, l.len());
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().value, 1);
assert_eq!(iter.next().unwrap().value, 2);
assert_eq!(iter.next().unwrap().value, 3);
assert!(iter.next().is_none());
{
let mut drain = l.drain();
assert_eq!(drain.next().unwrap().value, 1);
assert_eq!(drain.next().unwrap().value, 2);
assert_eq!(drain.next().unwrap().value, 3);
assert!(drain.next().is_none());
}
assert_eq!(l.len(), 0);
}
#[test]
fn test_push_front_arc() {
let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
let node3 = Arc::new(new_node(3));
l.push_front(node3);
let node2 = Arc::new(new_node(2));
l.push_front(node2);
let node1 = Arc::new(new_node(1));
l.push_front(node1);
assert_eq!(3, l.len());
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().value, 1);
assert_eq!(iter.next().unwrap().value, 2);
assert_eq!(iter.next().unwrap().value, 3);
assert!(iter.next().is_none());
{
let mut drain = l.drain();
assert_eq!(drain.next().unwrap().value, 1);
assert_eq!(drain.next().unwrap().value, 2);
assert_eq!(drain.next().unwrap().value, 3);
assert!(drain.next().is_none());
}
assert_eq!(l.len(), 0);
}
#[test]
fn test_pop_back_box() {
let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
let node1 = Box::new(new_node(1));
l.push_back(node1);
let node2 = Box::new(new_node(2));
l.push_back(node2);
let node3 = Box::new(new_node(3));
l.push_back(node3);
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().value, 1);
assert_eq!(iter.next().unwrap().value, 2);
assert_eq!(iter.next().unwrap().value, 3);
assert!(iter.next().is_none());
let del_node = l.pop_back();
assert_eq!(2, l.len());
assert!(del_node.is_some());
assert_eq!(del_node.unwrap().value, 3);
let mut iter_remaining = l.iter();
assert_eq!(iter_remaining.next().unwrap().value, 1);
assert_eq!(iter_remaining.next().unwrap().value, 2);
assert!(iter_remaining.next().is_none());
{
let mut drain = l.drain();
assert_eq!(drain.next().unwrap().value, 1);
assert_eq!(drain.next().unwrap().value, 2);
assert!(drain.next().is_none());
}
assert_eq!(l.len(), 0);
}
#[test]
fn test_pop_back_arc() {
let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
let node1 = Arc::new(new_node(1));
l.push_back(node1);
let node2 = Arc::new(new_node(2));
l.push_back(node2);
let node3 = Arc::new(new_node(3));
l.push_back(node3);
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().value, 1);
assert_eq!(iter.next().unwrap().value, 2);
assert_eq!(iter.next().unwrap().value, 3);
assert!(iter.next().is_none());
let del_node = l.pop_back();
assert_eq!(2, l.len());
assert!(del_node.is_some());
assert!(del_node.is_some());
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().value, 1);
assert_eq!(iter.next().unwrap().value, 2);
assert!(iter.next().is_none());
{
let mut drain = l.drain();
assert_eq!(drain.next().unwrap().value, 1);
assert_eq!(drain.next().unwrap().value, 2);
assert!(drain.next().is_none());
}
assert_eq!(l.len(), 0);
}
#[test]
fn test_pop_front_arc() {
let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
let node1 = Arc::new(new_node(1));
l.push_front(node1);
let node2 = Arc::new(new_node(2));
l.push_front(node2);
let node3 = Arc::new(new_node(3));
l.push_front(node3);
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().value, 3);
assert_eq!(iter.next().unwrap().value, 2);
assert_eq!(iter.next().unwrap().value, 1);
assert!(iter.next().is_none());
let del_node = l.pop_front();
assert_eq!(2, l.len());
assert!(del_node.is_some());
assert!(del_node.is_some());
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().value, 2);
assert_eq!(iter.next().unwrap().value, 1);
assert!(iter.next().is_none());
{
assert_eq!(l.pop_front().unwrap().value, 2);
assert_eq!(l.pop_front().unwrap().value, 1);
assert!(l.pop_front().is_none());
assert!(l.pop_back().is_none());
}
assert_eq!(l.len(), 0);
}
#[test]
fn test_iter_box() {
let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
let mut count = 0;
for _item in l.iter() {
count += 1;
}
assert_eq!(count, 0);
let node1 = Box::new(new_node(1));
l.push_back(node1);
let node2 = Box::new(new_node(2));
l.push_back(node2);
let node3 = Box::new(new_node(3));
l.push_back(node3);
count = 0;
for item in l.iter() {
count += 1;
println!("{}", item.value);
}
assert_eq!(count, 3);
{
let mut drain = l.drain();
assert_eq!(drain.next().unwrap().value, 1);
assert_eq!(drain.next().unwrap().value, 2);
assert_eq!(drain.next().unwrap().value, 3);
assert!(drain.next().is_none());
}
assert_eq!(l.len(), 0);
}
#[test]
fn test_iter_arc() {
let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
let mut count = 0;
for _item in l.iter() {
count += 1;
}
assert_eq!(count, 0);
let node1 = Arc::new(new_node(1));
l.push_back(node1);
let node2 = Arc::new(new_node(2));
l.push_back(node2);
let node3 = Arc::new(new_node(3));
l.push_back(node3);
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().value, 1);
assert_eq!(iter.next().unwrap().value, 2);
assert_eq!(iter.next().unwrap().value, 3);
assert!(iter.next().is_none());
{
let mut drain = l.drain();
assert_eq!(drain.next().unwrap().value, 1);
assert_eq!(drain.next().unwrap().value, 2);
assert_eq!(drain.next().unwrap().value, 3);
assert!(drain.next().is_none());
}
assert_eq!(l.len(), 0);
}
#[test]
fn test_single_element_box() {
let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
let node1 = Box::new(new_node(1));
l.push_front(node1);
let del_node = l.pop_back();
assert!(del_node.is_some());
assert_eq!(del_node.unwrap().value, 1);
assert_eq!(0, l.len());
assert!(l.pop_back().is_none());
let mut l2 = DLinkedList::<Box<TestNode>, TestTag>::new();
let node2 = Box::new(new_node(2));
l2.push_back(node2);
let del_node2 = l2.pop_back();
assert!(del_node2.is_some());
assert_eq!(del_node2.unwrap().value, 2);
assert_eq!(0, l2.len());
assert!(l2.pop_back().is_none());
{
let mut drain = l.drain();
assert!(drain.next().is_none());
}
assert_eq!(l.len(), 0);
{
let mut drain = l2.drain();
assert!(drain.next().is_none());
}
assert_eq!(l2.len(), 0);
}
#[test]
fn test_single_element_arc() {
let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
let node1 = Arc::new(new_node(1));
l.push_front(node1);
let del_node = l.pop_back();
assert!(del_node.is_some());
assert_eq!(0, l.len());
assert!(l.pop_back().is_none());
let mut l2 = DLinkedList::<Arc<TestNode>, TestTag>::new();
let node2 = Arc::new(new_node(2));
l2.push_back(node2);
let del_node2 = l2.pop_back();
assert!(del_node2.is_some());
assert_eq!(0, l2.len());
assert!(l2.pop_back().is_none());
{
let mut drain = l.drain();
assert!(drain.next().is_none());
}
assert_eq!(l.len(), 0);
{
let mut drain = l2.drain();
assert!(drain.next().is_none());
}
assert_eq!(l2.len(), 0);
}
#[test]
fn test_drop_box_implementation() {
ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
{
let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
let node1 = Box::new(new_node(1));
l.push_back(node1);
let node2 = Box::new(new_node(2));
l.push_back(node2);
let node3 = Box::new(new_node(3));
l.push_back(node3);
assert_eq!(l.len(), 3);
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 3);
}
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
}
#[test]
fn test_raw_pointer_list() {
ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
let node1 = Box::into_raw(Box::new(new_node(10)));
let node2 = Box::into_raw(Box::new(new_node(20)));
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
unsafe {
let mut l = DLinkedList::<*const TestNode, TestTag>::new();
l.push_back(node1);
l.push_back(node2);
let mut iter = l.iter();
let item = iter.next().unwrap();
assert_eq!((**item).value, 10);
let item = iter.next().unwrap();
assert_eq!((**item).value, 20);
assert!(iter.next().is_none());
}
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
unsafe {
assert_eq!((*node1).value, 10);
assert_eq!((*node2).value, 20);
drop(Box::from_raw(node1));
drop(Box::from_raw(node2));
}
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
}
#[test]
fn test_non_null_list() {
ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
let node1 = Box::leak(Box::new(new_node(100)));
let node2 = Box::leak(Box::new(new_node(200)));
let ptr1 = NonNull::from(node1);
let ptr2 = NonNull::from(node2);
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
unsafe {
let mut l = DLinkedList::<NonNull<TestNode>, TestTag>::new();
l.push_back(ptr1);
l.push_back(ptr2);
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().as_ref().value, 100);
assert_eq!(iter.next().unwrap().as_ref().value, 200);
assert!(iter.next().is_none());
}
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
unsafe {
drop(Box::from_raw(ptr1.as_ptr()));
drop(Box::from_raw(ptr2.as_ptr()));
}
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
}
#[test]
fn test_clear() {
ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
l.push_back(Box::new(new_node(1)));
l.push_back(Box::new(new_node(2)));
assert_eq!(l.len(), 2);
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
l.clear();
assert!(l.is_empty());
assert_eq!(l.len(), 0);
assert!(l.get_front().is_none());
assert!(l.get_back().is_none());
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
l.push_back(Box::new(new_node(3)));
assert_eq!(l.len(), 1);
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 1);
}
#[test]
fn test_remove_middle() {
ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
{
let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
let node1 = Box::new(new_node(1));
l.push_back(node1);
let node2 = Box::new(new_node(2));
let node2_p = Box::into_raw(node2);
l.push_back(unsafe { Box::from_raw(node2_p) });
let node3 = Box::new(new_node(3));
l.push_back(node3);
assert_eq!(l.len(), 3);
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 3);
let node2 = unsafe { l.remove_node(node2_p).unwrap() };
assert_eq!(l.len(), 2);
assert_eq!(node2.value, 2);
let node4 = Box::new(new_node(4));
let node4_p = Box::into_raw(node4);
assert!(unsafe { l.remove_node(node4_p) }.is_none());
unsafe {
let _ = Box::from_raw(node4_p);
}
}
assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
}
#[test]
fn test_peak_arc() {
let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
let node1 = Arc::new(new_node(1));
l.push_back(node1);
let node2 = Arc::new(new_node(2));
l.push_back(node2);
let node3 = Arc::new(new_node(3));
l.push_back(node3.clone());
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().value, 1);
assert_eq!(iter.next().unwrap().value, 2);
assert_eq!(iter.next().unwrap().value, 3);
assert!(iter.next().is_none());
let node3_p = Arc::as_ptr(&node3);
unsafe { l.peak(node3_p) };
let mut iter = l.iter();
assert_eq!(iter.next().unwrap().value, 3);
assert_eq!(iter.next().unwrap().value, 1);
assert_eq!(iter.next().unwrap().value, 2);
assert!(iter.next().is_none());
{
let mut drain = l.drain();
assert_eq!(drain.next().unwrap().value, 3);
assert_eq!(drain.next().unwrap().value, 1);
assert_eq!(drain.next().unwrap().value, 2);
assert!(drain.next().is_none());
}
assert_eq!(l.len(), 0);
}
}