once/
lib.rs

1//! # Once Crate
2//!
3//! The `once` crate provides thread-safe data structures that are designed for insert-once
4//! semantics, making them particularly useful for concurrent programming scenarios where data is
5//! computed once and then read many times. Values can be mutated through exclusive (`&mut`)
6//! references, but new entries can only be inserted, never removed.
7//!
8//! ## Key Components
9//!
10//! - [`OnceVec`]: A thread-safe vector that allows pushing elements in a way that ensures they are
11//!   safely visible to other threads.
12//! - [`OnceBiVec`]: A bidirectional vector built on top of `OnceVec` that supports negative indices.
13//! - [`MultiIndexed`]: A multi-dimensional array that allows efficient storage and retrieval of values
14//!   using multi-dimensional coordinates.
15//! - [`Grove`] and [`TwoEndedGrove`]: Specialized collections that support the implementation of the
16//!   other data structures.
17//!
18//! ## Concurrency Support
19//!
20//! This crate is designed with concurrency in mind and uses atomic operations and locks to ensure
21//! thread safety. It can be used with the `concurrent` feature to enable parallel operations via
22//! the `rayon` crate.
23//!
24//! ## Testing with Loom
25//!
26//! The crate supports testing with the `loom` concurrency testing framework. Loom tests can be run with:
27//! ```bash
28//! RUSTFLAGS="--cfg loom" cargo test --release --features loom -- loom
29//! ```
30
31// The loom tests require `--cfg loom` to be passed to `rustc`. However, this is a nonstandard cfg
32// flag that we need to explicitly allow.
33#![allow(unexpected_cfgs)]
34#![deny(clippy::use_self, unsafe_op_in_unsafe_fn)]
35
36pub mod grove;
37pub mod multiindexed;
38pub mod once;
39pub mod write_once;
40
41mod std_or_loom;
42
43pub use grove::{Grove, TwoEndedGrove};
44pub use multiindexed::MultiIndexed;
45pub use once::{OnceBiVec, OnceBiVecIter, OnceVec, OnceVecIter};
46
47#[cfg(test)]
48mod test_utils {
49    pub fn num_threads() -> usize {
50        std::thread::available_parallelism()
51            .map(std::num::NonZero::get)
52            .unwrap_or(2)
53    }
54
55    pub fn values_per_thread() -> usize {
56        #[cfg(not(miri))]
57        return 1000;
58
59        // Miri is slow, so we reduce the number of values per thread to speed up the tests.
60        #[cfg(miri)]
61        return 10;
62    }
63}