voluntary_servitude/lib.rs
1//! Atomic abstractions and thread-safe appendable list with lock-free iterators
2//!
3//! # Features
4//! - [`Atomic abstractions (Atomic, AtomicOption, FillOnceAtomicOption, FillOnceAtomicArc)`]
5//! - [`Thread-safe appendable list with a lock-free iterator (VoluntaryServitude - also called VS)`]
6//! - [`Serde serialization/deserialization ("serde-traits" feature)`]
7//! - [`par_extend, from_par_iter rayon implementation ("rayon-traits" feature)`]
8//! - [`Logging ("logs" feature)`]
9//!
10//! You probably only need this if you are debugging this crate
11//!
12//! # Atomic abstractions
13//! - [`Atomic`] -> atomic `Box<T>`
14//! - [`AtomicOption`] -> atomic `Option<Box<T>>`
15//! - [`FillOnceAtomicOption`] -> atomic `Option<Box<T>>` that can give references (ideal for iterators)
16//! - [`FillOnceAtomicArc`] -> atomic `Option<Arc<T>>` with a limited API (like [`FillOnceAtomicOption`])
17//!
18//! With [`Atomic`] and [`AtomicOption`] it's not safe to get a reference, you must replace the value to access it.
19//!
20//! To safely get a reference of T you must use [`FillOnceAtomicOption`] and accept the API limitations (initially `None` but can be filled once).
21//!
22//! For a safe `AtomicArc` you must use some data-structure from `arc-swap`, `RwLock/Mutex` from `parking_lot` (or `std`, which is slower but the standard) or [`FillOnceAtomicArc`] and accept the limited API (2018).
23//!
24//! # Thread-safe appendable list that can create a lock-free iterator
25//! - [`VoluntaryServitude`] (also called [`VS`])
26//!
27//! # API of `VS` Iterator
28//! - [`Iter`]
29//!
30//! # Logging
31//!
32//! *Setup logger according to `RUST_LOG` env var and `logs` feature*
33//!
34//! ## Enable the feature:
35//!
36//! **Cargo.toml**
37//! ```toml
38//! [dependencies]
39//! voluntary_servitude = { version = "4", features = "logs" }
40//! ```
41//!
42//! ## Set the `RUST_LOG` env var:
43//!
44//! ```bash
45//! export RUST_LOG=voluntary_servitude=trace
46//! export RUST_LOG=voluntary_servitude=debug
47//! export RUST_LOG=voluntary_servitude=info
48//! export RUST_LOG=voluntary_servitude=warn
49//! export RUST_LOG=voluntary_servitude=error
50//! ```
51//!
52//! ## Enable the logger using some setup (like env_logger)
53//!
54//! ```rust
55//! env_logger::init();
56//! // Call code to be logged
57//! // ...
58//! ```
59//!
60//! [`Atomic`]: ./atomics/struct.Atomic.html
61//! [`AtomicOption`]: ./atomics/struct.AtomicOption.html
62//! [`FillOnceAtomicOption`]: ./atomics/struct.FillOnceAtomicOption.html
63//! [`FillOnceAtomicArc`]: ./atomics/struct.FillOnceAtomicArc.html
64//! [`Atomic abstractions (Atomic, AtomicOption, FillOnceAtomicOption, FillOnceAtomicArc)`]: #atomic-abstractions
65//! [`Thread-safe appendable list with a lock-free iterator (VoluntaryServitude - also called VS)`]: ./struct.VoluntaryServitude.html
66//! [`Serde serialization/deserialization ("serde-traits" feature)`]: ./struct.VoluntaryServitude.html#impl-Serialize
67//! [`&VS`]: ./struct.VoluntaryServitude.html#impl-Insertable<Tab>
68//! [`&Iter`]: ./struct.Iter.html#impl-Insertable<Tab>
69//! [`par_extend, from_par_iter rayon implementation ("rayon-traits" feature)`]: ./struct.VoluntaryServitude.html#impl-FromParallelIterator<T>
70//! [`VoluntaryServitude`]: ./struct.VoluntaryServitude.html
71//! [`VS`]: ./type.VS.html
72//! [`Iter`]: ./struct.Iter.html
73//! [`Logging ("logs" feature)`]: #logging
74
75#![deny(
76 missing_docs,
77 missing_debug_implementations,
78 trivial_numeric_casts,
79 unused_extern_crates,
80 unused_import_braces,
81 unused_qualifications,
82 unused_results,
83 bad_style,
84 const_err,
85 dead_code,
86 improper_ctypes,
87 legacy_directory_ownership,
88 non_shorthand_field_patterns,
89 no_mangle_generic_items,
90 overflowing_literals,
91 path_statements,
92 patterns_in_fns_without_body,
93 plugin_as_library,
94 private_in_public,
95 safe_extern_statics,
96 unconditional_recursion,
97 unions_with_drop_fields,
98 unused_allocation,
99 unused_comparisons,
100 unused_parens,
101 while_true
102)]
103#![doc(html_root_url = "https://docs.rs/voluntary_servitude/4.0.7/voluntary-servitude")]
104#![cfg_attr(docs_rs_workaround, feature(doc_cfg))]
105
106/// Alias for [`voluntary_servitude`] macro
107///
108/// [`voluntary_servitude`]: ./macro.voluntary_servitude.html
109///
110/// ```
111/// # use voluntary_servitude::vs;
112/// # env_logger::init();
113/// use voluntary_servitude::VS;
114/// let vs: VS<()> = vs![];
115/// assert!(vs.is_empty());
116///
117/// let vs = vs![1, 2, 3];
118/// assert_eq!(vs.iter().collect::<Vec<_>>(), vec![&1, &2, &3]);
119///
120/// let vs = vs![1; 3];
121/// assert_eq!(vs.iter().collect::<Vec<_>>(), vec![&1; 3]);
122/// # let _ = vs![1, 2, 3,];
123/// ```
124#[macro_export]
125macro_rules! vs {
126 () => ($crate::voluntary_servitude![]);
127 ($elem: expr; $n: expr) => ($crate::voluntary_servitude![$elem; $n]);
128 ($($x: expr),+) => ($crate::voluntary_servitude![$($x),+]);
129 ($($x: expr,)+) => ($crate::voluntary_servitude![$($x,)+]);
130}
131
132/// Creates new [`VS`] with specified elements as in the `vec!` macro
133///
134/// [`VS`]: ./type.VS.html
135///
136/// ```
137/// # env_logger::init();
138/// # use voluntary_servitude::vs;
139/// use voluntary_servitude::VS;
140/// let vs: VS<()> = voluntary_servitude![];
141/// assert!(vs.is_empty());
142///
143/// let vs = voluntary_servitude![1, 2, 3];
144/// assert_eq!(vs.iter().collect::<Vec<_>>(), vec![&1, &2, &3]);
145///
146/// let vs = voluntary_servitude![1; 3];
147/// assert_eq!(vs.iter().collect::<Vec<_>>(), vec![&1; 3]);
148/// # let _ = voluntary_servitude![1, 2, 3,];
149/// ```
150#[macro_export]
151macro_rules! voluntary_servitude {
152 () => ($crate::VS::default());
153 ($elem: expr; $n: expr) => {{
154 let vs = $crate::VS::default();
155 for _ in 0..$n {
156 vs.append($elem);
157 }
158 vs
159 }};
160 ($($x: expr),+) => ($crate::voluntary_servitude![$($x,)+]);
161 ($($x: expr,)+) => {{
162 let vs = $crate::VS::default();
163 $(vs.append($x);)+
164 vs
165 }};
166}
167
168/// Remove logging macros when they are disabled (at compile time)
169#[macro_use]
170#[cfg(not(feature = "logs"))]
171#[allow(unused)]
172mod mock {
173 macro_rules! trace(($($x:tt)*) => ());
174 macro_rules! debug(($($x:tt)*) => ());
175 macro_rules! info(($($x:tt)*) => ());
176 macro_rules! warn(($($x:tt)*) => ());
177 macro_rules! error(($($x:tt)*) => ());
178}
179
180pub mod atomics;
181mod iterator;
182mod node;
183mod traits;
184mod voluntary_servitude;
185
186/// Simplify internal imports
187#[allow(unused)]
188mod prelude {
189 pub(crate) use crate::atomics::{Atomic, AtomicOption, FillOnceAtomicOption};
190 pub(crate) use crate::{IntoPtr, NotEmpty};
191 pub(crate) use crate::{Iter, VoluntaryServitude, VS};
192 #[cfg(feature = "logs")]
193 pub use log::{debug, error, info, trace, warn};
194}
195
196use std::{error::Error, fmt, fmt::Debug, fmt::Display, fmt::Formatter};
197
198/// Happens when you call `try_store` in a already filled [`AtomicOption`]/[`FillOnceAtomicOption`]/[`FillOnceAtomicArc`]
199///
200/// [`AtomicOption`]: ./atomics/struct.AtomicOption.html#method.try_store
201/// [`FillOnceAtomicOption`]: ./atomics/struct.FillOnceAtomicOption.html#method.try_store
202/// [`FillOnceAtomicArc`]: ./atomics/struct.FillOnceAtomicArc.html#method.try_store
203#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default)]
204pub struct NotEmpty;
205
206impl Debug for NotEmpty {
207 #[inline]
208 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
209 write!(f, "NotEmpty")
210 }
211}
212
213impl Display for NotEmpty {
214 #[inline]
215 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
216 write!(f, "not empty")
217 }
218}
219
220impl Error for NotEmpty {}
221
222pub use crate::iterator::Iter;
223pub use crate::voluntary_servitude::{VoluntaryServitude, VS};
224
225use std::ptr::null_mut;
226
227/// Trait made to simplify conversion between smart pointers and raw pointers
228pub(crate) trait IntoPtr<T> {
229 /// Converts itself into a mutable pointer to it (leak or unwrap things)
230 fn into_ptr(self) -> *mut T;
231}
232
233impl<T> IntoPtr<T> for T {
234 #[inline]
235 #[must_use]
236 fn into_ptr(self) -> *mut Self {
237 Box::into_raw(Box::new(self))
238 }
239}
240
241impl<T> IntoPtr<T> for Option<T> {
242 #[inline]
243 #[must_use]
244 fn into_ptr(self) -> *mut T {
245 self.map(Box::new).into_ptr()
246 }
247}
248
249impl<T> IntoPtr<T> for Box<T> {
250 #[inline]
251 #[must_use]
252 fn into_ptr(self) -> *mut T {
253 Self::into_raw(self)
254 }
255}
256
257impl<T> IntoPtr<T> for Option<Box<T>> {
258 #[inline]
259 #[must_use]
260 fn into_ptr(self) -> *mut T {
261 self.map_or(null_mut(), Box::into_raw)
262 }
263}
264
265#[cfg(test)]
266pub fn setup_logger() {
267 use std::sync::Once;
268 #[allow(unused)]
269 static INITIALIZE: Once = Once::new();
270 #[cfg(feature = "logs")]
271 INITIALIZE.call_once(env_logger::init);
272}