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}