1#![no_std]
43#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
44#![cfg_attr(feature = "unstable", feature(doc_cfg))]
45
46#[cfg(feature = "std")]
47extern crate std;
48
49#[cfg(feature = "alloc")]
50extern crate alloc;
51
52pub mod queue;
53#[cfg(feature = "std")]
57pub use crate::queue::MpmcQueue;
58pub mod util {
65 pub const CACHE_LINE_SIZE: usize = 64;
67
68 #[inline]
70 pub const fn align_to_cache_line(size: usize) -> usize {
71 (size + CACHE_LINE_SIZE - 1) & !(CACHE_LINE_SIZE - 1)
72 }
73
74 #[repr(align(64))]
76 pub struct CachePadded<T> {
77 value: T,
78 }
79
80 impl<T> CachePadded<T> {
81 #[inline]
83 pub const fn new(value: T) -> Self {
84 Self { value }
85 }
86
87 #[inline]
89 pub const fn get(&self) -> &T {
90 &self.value
91 }
92
93 #[inline]
95 pub fn get_mut(&mut self) -> &mut T {
96 &mut self.value
97 }
98
99 #[inline]
101 pub fn into_inner(self) -> T {
102 self.value
103 }
104 }
105
106 impl CachePadded<std::sync::atomic::AtomicUsize> {
108 #[inline]
110 pub fn store(&self, val: usize, order: std::sync::atomic::Ordering) {
111 self.value.store(val, order);
112 }
113
114 #[inline]
116 pub fn load(&self, order: std::sync::atomic::Ordering) -> usize {
117 self.value.load(order)
118 }
119
120 #[inline]
122 pub fn compare_exchange(
123 &self,
124 current: usize,
125 new: usize,
126 success: std::sync::atomic::Ordering,
127 failure: std::sync::atomic::Ordering,
128 ) -> Result<usize, usize> {
129 self.value.compare_exchange(current, new, success, failure)
130 }
131 }
132
133 impl CachePadded<std::sync::atomic::AtomicIsize> {
134 #[inline]
136 pub fn store(&self, val: isize, order: std::sync::atomic::Ordering) {
137 self.value.store(val, order);
138 }
139
140 #[inline]
142 pub fn load(&self, order: std::sync::atomic::Ordering) -> isize {
143 self.value.load(order)
144 }
145
146 #[inline]
148 pub fn compare_exchange(
149 &self,
150 current: isize,
151 new: isize,
152 success: std::sync::atomic::Ordering,
153 failure: std::sync::atomic::Ordering,
154 ) -> Result<isize, isize> {
155 self.value.compare_exchange(current, new, success, failure)
156 }
157 }
158
159 impl<T: Clone> Clone for CachePadded<T> {
160 fn clone(&self) -> Self {
161 Self::new(self.value.clone())
162 }
163 }
164
165 impl<T: Copy> Copy for CachePadded<T> {}
166
167 impl<T: core::fmt::Debug> core::fmt::Debug for CachePadded<T> {
168 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
169 core::fmt::Debug::fmt(&self.value, f)
170 }
171 }
172}
173
174#[derive(Debug, Clone, PartialEq, Eq)]
176pub enum Error {
177 WouldBlock,
179 Closed,
181 InvalidState,
183}
184
185impl core::fmt::Display for Error {
186 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
187 match self {
188 Error::WouldBlock => write!(f, "Operation would block"),
189 Error::Closed => write!(f, "Data structure is closed"),
190 Error::InvalidState => write!(f, "Invalid operation for current state"),
191 }
192 }
193}
194
195#[cfg(feature = "std")]
196impl std::error::Error for Error {}
197
198pub type Result<T> = core::result::Result<T, Error>;
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204 use std::string::ToString;
205
206 #[test]
207 fn test_cache_line_alignment() {
208 assert_eq!(util::align_to_cache_line(1), 64);
209 assert_eq!(util::align_to_cache_line(64), 64);
210 assert_eq!(util::align_to_cache_line(65), 128);
211 assert_eq!(util::align_to_cache_line(127), 128);
212 assert_eq!(util::align_to_cache_line(128), 128);
213 }
214
215 #[test]
216 fn test_cache_padded() {
217 let padded = util::CachePadded::new(42);
218 assert_eq!(*padded.get(), 42);
219
220 let mut padded = padded;
221 *padded.get_mut() = 100;
222 assert_eq!(padded.into_inner(), 100);
223 }
224
225 #[test]
226 fn test_error_display() {
227 assert_eq!(
228 Error::WouldBlock.to_string().trim(),
229 "Operation would block"
230 );
231 assert_eq!(Error::Closed.to_string().trim(), "Data structure is closed");
232 assert_eq!(
233 Error::InvalidState.to_string().trim(),
234 "Invalid operation for current state"
235 );
236 }
237}