wfqueue/
lib.rs

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    /// # Safety
27    ///
28    /// Unsafe conversion from `NonZeroUsize`.
29    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
105// impl Queueable
106
107impl 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}