use crate::cell::UnsafeCell;
use core::fmt;
use core::marker::{PhantomData, PhantomPinned};
use core::mem::ManuallyDrop;
use core::ptr::{self, NonNull};
pub(crate) struct LinkedList<L, T> {
head: Option<NonNull<T>>,
tail: Option<NonNull<T>>,
_marker: PhantomData<*const L>,
}
unsafe impl<L: Link> Send for LinkedList<L, L::Target> where L::Target: Send {}
unsafe impl<L: Link> Sync for LinkedList<L, L::Target> where L::Target: Sync {}
pub(crate) unsafe trait Link {
type Handle;
type Target;
#[allow(clippy::wrong_self_convention)]
fn as_raw(handle: &Self::Handle) -> NonNull<Self::Target>;
unsafe fn from_raw(ptr: NonNull<Self::Target>) -> Self::Handle;
unsafe fn pointers(target: NonNull<Self::Target>) -> NonNull<Pointers<Self::Target>>;
}
pub(crate) struct Pointers<T> {
inner: UnsafeCell<PointersInner<T>>,
}
#[repr(C)]
struct PointersInner<T> {
#[allow(dead_code)]
prev: Option<NonNull<T>>,
#[allow(dead_code)]
next: Option<NonNull<T>>,
_pin: PhantomPinned,
}
unsafe impl<T: Send> Send for Pointers<T> {}
unsafe impl<T: Sync> Sync for Pointers<T> {}
pub(crate) struct Iter<'a, T: Link> {
_list: &'a LinkedList<T, T::Target>,
curr: Option<NonNull<T::Target>>,
}
impl<L, T> LinkedList<L, T> {
pub(crate) const fn new() -> LinkedList<L, T> {
LinkedList {
head: None,
tail: None,
_marker: PhantomData,
}
}
pub(crate) fn iter(&self) -> Iter<'_, L>
where
L: Link<Target = T>,
{
Iter {
_list: self,
curr: self.head,
}
}
}
impl<L: Link> LinkedList<L, L::Target> {
pub(crate) fn push_front(&mut self, val: L::Handle) {
let val = ManuallyDrop::new(val);
let ptr = L::as_raw(&val);
assert_ne!(self.head, Some(ptr));
unsafe {
L::pointers(ptr).as_mut().set_next(self.head);
L::pointers(ptr).as_mut().set_prev(None);
if let Some(head) = self.head {
L::pointers(head).as_mut().set_prev(Some(ptr));
}
self.head = Some(ptr);
if self.tail.is_none() {
self.tail = Some(ptr);
}
}
}
pub(crate) unsafe fn remove(&mut self, node: NonNull<L::Target>) -> Option<L::Handle> {
if let Some(prev) = L::pointers(node).as_ref().get_prev() {
debug_assert_eq!(L::pointers(prev).as_ref().get_next(), Some(node));
L::pointers(prev)
.as_mut()
.set_next(L::pointers(node).as_ref().get_next());
} else {
if self.head != Some(node) {
return None;
}
self.head = L::pointers(node).as_ref().get_next();
}
if let Some(next) = L::pointers(node).as_ref().get_next() {
debug_assert_eq!(L::pointers(next).as_ref().get_prev(), Some(node));
L::pointers(next)
.as_mut()
.set_prev(L::pointers(node).as_ref().get_prev());
} else {
if self.tail != Some(node) {
return None;
}
self.tail = L::pointers(node).as_ref().get_prev();
}
L::pointers(node).as_mut().set_next(None);
L::pointers(node).as_mut().set_prev(None);
Some(L::from_raw(node))
}
}
impl<L: Link> fmt::Debug for LinkedList<L, L::Target> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LinkedList")
.field("head", &self.head)
.field("tail", &self.tail)
.finish()
}
}
impl<T> Pointers<T> {
pub(crate) fn new() -> Pointers<T> {
Pointers {
inner: UnsafeCell::new(PointersInner {
prev: None,
next: None,
_pin: PhantomPinned,
}),
}
}
pub(crate) fn get_prev(&self) -> Option<NonNull<T>> {
unsafe {
self.inner.with(|inner| {
let prev = inner as *const Option<NonNull<T>>;
ptr::read(prev)
})
}
}
pub(crate) fn get_next(&self) -> Option<NonNull<T>> {
unsafe {
self.inner.with(|inner| {
let prev = inner as *const Option<NonNull<T>>;
let next = prev.add(1);
ptr::read(next)
})
}
}
fn set_prev(&mut self, value: Option<NonNull<T>>) {
unsafe {
self.inner.with_mut(|inner| {
let prev = inner as *mut Option<NonNull<T>>;
ptr::write(prev, value);
});
}
}
fn set_next(&mut self, value: Option<NonNull<T>>) {
unsafe {
self.inner.with_mut(|inner| {
let prev = inner as *mut Option<NonNull<T>>;
let next = prev.add(1);
ptr::write(next, value);
});
}
}
}
impl<T> fmt::Debug for Pointers<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let prev = self.get_prev();
let next = self.get_next();
f.debug_struct("Pointers")
.field("prev", &prev)
.field("next", &next)
.finish()
}
}
impl<'a, T> Iterator for Iter<'a, T>
where
T: Link,
{
type Item = T::Handle;
fn next(&mut self) -> Option<Self::Item> {
let curr = self.curr;
self.curr = curr.and_then(|curr| unsafe { T::pointers(curr).as_ref() }.get_next());
curr.map(|curr| unsafe { T::from_raw(curr) })
}
}