use crate::id;
use crate::util::abort;
use crate::util::debug_unreachable;
use crate::util::run_on_drop;
use crate::util::ConstFnBounds;
use crate::Id;
use crate::InitializedNode;
use crate::Node;
use core::cell::UnsafeCell;
use core::fmt;
use core::fmt::Debug;
use core::fmt::Formatter;
use core::mem;
use core::mem::align_of;
use core::mem::transmute;
use core::pin::Pin;
use core::ptr;
use core::ptr::NonNull;
pub trait Types {
type Id: Id;
type Protected;
type Removed;
type Unprotected;
}
pub struct PinList<T: ?Sized + Types> {
pub(crate) id: T::Id,
head: OptionNodeShared<T>,
tail: OptionNodeShared<T>,
}
pub(crate) struct OptionNodeShared<T: ?Sized + Types>(NonNull<NodeShared<T>>);
impl<T: ?Sized + Types> OptionNodeShared<T> {
pub(crate) const NONE: Self = Self(Self::SENTINEL);
pub(crate) fn some(ptr: NonNull<NodeShared<T>>) -> Self {
Self(ptr)
}
pub(crate) fn get(self) -> Option<NonNull<NodeShared<T>>> {
(self.0 != Self::SENTINEL).then(|| self.0)
}
const SENTINEL: NonNull<NodeShared<T>> = {
assert!(2 <= align_of::<NodeShared<T>>());
#[allow(clippy::useless_transmute)]
unsafe {
NonNull::new_unchecked(transmute::<usize, *mut NodeShared<T>>(1))
}
};
}
impl<T: ?Sized + Types> Clone for OptionNodeShared<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized + Types> Copy for OptionNodeShared<T> {}
pub(crate) struct NodeShared<T: ?Sized + Types> {
pub(crate) protected: UnsafeCell<NodeProtected<T>>,
pub(crate) unprotected: T::Unprotected,
}
pub(crate) enum NodeProtected<T: ?Sized + Types> {
Linked(NodeLinked<T>),
Removed(NodeRemoved<T>),
}
pub(crate) struct NodeLinked<T: ?Sized + Types> {
pub(crate) prev: OptionNodeShared<T>,
pub(crate) next: OptionNodeShared<T>,
pub(crate) data: T::Protected,
}
pub(crate) struct NodeRemoved<T: ?Sized + Types> {
pub(crate) data: T::Removed,
}
unsafe impl<T: ?Sized + Types> Send for PinList<T>
where
T::Id: Send,
T::Protected: Send,
T::Removed: Send,
T::Unprotected: Sync,
{
}
unsafe impl<T: ?Sized + Types> Sync for PinList<T>
where
T::Id: Sync,
T::Protected: Send + Sync,
T::Removed: Send,
T::Unprotected: Sync,
{
}
impl<T: ?Sized> PinList<T>
where
<T as ConstFnBounds>::Type: Types,
{
#[must_use]
pub const fn new(id: id::Unique<<<T as ConstFnBounds>::Type as Types>::Id>) -> Self {
Self {
id: id.into_inner(),
head: OptionNodeShared::NONE,
tail: OptionNodeShared::NONE,
}
}
}
impl<T: ?Sized + Types> PinList<T> {
#[must_use]
pub fn is_empty(&self) -> bool {
debug_assert_eq!(self.head.get().is_some(), self.tail.get().is_some());
self.head.get().is_none()
}
pub(crate) unsafe fn cursor(&self, current: OptionNodeShared<T>) -> Cursor<'_, T> {
Cursor {
list: self,
current,
}
}
pub(crate) unsafe fn cursor_mut(&mut self, current: OptionNodeShared<T>) -> CursorMut<'_, T> {
CursorMut {
list: self,
current,
}
}
#[must_use]
pub fn cursor_ghost(&self) -> Cursor<'_, T> {
unsafe { self.cursor(OptionNodeShared::NONE) }
}
#[must_use]
pub fn cursor_front(&self) -> Cursor<'_, T> {
let mut cursor = self.cursor_ghost();
cursor.move_next();
cursor
}
#[must_use]
pub fn cursor_back(&self) -> Cursor<'_, T> {
let mut cursor = self.cursor_ghost();
cursor.move_previous();
cursor
}
#[must_use]
pub fn cursor_ghost_mut(&mut self) -> CursorMut<'_, T> {
unsafe { self.cursor_mut(OptionNodeShared::NONE) }
}
#[must_use]
pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T> {
let mut cursor = self.cursor_ghost_mut();
cursor.move_next();
cursor
}
#[must_use]
pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T> {
let mut cursor = self.cursor_ghost_mut();
cursor.move_previous();
cursor
}
pub fn push_front<'node>(
&mut self,
node: Pin<&'node mut Node<T>>,
protected: T::Protected,
unprotected: T::Unprotected,
) -> Pin<&'node mut InitializedNode<'node, T>> {
self.cursor_ghost_mut()
.insert_after(node, protected, unprotected)
}
pub fn push_back<'node>(
&mut self,
node: Pin<&'node mut Node<T>>,
protected: T::Protected,
unprotected: T::Unprotected,
) -> Pin<&'node mut InitializedNode<'node, T>> {
self.cursor_ghost_mut()
.insert_before(node, protected, unprotected)
}
}
#[allow(clippy::missing_fields_in_debug)]
impl<T: ?Sized + Types> Debug for PinList<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("PinList").field("id", &self.id).finish()
}
}
pub struct Cursor<'list, T: ?Sized + Types> {
list: &'list PinList<T>,
current: OptionNodeShared<T>,
}
unsafe impl<T: ?Sized + Types> Send for Cursor<'_, T> where
PinList<T>: Sync
{
}
unsafe impl<T: ?Sized + Types> Sync for Cursor<'_, T> where
PinList<T>: Sync
{
}
impl<'list, T: ?Sized + Types> Cursor<'list, T> {
fn current_shared(&self) -> Option<&'list NodeShared<T>> {
self.current
.get()
.map(|current| unsafe { current.as_ref() })
}
fn current_protected(&self) -> Option<&'list NodeProtected<T>> {
Some(unsafe { &*self.current_shared()?.protected.get() })
}
fn current_linked(&self) -> Option<&'list NodeLinked<T>> {
match self.current_protected()? {
NodeProtected::Linked(linked) => Some(linked),
NodeProtected::Removed(..) => unsafe { debug_unreachable!() },
}
}
pub fn move_next(&mut self) {
self.current = match self.current_linked() {
Some(linked) => linked.next,
None => self.list.head,
};
}
pub fn move_previous(&mut self) {
self.current = match self.current_linked() {
Some(linked) => linked.prev,
None => self.list.tail,
};
}
#[must_use]
pub fn list(&self) -> &'list PinList<T> {
self.list
}
#[must_use]
pub fn protected(&self) -> Option<&'list T::Protected> {
Some(&self.current_linked()?.data)
}
#[must_use]
pub fn unprotected(&self) -> Option<&'list T::Unprotected> {
Some(&self.current_shared()?.unprotected)
}
}
impl<T: ?Sized + Types> Clone for Cursor<'_, T> {
fn clone(&self) -> Self {
Self {
list: self.list,
current: self.current,
}
}
}
impl<T: ?Sized + Types> Debug for Cursor<'_, T>
where
T::Unprotected: Debug,
T::Protected: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Cursor")
.field("list", &self.list)
.field("protected", &self.protected())
.field("unprotected", &self.unprotected())
.finish()
}
}
pub struct CursorMut<'list, T: ?Sized + Types> {
pub(crate) list: &'list mut PinList<T>,
pub(crate) current: OptionNodeShared<T>,
}
unsafe impl<T: ?Sized + Types> Send for CursorMut<'_, T> where
PinList<T>: Send
{
}
unsafe impl<T: ?Sized + Types> Sync for CursorMut<'_, T> where
PinList<T>: Sync
{
}
impl<'list, T: ?Sized + Types> CursorMut<'list, T> {
fn current_shared(&self) -> Option<&NodeShared<T>> {
self.current
.get()
.map(|current| unsafe { current.as_ref() })
}
fn current_protected(&self) -> Option<&NodeProtected<T>> {
Some(unsafe { &*self.current_shared()?.protected.get() })
}
fn current_protected_mut(&mut self) -> Option<&mut NodeProtected<T>> {
Some(unsafe { &mut *self.current_shared()?.protected.get() })
}
fn current_linked(&self) -> Option<&NodeLinked<T>> {
match self.current_protected()? {
NodeProtected::Linked(linked) => Some(linked),
NodeProtected::Removed(..) => unsafe { debug_unreachable!() },
}
}
fn current_linked_mut(&mut self) -> Option<&mut NodeLinked<T>> {
match self.current_protected_mut()? {
NodeProtected::Linked(linked) => Some(linked),
NodeProtected::Removed(..) => unsafe { debug_unreachable!() },
}
}
pub(crate) fn prev_mut(&mut self) -> &mut OptionNodeShared<T> {
match self.current.get() {
Some(_) => &mut self.current_linked_mut().unwrap().prev,
None => &mut self.list.tail,
}
}
pub(crate) fn next_mut(&mut self) -> &mut OptionNodeShared<T> {
match self.current.get() {
Some(_) => &mut self.current_linked_mut().unwrap().next,
None => &mut self.list.head,
}
}
#[must_use]
pub fn into_shared(self) -> Cursor<'list, T> {
Cursor {
list: self.list,
current: self.current,
}
}
#[must_use]
pub fn as_shared(&self) -> Cursor<'_, T> {
Cursor {
list: self.list,
current: self.current,
}
}
pub fn move_next(&mut self) {
self.current = *self.next_mut();
}
pub fn move_previous(&mut self) {
self.current = *self.prev_mut();
}
#[must_use]
pub fn list(&self) -> &PinList<T> {
self.list
}
#[must_use]
pub fn protected(&self) -> Option<&T::Protected> {
Some(&self.current_linked()?.data)
}
#[must_use]
pub fn protected_mut(&mut self) -> Option<&mut T::Protected> {
Some(&mut self.current_linked_mut()?.data)
}
#[must_use]
pub fn unprotected(&self) -> Option<&T::Unprotected> {
Some(&self.current_shared()?.unprotected)
}
pub fn insert_before<'node>(
&mut self,
node: Pin<&'node mut Node<T>>,
protected: T::Protected,
unprotected: T::Unprotected,
) -> Pin<&'node mut InitializedNode<'node, T>> {
node.insert_before(self, protected, unprotected)
}
pub fn insert_after<'node>(
&mut self,
node: Pin<&'node mut Node<T>>,
protected: T::Protected,
unprotected: T::Unprotected,
) -> Pin<&'node mut InitializedNode<'node, T>> {
node.insert_after(self, protected, unprotected)
}
pub fn push_front<'node>(
&mut self,
node: Pin<&'node mut Node<T>>,
protected: T::Protected,
unprotected: T::Unprotected,
) -> Pin<&'node mut InitializedNode<'node, T>> {
self.list.push_front(node, protected, unprotected)
}
pub fn push_back<'node>(
&mut self,
node: Pin<&'node mut Node<T>>,
protected: T::Protected,
unprotected: T::Unprotected,
) -> Pin<&'node mut InitializedNode<'node, T>> {
self.list.push_back(node, protected, unprotected)
}
pub fn remove_current(&mut self, removed: T::Removed) -> Result<T::Protected, T::Removed> {
let mut res = Err(removed);
self.remove_current_with(|protected| match mem::replace(&mut res, Ok(protected)) {
Ok(..) => unsafe { debug_unreachable!() },
Err(removed) => removed,
});
res
}
pub fn remove_current_with<F>(&mut self, f: F) -> bool
where
F: FnOnce(T::Protected) -> T::Removed,
{
self.remove_current_with_or(f, || abort())
}
pub fn remove_current_with_or<F, Fallback>(&mut self, f: F, fallback: Fallback) -> bool
where
F: FnOnce(T::Protected) -> T::Removed,
Fallback: FnOnce() -> T::Removed,
{
let protected: *mut NodeProtected<T> = match self.current_protected_mut() {
Some(protected) => protected,
None => return false,
};
let old = match unsafe { ptr::read(protected) } {
NodeProtected::Linked(linked) => linked,
NodeProtected::Removed(..) => unsafe { debug_unreachable!() },
};
*unsafe { self.list.cursor_mut(old.prev) }.next_mut() = old.next;
*unsafe { self.list.cursor_mut(old.next) }.prev_mut() = old.prev;
self.current = old.next;
let guard = run_on_drop(|| {
let removed = NodeRemoved { data: fallback() };
unsafe { ptr::write(protected, NodeProtected::Removed(removed)) };
});
let removed = NodeRemoved { data: f(old.data) };
unsafe { ptr::write(protected, NodeProtected::Removed(removed)) };
mem::forget(guard);
true
}
}
impl<T: ?Sized + Types> Debug for CursorMut<'_, T>
where
T::Unprotected: Debug,
T::Protected: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("CursorMut")
.field("list", &self.list)
.field("protected", &self.protected())
.field("unprotected", &self.unprotected())
.finish()
}
}