locklessness/primitives/
prepend_list.rs1use std::sync::atomic::{AtomicPtr, Ordering};
5use std::{ptr, mem};
6
7pub type NodePtr<T> = Option<Box<Node<T>>>;
8
9#[derive(Debug)]
10pub struct Node<T> {
11 pub value: T,
12 pub next: NodePtr<T>
13}
14
15#[derive(Debug)]
16pub struct PrependList<T>(AtomicPtr<Node<T>>);
17
18fn replace_forget<T>(dest: &mut T, value: T) {
19 mem::forget(mem::replace(dest, value))
20}
21
22impl<T> PrependList<T> {
23 fn into_raw(ptr: NodePtr<T>) -> *mut Node<T> {
24 match ptr {
25 Some(b) => Box::into_raw(b),
26 None => ptr::null_mut()
27 }
28 }
29 unsafe fn from_raw(ptr: *mut Node<T>) -> NodePtr<T> {
30 if ptr == ptr::null_mut() {
31 None
32 } else {
33 Some(Box::from_raw(ptr))
34 }
35 }
36
37 pub fn new(ptr: NodePtr<T>) -> Self {
38 PrependList(AtomicPtr::new(Self::into_raw(ptr)))
39 }
40 pub fn swap(&self, ptr: NodePtr<T>) -> NodePtr<T> {
41 unsafe {
42 Self::from_raw(self.0.swap(Self::into_raw(ptr), Ordering::AcqRel))
43 }
44 }
45 pub fn push(&self, mut node: Box<Node<T>>) {
46 let mut current = self.0.load(Ordering::Relaxed);
47 loop {
48 replace_forget(&mut node.next, unsafe { Self::from_raw(current) });
49 match self.0.compare_exchange_weak(current, &mut *node, Ordering::AcqRel, Ordering::Relaxed) {
50 Ok(_) => {
51 mem::forget(node);
52 return
53 },
54 Err(p) => current = p
55 }
56 }
57 }
58}
59
60impl<T> Drop for PrependList<T> {
61 fn drop(&mut self) {
62 unsafe { Self::from_raw(self.0.swap(ptr::null_mut(), Ordering::Relaxed)) };
63 }
64}