use core::mem::ManuallyDrop;
#[cfg_attr(not(arm_llsc), path = "treiber/cas.rs")]
#[cfg_attr(arm_llsc, path = "treiber/llsc.rs")]
mod impl_;
pub use impl_::{AtomicPtr, NonNullPtr};
pub struct Stack<N>
where
N: Node,
{
top: AtomicPtr<N>,
}
impl<N> Stack<N>
where
N: Node,
{
pub const fn new() -> Self {
Self {
top: AtomicPtr::null(),
}
}
pub unsafe fn push(&self, node: NonNullPtr<N>) {
impl_::push(self, node);
}
pub fn try_pop(&self) -> Option<NonNullPtr<N>> {
impl_::try_pop(self)
}
}
pub trait Node: Sized {
type Data;
unsafe fn next(&self) -> &AtomicPtr<Self>;
#[allow(dead_code)] unsafe fn next_mut(&mut self) -> &mut AtomicPtr<Self>;
}
#[repr(C)]
pub union UnionNode<T> {
next: ManuallyDrop<AtomicPtr<UnionNode<T>>>,
pub data: ManuallyDrop<T>,
}
impl<T> UnionNode<T> {
pub const fn unlinked() -> Self {
Self {
next: ManuallyDrop::new(AtomicPtr::null()),
}
}
}
impl<T> Node for UnionNode<T> {
type Data = T;
unsafe fn next(&self) -> &AtomicPtr<Self> {
unsafe { &self.next }
}
unsafe fn next_mut(&mut self) -> &mut AtomicPtr<Self> {
unsafe { &mut self.next }
}
}
pub struct StructNode<T> {
pub next: ManuallyDrop<AtomicPtr<StructNode<T>>>,
pub data: ManuallyDrop<T>,
}
impl<T> Node for StructNode<T> {
type Data = T;
unsafe fn next(&self) -> &AtomicPtr<Self> {
&self.next
}
unsafe fn next_mut(&mut self) -> &mut AtomicPtr<Self> {
&mut self.next
}
}
#[cfg(test)]
mod tests {
use core::mem;
use super::*;
#[test]
fn node_is_never_zero_sized() {
struct Zst;
assert_ne!(mem::size_of::<UnionNode<Zst>>(), 0);
}
}