use crate::pin_list::Id;
use crate::pin_list::InitializedNode;
use crate::pin_list::Node;
use crate::pin_list::id;
use crate::pin_list::util::debug_unreachable;
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 Acquired;
type Released;
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_some(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>),
Acquired(NodeAcquired<T>),
Released(NodeReleased<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 NodeAcquired<T: ?Sized + Types> {
pub(crate) data: T::Acquired,
}
pub(crate) struct NodeReleased<T: ?Sized + Types> {
pub(crate) data: T::Released,
}
unsafe impl<T: ?Sized + Types> Send for PinList<T>
where
T::Id: Send,
T::Protected: Send,
T::Released: Send,
T::Unprotected: Sync,
{
}
unsafe impl<T: ?Sized + Types> Sync for PinList<T>
where
T::Id: Sync,
T::Protected: Send + Sync,
T::Released: Send,
T::Unprotected: Sync,
{
}
impl<T: ?Sized> PinList<T>
where
T: Types,
{
#[must_use]
pub const fn new(id: id::Unique<<T as Types>::Id>) -> Self {
Self {
id: id.into_inner(),
head: OptionNodeShared::NONE,
tail: OptionNodeShared::NONE,
}
}
}
impl<T: ?Sized + Types> PinList<T> {
pub(crate) unsafe fn cursor_mut(&mut self, current: OptionNodeShared<T>) -> CursorMut<'_, T> {
CursorMut {
list: self,
current,
}
}
#[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 acquire_front(
&mut self,
acquired: T::Acquired,
) -> Result<(<T as Types>::Protected, AcquiredNode<T>), <T as Types>::Acquired> {
self.cursor_front_mut().acquire_current(acquired)
}
pub fn push_back<'node>(
&mut self,
node: Pin<&'node mut Node<T>>,
protected: T::Protected,
) -> Pin<&'node mut InitializedNode<'node, T>> {
node.insert_before(&mut self.cursor_ghost_mut(), protected)
}
}
#[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 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<T: ?Sized + Types> CursorMut<'_, 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::Acquired(..) | NodeProtected::Released(..) => unsafe {
debug_unreachable!()
},
}
}
fn current_linked_mut(&mut self) -> Option<&mut NodeLinked<T>> {
match self.current_protected_mut()? {
NodeProtected::Linked(linked) => Some(linked),
NodeProtected::Acquired(..) | NodeProtected::Released(..) => 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,
}
}
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 unprotected(&self) -> Option<&T::Unprotected> {
Some(&self.current_shared()?.unprotected)
}
pub fn acquire_current(
&mut self,
acquired: T::Acquired,
) -> Result<(T::Protected, AcquiredNode<T>), T::Acquired> {
let protected: *mut NodeProtected<T> = match self.current_protected_mut() {
Some(x) => x,
None => return Err(acquired),
};
let old = match unsafe { ptr::read(protected) } {
NodeProtected::Linked(linked) => linked,
NodeProtected::Acquired(..) | NodeProtected::Released(..) => 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;
let acquired_node = self.current.0;
self.current = old.next;
let old_data = old.data;
let acquired = NodeAcquired { data: acquired };
unsafe { ptr::write(protected, NodeProtected::Acquired(acquired)) };
Ok((
old_data,
AcquiredNode {
node: acquired_node,
list_id: self.list.id,
},
))
}
}
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()
}
}
pub struct AcquiredNode<T: ?Sized + Types> {
pub(crate) list_id: T::Id,
pub(crate) node: NonNull<NodeShared<T>>,
}
unsafe impl<T: ?Sized + Types> Send for AcquiredNode<T> where
PinList<T>: Send
{
}
unsafe impl<T: ?Sized + Types> Sync for AcquiredNode<T> where
PinList<T>: Sync
{
}
impl<T: ?Sized + Types> AcquiredNode<T> {
fn current_shared(&self, list: &PinList<T>) -> &NodeShared<T> {
assert_eq!(self.list_id, list.id, "incorrect `PinList`");
unsafe { self.node.as_ref() }
}
fn current_protected(&self, list: &PinList<T>) -> &NodeProtected<T> {
unsafe { &*self.current_shared(list).protected.get() }
}
pub fn unprotected(&self, list: &PinList<T>) -> &T::Unprotected {
&self.current_shared(list).unprotected
}
pub fn acquired(&self, list: &PinList<T>) -> &T::Acquired {
match self.current_protected(list) {
NodeProtected::Acquired(node_acquired) => &node_acquired.data,
NodeProtected::Linked(..) | NodeProtected::Released(..) => unsafe {
debug_unreachable!()
},
}
}
fn current_protected_mut(self, list: &mut PinList<T>) -> &mut NodeProtected<T> {
unsafe { &mut *self.current_shared(list).protected.get() }
}
pub fn release_current(self, list: &mut PinList<T>, removed: T::Released) -> T::Acquired {
let protected: *mut NodeProtected<T> = self.current_protected_mut(list);
let old = match unsafe { ptr::read(protected) } {
NodeProtected::Acquired(acquired) => acquired,
NodeProtected::Linked(..) | NodeProtected::Released(..) => unsafe {
debug_unreachable!()
},
};
let old_data = old.data;
let removed = NodeReleased { data: removed };
unsafe { ptr::write(protected, NodeProtected::Released(removed)) };
old_data
}
pub fn insert_after(
self,
cursor: &mut CursorMut<'_, T>,
protected: T::Protected,
) -> T::Acquired {
let node = self.node;
let next = *cursor.next_mut();
let shared = self.current_protected_mut(cursor.list);
let linked = NodeProtected::Linked(NodeLinked {
prev: cursor.current,
next,
data: protected,
});
let acquired = match mem::replace(shared, linked) {
NodeProtected::Acquired(node_acquired) => node_acquired.data,
NodeProtected::Linked(..) | NodeProtected::Released(..) => unsafe {
debug_unreachable!()
},
};
*cursor.next_mut() = OptionNodeShared::some(node);
*unsafe { cursor.list.cursor_mut(next) }.prev_mut() = OptionNodeShared::some(node);
acquired
}
}