use core::ptr;
use core::ptr::NonNull;
use core::cell::Cell;
use core::pin::Pin;
pub trait PtrCell<T> {
fn get(&self) -> *const T;
fn set(&self, ptr: *const T);
fn default() -> Self;
unsafe fn get_node<L: LinkedList<NodePtr = Self> + ?Sized>(&self) -> *const Node<L>
where Self: PtrCell<L::NodeItem> + Sized
{
let n : *const L::NodeItem = self.get();
if n.is_null() {
ptr::null()
} else {
L::node(unsafe { Pin::new_unchecked(&*n) }).get_ref() as *const _
}
}
}
impl<T> PtrCell<T> for Cell<*const T> {
fn get(&self) -> *const T { self.get() }
fn set(&self, ptr: *const T) { self.set(ptr) }
fn default() -> Self { Cell::new(core::ptr::null()) }
}
pub trait LinkedList {
type NodeItem;
type NodePtr : PtrCell<Self::NodeItem>;
fn node(node: Pin<&Self::NodeItem>) -> Pin<&Node<Self>>;
}
pub struct Node<L: LinkedList + ?Sized> {
next: L::NodePtr,
prev: Cell<*const L::NodePtr>,
phantom: core::marker::PhantomPinned,
}
impl<L: LinkedList + ?Sized> Default for Node<L> {
fn default() -> Self {
Node {
next: L::NodePtr::default(),
prev: Cell::new(core::ptr::null()),
phantom: core::marker::PhantomPinned,
}
}
}
impl<L: LinkedList + ?Sized> Node<L> {
fn verify(&self) {
unsafe {
let n : *const Self = self.next.get_node();
debug_assert!(n.is_null() || ptr::eq((*n).prev.get(), &self.next as *const _));
let p = self.prev.get();
debug_assert!(!p.is_null() || ptr::eq( (*p).get_node(), self as *const _));
}
}
}
impl<L: LinkedList + ?Sized> Drop for Node<L> {
fn drop(&mut self) {
self.verify();
let prev = self.prev.get();
let next : *const Self = unsafe { self.next.get_node() };
if !next.is_null() {
unsafe { (*next).prev.set(prev) };
}
if !prev.is_null() {
unsafe { (*prev).set(self.next.get()) };
}
}
}
struct NodeIter<'a, L: LinkedList + ?Sized>(&'a L::NodePtr);
impl<'a, L: LinkedList + ?Sized> Iterator for NodeIter<L> {
type Item = NonNull<L::NodeItem>;
fn next(&mut self) -> Option<Self::Item> {
let r = NonNull::new(self.0);
r.as_ref()
.map(|n| unsafe { self.0 = L::next_ptr(*n).as_ref().next });
return r;
}
}
pub struct Head<L: LinkedList + ?Sized>(L::NodePtr);
impl<L: LinkedList + ?Sized> Default for Head<L> {
fn default() -> Self {
Head(ptr::null_mut())
}
}
impl<L: LinkedList + ?Sized> Head<L> {
pub unsafe fn append(&mut self, node: NonNull<L::NodeItem>) {
let mut node_node = L::next_ptr(node);
node_node.as_mut().next = self.0;
node_node.as_mut().prev = &mut self.0 as *mut *mut L::NodeItem;
if !self.0.is_null() {
L::next_ptr(NonNull::new_unchecked(self.0)).as_mut().prev =
&mut node_node.as_mut().next as *mut _
}
self.0 = node.as_ptr();
}
fn iter(&mut self) -> NodeIter<L> {
return NodeIter(self.0);
}
pub fn swap(&mut self, other: &mut Self) {
unsafe {
::std::mem::swap(&mut self.0, &mut other.0);
if !self.0.is_null() {
L::next_ptr(NonNull::new_unchecked(self.0)).as_mut().prev = self.0 as *mut _;
}
if !other.0.is_null() {
L::next_ptr(NonNull::new_unchecked(other.0)).as_mut().prev = other.0 as *mut _;
}
}
}
pub fn clear(&mut self) {
unsafe {
for x in self.iter() {
Box::from_raw(x.as_ptr());
}
}
}
}
impl<L: LinkedList + ?Sized> Iterator for Head<L> {
type Item = Box<L::NodeItem>;
fn next(&mut self) -> Option<Self::Item> {
NonNull::new(self.0).map(|n| unsafe {
let mut node_node = L::next_ptr(n);
self.0 = node_node.as_ref().next;
if !self.0.is_null() {
L::next_ptr(NonNull::new_unchecked(self.0)).as_mut().prev =
&mut self.0 as *mut _;
}
node_node.as_mut().prev = ::std::ptr::null_mut();
node_node.as_mut().next = ::std::ptr::null_mut();
Box::from_raw(n.as_ptr())
})
}
}
impl<L: LinkedList + ?Sized> Drop for Head<L> {
fn drop(&mut self) {
self.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
enum TestList {}
#[derive(Default)]
struct TestNode {
elem: u32,
list: Node<TestList>,
}
impl LinkedList for TestList {
type NodeItem = TestNode;
unsafe fn next_ptr(mut node: NonNull<Self::NodeItem>) -> NonNull<Node<Self>> {
NonNull::new_unchecked(&mut node.as_mut().list as *mut _)
}
}
impl TestNode {
fn new(v: u32) -> Self {
TestNode {
elem: v,
..Default::default()
}
}
}
#[test]
fn list_append() {
let mut l: Head<TestList> = Default::default();
assert_eq!(l.iter().count(), 0);
unsafe {
l.append(NonNull::new_unchecked(Box::into_raw(Box::new(
TestNode::new(10),
))));
}
assert_eq!(l.iter().count(), 1);
unsafe {
l.append(NonNull::new_unchecked(Box::into_raw(Box::new(
TestNode::new(20),
))));
}
assert_eq!(l.iter().count(), 2);
unsafe {
l.append(NonNull::new_unchecked(Box::into_raw(Box::new(
TestNode::new(30),
))));
}
assert_eq!(l.iter().count(), 3);
assert_eq!(
l.iter()
.map(|x| unsafe { x.as_ref().elem })
.collect::<Vec<u32>>(),
vec![30, 20, 10]
);
let ptr = l.iter().nth(1).unwrap();
assert_eq!(unsafe { ptr.as_ref().elem }, 20);
unsafe {
Box::from_raw(ptr.as_ptr());
}
assert_eq!(l.iter().count(), 2);
assert_eq!(
l.iter()
.map(|x| unsafe { x.as_ref().elem })
.collect::<Vec<u32>>(),
vec![30, 10]
);
}
}
*/