1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
#![allow(non_snake_case)]
#![deny(missing_docs)]
#![feature(generic_associated_types)]
#![feature(doc_cfg)]
#![no_std]
//! [`ParallelVec`] is a generic collection of contiguously stored heterogenous values with
//! an API similar to that of a `Vec<(T1, T2, ...)>` but stores the data laid out as a
//! separate slice per field, using a [structures of arrays](https://en.wikipedia.org/wiki/AoS_and_SoA#Structure_of_arrays)
//! layout. The advantage of this layout is that cache utilization may be signifgantly improved
//! when iterating over the data.
//!
//! This approach is common to game engines, and Entity-Component-Systems in particular but is
//! applicable anywhere that cache coherency and memory bandwidth are important for performance.
//!
//! Unlike a struct of `Vec`s, only one length and capacity field is stored, and only one contiguous
//! allocation is made for the entire data structs. Upon reallocation, a struct of `Vec` may apply
//! additional allocation pressure. `ParallelVec` only allocates once per resize.
//!
//! ## Example
//! ```rust
//! use parallel_vec::ParallelVec;
//!
//! /// Some 'entity' data.
//! # #[derive(Copy, Clone)]
//! struct Position { x: f64, y: f64 }
//! # #[derive(Copy, Clone)]
//! struct Velocity { dx: f64, dy: f64 }
//! struct ColdData { /* Potentially many fields omitted here */ }
//!
//! # use std::ops::Add;
//! # impl Add<Velocity> for Position { type Output=Self; fn add(self, other: Velocity) -> Self { Self { x: self.x + other.dx, y: self.y + other.dy } } }
//! // Create a vec of entities
//! let mut entities: ParallelVec<(Position, Velocity, ColdData)> = ParallelVec::new();
//! entities.push((Position {x: 1.0, y: 2.0}, Velocity { dx: 0.0, dy: 0.5 }, ColdData {}));
//! entities.push((Position {x: 0.0, y: 2.0}, Velocity { dx: 0.5, dy: 0.5 }, ColdData {}));
//!
//! // Update entities. This loop only loads position and velocity data, while skipping over
//! // the ColdData which is not necessary for the physics simulation.
//! for (position, velocity, _) in entities.iter_mut() {
//! *position = *position + *velocity;
//! }
//!
//! // Remove an entity
//! entities.swap_remove(0);
//! ```
//!
//! ## Nightly
//! This crate requires use of GATs and therefore requires the following nightly features:
//! * `generic_associated_types`
//!
//! ## `no_std` Support
//! By default, this crate requires the standard library. Disabling the default features
//! enables this crate to compile in `#![no_std]` environments. There must be a set global
//! allocator and heap support for this crate to work.
//!
//! ## `serde` Support
//! `ParallelVec` can be serialized if it's parameters can be serialized. This is disabled by
//! default. Use the `serde` feature to enable support for serialization and deserialization.
extern crate alloc;
#[cfg(any(test, feature = "std"))]
#[macro_use]
extern crate std;
/// A collection of iterators types for [`ParallelVec`].
pub mod iter;
/// Implementations for [`ParallelParam`].
pub mod param;
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
mod serde;
mod slice;
mod vec;
#[cfg(feature = "serde")]
pub use crate::serde::*;
pub use param::ParallelParam;
pub use slice::{ParallelSlice, ParallelSliceMut};
pub use vec::ParallelVec;
/// Error when attempting to convert types to [`ParallelVec`].
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum ParallelVecConversionError {
/// The provided inputs were not the same length.
UnevenLengths,
}
#[inline(always)]
pub(crate) fn assert_in_bounds(idx: usize, len: usize) {
assert!(idx < len, "Index out of bounds: {} (len: {})", idx, len);
}
#[inline(always)]
pub(crate) fn assert_in_bounds_inclusive(idx: usize, len: usize) {
assert!(idx <= len, "Index out of bounds: {} (len: {})", idx, len);
}
#[inline(always)]
pub(crate) fn out_of_bounds(idx: usize, len: usize) {
panic!("Index out of bounds: {} (len: {})", idx, len);
}