1#[cfg(not(feature = "loom"))]
2mod loom {
3 pub use std::sync;
4}
5
6#[cfg(feature = "loom")]
7use loom;
8
9pub mod queue;
10
11use std::num::NonZeroUsize;
12use std::marker::PhantomData;
13use cache_padded::CachePadded;
14use per_thread_object::ThreadLocal;
15
16
17pub struct WfQueue<T: Queueable> {
18 queue: queue::WfQueue,
19 context: ThreadLocal<Context>,
20 _phantom: PhantomData<T>
21}
22
23pub trait Queueable {
24 fn into_nonzero(self) -> NonZeroUsize;
25
26 unsafe fn from_nonzero(n: NonZeroUsize) -> Self;
30}
31
32struct Context {
33 enq: CachePadded<queue::EnqueueCtx>,
34 deq: CachePadded<queue::DequeueCtx>
35}
36
37impl<T: Queueable> WfQueue<T> {
38 pub fn new(cap: usize) -> WfQueue<T> {
39 WfQueue {
40 queue: queue::WfQueue::new(cap),
41 context: ThreadLocal::new(),
42 _phantom: PhantomData
43 }
44 }
45
46 #[inline]
47 pub fn len(&self) -> usize {
48 self.queue.len()
49 }
50
51 #[inline]
52 pub fn capacity(&self) -> usize {
53 self.queue.capacity()
54 }
55
56 #[inline]
57 pub fn is_empty(&self) -> bool {
58 self.queue.is_empty()
59 }
60
61 #[inline]
62 pub fn is_full(&self) -> bool {
63 self.queue.is_full()
64 }
65
66 pub fn push(&self, val: T) -> Result<(), T> {
67 let ctx = self.context.get_or(Context::new);
68 let val = val.into_nonzero();
69
70 if self.queue.try_enqueue(&ctx.enq, val) {
71 Ok(())
72 } else {
73 unsafe {
74 Err(T::from_nonzero(val))
75 }
76 }
77 }
78
79 pub fn pop(&self) -> Option<T> {
80 let ctx = self.context.get_or(Context::new);
81 let val = self.queue.try_dequeue(&ctx.deq)?;
82
83 unsafe {
84 Some(T::from_nonzero(val))
85 }
86 }
87}
88
89impl<T: Queueable> Drop for WfQueue<T> {
90 #[inline]
91 fn drop(&mut self) {
92 while self.pop().is_some() {}
93 }
94}
95
96impl Context {
97 pub const fn new() -> Context {
98 Context {
99 enq: CachePadded::new(queue::EnqueueCtx::new()),
100 deq: CachePadded::new(queue::DequeueCtx::new())
101 }
102 }
103}
104
105impl Queueable for NonZeroUsize {
108 #[inline]
109 fn into_nonzero(self) -> NonZeroUsize {
110 self
111 }
112
113 #[inline]
114 unsafe fn from_nonzero(n: NonZeroUsize) -> Self {
115 n
116 }
117}
118
119impl<T> Queueable for &'static T {
120 #[inline]
121 fn into_nonzero(self) -> NonZeroUsize {
122 unsafe {
123 NonZeroUsize::new_unchecked(self as *const T as usize)
124 }
125 }
126
127 #[inline]
128 unsafe fn from_nonzero(n: NonZeroUsize) -> Self {
129 &*(n.get() as *const T)
130 }
131}
132
133impl<T> Queueable for Box<T> {
134 #[inline]
135 fn into_nonzero(self) -> NonZeroUsize {
136 unsafe {
137 NonZeroUsize::new_unchecked(Box::into_raw(self) as usize)
138 }
139 }
140
141 #[inline]
142 unsafe fn from_nonzero(n: NonZeroUsize) -> Self {
143 Box::from_raw(n.get() as *mut _)
144 }
145}
146
147use loom::sync::Arc;
148
149impl<T> Queueable for Arc<T> {
150 #[inline]
151 fn into_nonzero(self) -> NonZeroUsize {
152 unsafe {
153 NonZeroUsize::new_unchecked(Arc::into_raw(self) as usize)
154 }
155 }
156
157 #[inline]
158 unsafe fn from_nonzero(n: NonZeroUsize) -> Self {
159 Arc::from_raw(n.get() as *mut _)
160 }
161}
162
163use std::ptr::NonNull;
164
165impl<T> Queueable for NonNull<T> {
166 #[inline]
167 fn into_nonzero(self) -> NonZeroUsize {
168 unsafe {
169 NonZeroUsize::new_unchecked(self.as_ptr() as usize)
170 }
171 }
172
173 #[inline]
174 unsafe fn from_nonzero(n: NonZeroUsize) -> Self {
175 NonNull::new_unchecked(n.get() as *mut _)
176 }
177}