use core::{
cell::UnsafeCell,
iter, ptr,
ptr::NonNull,
sync::atomic::{AtomicBool, Ordering},
};
pub trait GetLinks {
type EntryType: ?Sized;
fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType>;
}
pub struct Links<T: ?Sized> {
inserted: AtomicBool,
entry: UnsafeCell<ListEntry<T>>,
}
unsafe impl<T: ?Sized> Send for Links<T> {}
unsafe impl<T: ?Sized> Sync for Links<T> {}
impl<T: ?Sized> Links<T> {
pub const fn new() -> Self {
Self {
inserted: AtomicBool::new(false),
entry: UnsafeCell::new(ListEntry::new()),
}
}
fn acquire_for_insertion(&self) -> bool {
self.inserted
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
}
fn release_after_removal(&self) {
self.inserted.store(false, Ordering::Release);
}
}
impl<T: ?Sized> Default for Links<T> {
fn default() -> Self {
Self::new()
}
}
struct ListEntry<T: ?Sized> {
next: Option<NonNull<T>>,
prev: Option<NonNull<T>>,
}
impl<T: ?Sized> ListEntry<T> {
const fn new() -> Self {
Self {
next: None,
prev: None,
}
}
}
pub struct RawList<G: GetLinks> {
head: Option<NonNull<G::EntryType>>,
}
impl<G: GetLinks> RawList<G> {
pub const fn new() -> Self {
Self { head: None }
}
pub fn iter(&self) -> Iterator<'_, G> {
Iterator::new(self.cursor_front(), self.cursor_back())
}
pub const fn is_empty(&self) -> bool {
self.head.is_none()
}
fn insert_after_priv(
&mut self,
existing: NonNull<G::EntryType>,
new_entry: &mut ListEntry<G::EntryType>,
new_ptr: Option<NonNull<G::EntryType>>,
) {
{
let existing_links = unsafe { &mut *G::get_links(existing.as_ref()).entry.get() };
new_entry.next = existing_links.next;
existing_links.next = new_ptr;
}
new_entry.prev = Some(existing);
let next_links =
unsafe { &mut *G::get_links(new_entry.next.unwrap().as_ref()).entry.get() };
next_links.prev = new_ptr;
}
pub unsafe fn insert_after(
&mut self,
existing: NonNull<G::EntryType>,
new: NonNull<G::EntryType>,
) -> bool {
let links = unsafe { G::get_links(new.as_ref()) };
if !links.acquire_for_insertion() {
return false;
}
let new_entry = unsafe { &mut *links.entry.get() };
self.insert_after_priv(existing, new_entry, Some(new));
true
}
fn push_back_internal(&mut self, new: NonNull<G::EntryType>, front: bool) -> bool {
let links = unsafe { G::get_links(new.as_ref()) };
if !links.acquire_for_insertion() {
return false;
}
let new_entry = unsafe { &mut *links.entry.get() };
let new_ptr = Some(new);
match self.back() {
Some(back) => {
self.insert_after_priv(back, new_entry, new_ptr);
if front {
self.head = new_ptr;
}
}
None => {
self.head = new_ptr;
new_entry.next = new_ptr;
new_entry.prev = new_ptr;
}
}
true
}
pub unsafe fn push_back(&mut self, new: NonNull<G::EntryType>) -> bool {
self.push_back_internal(new, false)
}
pub unsafe fn push_front(&mut self, new: NonNull<G::EntryType>) -> bool {
self.push_back_internal(new, true)
}
fn remove_internal(&mut self, data: &G::EntryType) -> bool {
let links = G::get_links(data);
let entry = unsafe { &mut *links.entry.get() };
let next = if let Some(next) = entry.next {
next
} else {
return false;
};
if ptr::eq(data, next.as_ptr()) {
self.head = None
} else {
if let Some(raw_head) = self.head {
if ptr::eq(data, raw_head.as_ptr()) {
self.head = Some(next);
}
}
unsafe { &mut *G::get_links(entry.prev.unwrap().as_ref()).entry.get() }.next =
entry.next;
unsafe { &mut *G::get_links(next.as_ref()).entry.get() }.prev = entry.prev;
}
entry.next = None;
entry.prev = None;
links.release_after_removal();
true
}
pub unsafe fn remove(&mut self, data: &G::EntryType) -> bool {
self.remove_internal(data)
}
fn pop_front_internal(&mut self) -> Option<NonNull<G::EntryType>> {
let head = self.head?;
unsafe { self.remove(head.as_ref()) };
Some(head)
}
pub fn pop_front(&mut self) -> Option<NonNull<G::EntryType>> {
self.pop_front_internal()
}
pub(crate) fn front(&self) -> Option<NonNull<G::EntryType>> {
self.head
}
pub(crate) fn back(&self) -> Option<NonNull<G::EntryType>> {
unsafe { &*G::get_links(self.head?.as_ref()).entry.get() }.prev
}
pub(crate) fn cursor_front(&self) -> Cursor<'_, G> {
Cursor::new(self, self.front())
}
pub(crate) fn cursor_back(&self) -> Cursor<'_, G> {
Cursor::new(self, self.back())
}
pub fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
CursorMut::new(self, self.front())
}
}
struct CommonCursor<G: GetLinks> {
cur: Option<NonNull<G::EntryType>>,
}
impl<G: GetLinks> CommonCursor<G> {
const fn new(cur: Option<NonNull<G::EntryType>>) -> Self {
Self { cur }
}
fn move_next(&mut self, list: &RawList<G>) {
match self.cur.take() {
None => self.cur = list.head,
Some(cur) => {
if let Some(head) = list.head {
let links = unsafe { &*G::get_links(cur.as_ref()).entry.get() };
if !ptr::addr_eq(links.next.unwrap().as_ptr(), head.as_ptr()) {
self.cur = links.next;
}
}
}
}
}
fn move_prev(&mut self, list: &RawList<G>) {
match list.head {
None => self.cur = None,
Some(head) => {
let next = match self.cur.take() {
None => head,
Some(cur) => {
if ptr::addr_eq(cur.as_ptr(), head.as_ptr()) {
return;
}
cur
}
};
let links = unsafe { &*G::get_links(next.as_ref()).entry.get() };
self.cur = links.prev;
}
}
}
}
unsafe impl<G: GetLinks> Send for RawList<G> where G::EntryType: Send {}
unsafe impl<G: GetLinks> Sync for RawList<G> where G::EntryType: Sync {}
pub(crate) struct Cursor<'a, G: GetLinks> {
cursor: CommonCursor<G>,
list: &'a RawList<G>,
}
impl<'a, G: GetLinks> Cursor<'a, G> {
pub(crate) fn new(list: &'a RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
Self {
list,
cursor: CommonCursor::new(cur),
}
}
pub(crate) fn current(&self) -> Option<&'a G::EntryType> {
let cur = self.cursor.cur?;
Some(unsafe { &*cur.as_ptr() })
}
pub(crate) fn current_ptr(&self) -> Option<NonNull<G::EntryType>> {
self.cursor.cur
}
pub(crate) fn move_next(&mut self) {
self.cursor.move_next(self.list);
}
pub fn peek_next(&self) -> Option<&G::EntryType> {
let mut new = CommonCursor::new(self.cursor.cur);
new.move_next(self.list);
Some(unsafe { &*new.cur?.as_ptr() })
}
pub fn peek_prev(&self) -> Option<&G::EntryType> {
let mut new = CommonCursor::new(self.cursor.cur);
new.move_prev(self.list);
Some(unsafe { &*new.cur?.as_ptr() })
}
pub(crate) fn move_prev(&mut self) {
self.cursor.move_prev(self.list);
}
}
pub struct CursorMut<'a, G: GetLinks> {
cursor: CommonCursor<G>,
pub(crate) list: &'a mut RawList<G>,
}
impl<'a, G: GetLinks> CursorMut<'a, G> {
fn new(list: &'a mut RawList<G>, cur: Option<NonNull<G::EntryType>>) -> Self {
Self {
list,
cursor: CommonCursor::new(cur),
}
}
pub unsafe fn current_mut(&mut self) -> Option<&mut G::EntryType> {
let cur = self.cursor.cur?;
Some(unsafe { &mut *cur.as_ptr() })
}
pub fn current(&self) -> Option<&G::EntryType> {
let cur = self.current_ptr()?;
Some(unsafe { &mut *cur.as_ptr() })
}
pub(crate) fn current_ptr(&self) -> Option<NonNull<G::EntryType>> {
self.cursor.cur
}
pub fn remove_current(&mut self) -> Option<NonNull<G::EntryType>> {
let entry = self.cursor.cur?;
self.cursor.move_next(self.list);
unsafe { self.list.remove(entry.as_ref()) };
Some(entry)
}
pub unsafe fn peek_next(&mut self) -> Option<&mut G::EntryType> {
let mut new = CommonCursor::new(self.cursor.cur);
new.move_next(self.list);
Some(unsafe { &mut *new.cur?.as_ptr() })
}
pub unsafe fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
let mut new = CommonCursor::new(self.cursor.cur);
new.move_prev(self.list);
Some(unsafe { &mut *new.cur?.as_ptr() })
}
pub fn move_next(&mut self) {
self.cursor.move_next(self.list);
}
pub fn move_prev(&mut self) {
self.cursor.move_prev(self.list);
}
}
impl<'a, G: GetLinks> iter::IntoIterator for &'a RawList<G> {
type Item = &'a G::EntryType;
type IntoIter = Iterator<'a, G>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct Iterator<'a, G: GetLinks> {
cursor_front: Cursor<'a, G>,
cursor_back: Cursor<'a, G>,
}
impl<'a, G: GetLinks> Iterator<'a, G> {
const fn new(cursor_front: Cursor<'a, G>, cursor_back: Cursor<'a, G>) -> Self {
Self {
cursor_front,
cursor_back,
}
}
}
impl<'a, G: GetLinks> iter::Iterator for Iterator<'a, G> {
type Item = &'a G::EntryType;
fn next(&mut self) -> Option<Self::Item> {
let ret = self.cursor_front.current()?;
self.cursor_front.move_next();
Some(ret)
}
}
impl<G: GetLinks> iter::DoubleEndedIterator for Iterator<'_, G> {
fn next_back(&mut self) -> Option<Self::Item> {
let ret = self.cursor_back.current()?;
self.cursor_back.move_prev();
Some(ret)
}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use alloc::{boxed::Box, vec::Vec};
use core::ptr::NonNull;
struct Example {
links: super::Links<Self>,
}
impl super::GetLinks for Example {
type EntryType = Self;
fn get_links(obj: &Self) -> &super::Links<Self> {
&obj.links
}
}
fn build_vector(size: usize) -> Vec<Box<Example>> {
let mut v = Vec::new();
v.reserve(size);
for _ in 0..size {
v.push(Box::new(Example {
links: super::Links::new(),
}));
}
v
}
#[track_caller]
fn assert_list_contents(v: &[Box<Example>], list: &super::RawList<Example>) {
let n = v.len();
let mut count = 0;
for (i, e) in list.iter().enumerate() {
assert!(core::ptr::eq(e, &*v[i]));
count += 1;
}
assert_eq!(count, n);
let mut count = 0;
for (i, e) in list.iter().rev().enumerate() {
assert!(core::ptr::eq(e, &*v[n - 1 - i]));
count += 1;
}
assert_eq!(count, n);
}
#[track_caller]
fn test_each_element(
min_len: usize,
max_len: usize,
test: impl Fn(&mut Vec<Box<Example>>, &mut super::RawList<Example>, usize, Box<Example>),
) {
for n in min_len..=max_len {
for i in 0..n {
let extra = Box::new(Example {
links: super::Links::new(),
});
let mut v = build_vector(n);
let mut list = super::RawList::<Example>::new();
for j in 0..n {
unsafe { list.push_back(NonNull::from(&*v[j])) };
}
test(&mut v, &mut list, i, extra);
assert_list_contents(&v, &list);
}
}
}
#[test]
fn test_push_back() {
const MAX: usize = 10;
let v = build_vector(MAX);
let mut list = super::RawList::<Example>::new();
for n in 1..=MAX {
unsafe { list.push_back(NonNull::from(&*v[n - 1])) };
assert_list_contents(&v[..n], &list);
}
}
#[test]
fn test_push_front() {
const MAX: usize = 10;
let v = build_vector(MAX);
let mut list = super::RawList::<Example>::new();
for n in 1..=MAX {
println!("push front: {}", MAX - n);
unsafe { list.push_front(NonNull::from(&*v[MAX - n])) };
assert_list_contents(&v[MAX - n..MAX], &list);
}
}
#[test]
fn test_one_removal() {
test_each_element(1, 10, |v, list, i, _| {
unsafe { list.remove(&v[i]) };
v.remove(i);
});
}
#[test]
fn test_one_insert_after() {
test_each_element(1, 10, |v, list, i, extra| {
unsafe { list.insert_after(v[i].as_ref().into(), extra.as_ref().into()) };
v.insert(i + 1, extra);
});
}
}