zduny_wasm_timer/timer/
arc_list.rs1use std::marker;
4use std::ops::Deref;
5use std::sync::atomic::Ordering::SeqCst;
6use std::sync::atomic::{AtomicBool, AtomicUsize};
7use std::sync::Arc;
8
9pub struct ArcList<T> {
10 list: AtomicUsize,
11 _marker: marker::PhantomData<T>,
12}
13
14impl<T> ArcList<T> {
15 pub fn new() -> ArcList<T> {
16 ArcList {
17 list: AtomicUsize::new(0),
18 _marker: marker::PhantomData,
19 }
20 }
21
22 pub fn push(&self, data: &Arc<Node<T>>) -> Result<(), ()> {
28 if data.enqueued.swap(true, SeqCst) {
29 return Ok(());
32 }
33 let mut head = self.list.load(SeqCst);
34 let node = Arc::into_raw(data.clone()) as usize;
35 loop {
36 if head == 1 {
38 unsafe {
39 drop(Arc::from_raw(node as *mut Node<T>));
40 }
41 return Err(());
42 }
43
44 data.next.store(head, SeqCst);
46 match self.list.compare_exchange(head, node, SeqCst, SeqCst) {
47 Ok(_) => break Ok(()),
48 Err(new_head) => head = new_head,
49 }
50 }
51 }
52
53 pub fn take(&self) -> ArcList<T> {
56 let mut list = self.list.load(SeqCst);
57 loop {
58 if list == 1 {
59 break;
60 }
61 match self.list.compare_exchange(list, 0, SeqCst, SeqCst) {
62 Ok(_) => break,
63 Err(l) => list = l,
64 }
65 }
66 ArcList {
67 list: AtomicUsize::new(list),
68 _marker: marker::PhantomData,
69 }
70 }
71
72 pub fn take_and_seal(&self) -> ArcList<T> {
75 ArcList {
76 list: AtomicUsize::new(self.list.swap(1, SeqCst)),
77 _marker: marker::PhantomData,
78 }
79 }
80
81 pub fn pop(&mut self) -> Option<Arc<Node<T>>> {
84 let head = *self.list.get_mut();
85 if head == 0 || head == 1 {
86 return None;
87 }
88 let head = unsafe { Arc::from_raw(head as *const Node<T>) };
89 *self.list.get_mut() = head.next.load(SeqCst);
90 assert!(head.enqueued.swap(false, SeqCst));
93 Some(head)
94 }
95}
96
97impl<T> Drop for ArcList<T> {
98 fn drop(&mut self) {
99 while self.pop().is_some() {
100 }
102 }
103}
104
105pub struct Node<T> {
106 next: AtomicUsize,
107 enqueued: AtomicBool,
108 data: T,
109}
110
111impl<T> Node<T> {
112 pub fn new(data: T) -> Node<T> {
113 Node {
114 next: AtomicUsize::new(0),
115 enqueued: AtomicBool::new(false),
116 data,
117 }
118 }
119}
120
121impl<T> Deref for Node<T> {
122 type Target = T;
123
124 fn deref(&self) -> &T {
125 &self.data
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use wasm_bindgen_test::wasm_bindgen_test;
132
133 use super::*;
134
135 #[wasm_bindgen_test]
136 fn smoke() {
137 let a = ArcList::new();
138 let n = Arc::new(Node::new(1));
139 assert!(a.push(&n).is_ok());
140
141 let mut l = a.take();
142 assert_eq!(**l.pop().unwrap(), 1);
143 assert!(l.pop().is_none());
144 }
145
146 #[wasm_bindgen_test]
147 fn seal() {
148 let a = ArcList::new();
149 let n = Arc::new(Node::new(1));
150 let mut l = a.take_and_seal();
151 assert!(l.pop().is_none());
152 assert!(a.push(&n).is_err());
153
154 assert!(a.take().pop().is_none());
155 assert!(a.take_and_seal().pop().is_none());
156 }
157}