use std::{
ptr,
sync::atomic::{AtomicPtr, Ordering as AtomicOrdering},
};
pub struct EntryList<T: 'static> {
entry: Option<&'static T>,
next: AtomicPtr<Self>,
}
impl<T> EntryList<T> {
pub(crate) const fn root() -> Self {
Self { entry: None, next: AtomicPtr::new(ptr::null_mut()) }
}
#[inline]
fn next(&self) -> Option<&Self> {
unsafe { self.next.load(AtomicOrdering::Relaxed).as_ref() }
}
}
#[allow(missing_docs)]
impl<T> EntryList<T> {
#[inline]
pub const fn new(entry: &'static T) -> Self {
Self { entry: Some(entry), next: AtomicPtr::new(ptr::null_mut()) }
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &T> {
let mut list = Some(self);
std::iter::from_fn(move || -> Option<Option<&T>> {
let current = list?;
list = current.next();
Some(current.entry.as_ref().copied())
})
.flatten()
}
#[inline]
pub fn push(&'static self, other: &'static Self) {
let mut old_next = self.next.load(AtomicOrdering::Relaxed);
loop {
other.next.store(old_next, AtomicOrdering::Release);
let other = other as *const Self as *mut Self;
match self.next.compare_exchange_weak(
old_next,
other,
AtomicOrdering::AcqRel,
AtomicOrdering::Acquire,
) {
Ok(_) => return,
Err(new) => old_next = new,
}
}
}
}