use core::marker::PhantomData;
use core::ptr::NonNull;
#[repr(C)]
#[derive(Debug)]
pub struct ListEntry {
pub flink: *mut ListEntry,
pub blink: *mut ListEntry,
}
impl ListEntry {
pub fn is_empty(&self) -> bool {
core::ptr::eq(self.flink, self as *const _ as *mut _)
}
pub fn next(&self, head: *const ListEntry) -> Option<NonNull<ListEntry>> {
if core::ptr::eq(self.flink, head as *mut _) {
None
} else {
NonNull::new(self.flink)
}
}
pub fn prev(&self, head: *const ListEntry) -> Option<NonNull<ListEntry>> {
if core::ptr::eq(self.blink, head as *mut _) {
None
} else {
NonNull::new(self.blink)
}
}
}
pub struct ListEntryIter<'a, T> {
head: *const ListEntry,
current: *const ListEntry,
offset: usize,
_marker: PhantomData<&'a T>,
}
impl<'a, T> ListEntryIter<'a, T> {
pub unsafe fn new(head: *const ListEntry, offset: usize) -> Self {
let first = unsafe { (*head).flink };
Self {
head,
current: first,
offset,
_marker: PhantomData,
}
}
}
impl<'a, T> Iterator for ListEntryIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if core::ptr::eq(self.current, self.head) {
return None;
}
let container = unsafe {
let entry_addr = self.current as usize;
let container_addr = entry_addr - self.offset;
&*(container_addr as *const T)
};
self.current = unsafe { (*self.current).flink };
Some(container)
}
}
pub struct ListEntryIterMut<'a, T> {
head: *mut ListEntry,
current: *mut ListEntry,
offset: usize,
_marker: PhantomData<&'a mut T>,
}
impl<'a, T> ListEntryIterMut<'a, T> {
pub unsafe fn new(head: *mut ListEntry, offset: usize) -> Self {
let first = unsafe { (*head).flink };
Self {
head,
current: first,
offset,
_marker: PhantomData,
}
}
}
impl<'a, T> Iterator for ListEntryIterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
if core::ptr::eq(self.current, self.head) {
return None;
}
let container = unsafe {
let entry_addr = self.current as usize;
let container_addr = entry_addr - self.offset;
&mut *(container_addr as *mut T)
};
self.current = unsafe { (*self.current).flink };
Some(container)
}
}
pub unsafe fn unlink_entry(entry: *mut ListEntry) {
unsafe {
let flink = (*entry).flink;
let blink = (*entry).blink;
(*blink).flink = flink;
(*flink).blink = blink;
(*entry).flink = entry;
(*entry).blink = entry;
}
}
pub unsafe fn link_entry_after(entry: *mut ListEntry, after: *mut ListEntry) {
unsafe {
let next = (*after).flink;
(*entry).flink = next;
(*entry).blink = after;
(*after).flink = entry;
(*next).blink = entry;
}
}