soa_rs/
lib.rs

1//! # Soars
2//!
3//! Soars makes it simple to work with the structure-of-arrays memory layout.
4//! What [`Vec`] is to array-of-structures, [`Soa`] is to structure-of-arrays.
5//!
6//! # Examples
7//!
8//! First, derive [`Soars`] for your type:
9//! ```
10//! # use soa_rs::{soa, Soars};
11//! #[derive(Soars, Debug, Clone, Copy, PartialEq)]
12//! #[soa_derive(Debug, PartialEq)]
13//! struct Example {
14//!     foo: u8,
15//!     bar: u16,
16//! }
17//! ```
18//!
19//! You can create an [`Soa`] explicitly:
20//! ```
21//! # use soa_rs::{soa, Soars, Soa};
22//! # #[derive(Soars, Debug, Clone, Copy, PartialEq)]
23//! # #[soa_derive(Debug, PartialEq)]
24//! # struct Example {
25//! #     foo: u8,
26//! #     bar: u16,
27//! # }
28//! let mut soa: Soa<Example> = Soa::new();
29//! soa.push(Example { foo: 1, bar: 2 });
30//! ```
31//!
32//! ...or by using the [`soa!`] macro.
33//! ```
34//! # use soa_rs::{soa, Soars};
35//! # #[derive(Soars, Debug, Clone, Copy, PartialEq)]
36//! # #[soa_derive(Debug, PartialEq)]
37//! # struct Example {
38//! #     foo: u8,
39//! #     bar: u16,
40//! # }
41//! let mut soa = soa![Example { foo: 1, bar: 2 }, Example { foo: 3, bar: 4 }];
42//! ```
43//!
44//! An SoA can be indexed and sliced just like a `&[T]`. Use `idx` in lieu of
45//! the index operator.
46//! ```
47//! # use soa_rs::{soa, Soars, AsSlice};
48//! # #[derive(Soars, Debug, Clone, Copy, PartialEq)]
49//! # #[soa_derive(Debug, PartialEq)]
50//! # struct Example {
51//! #     foo: u8,
52//! #     bar: u16,
53//! # }
54//! let mut soa = soa![
55//!     Example { foo: 1, bar: 2 },
56//!     Example { foo: 3, bar: 4 },
57//!     Example { foo: 5, bar: 6 },
58//!     Example { foo: 7, bar: 8 }
59//! ];
60//! assert_eq!(soa.idx(3), ExampleRef { foo: &7, bar: &8 });
61//! assert_eq!(
62//!     soa.idx(1..3),
63//!     soa![
64//!         Example { foo: 3, bar: 4 },
65//!         Example { foo: 5, bar: 6 },
66//!     ],
67//! );
68//! ```
69//!
70//! The usual [`Vec`] APIs work normally.
71//! ```
72//! # use soa_rs::{soa, Soars, Soa};
73//! # #[derive(Soars, Debug, Clone, Copy, PartialEq)]
74//! # #[soa_derive(Debug, PartialEq)]
75//! # struct Example {
76//! #     foo: u8,
77//! #     bar: u16,
78//! # }
79//! let mut soa = Soa::<Example>::new();
80//! soa.push(Example { foo: 1, bar: 2 });
81//! soa.push(Example { foo: 3, bar: 4 });
82//! soa.insert(0, Example { foo: 5, bar: 6 });
83//! assert_eq!(soa.pop(), Some(Example { foo: 3, bar: 4 }));
84//! for mut el in &mut soa {
85//!     *el.bar += 10;
86//! }
87//! assert_eq!(soa.bar(), [16, 12]);
88//! ```
89//!
90//! # Field getters
91//!
92//! You can access the fields as slices.
93//! ```
94//! # use soa_rs::{soa, Soars};
95//! # #[derive(Soars, Debug, Clone, Copy, PartialEq)]
96//! # #[soa_derive(Debug, PartialEq)]
97//! # struct Example {
98//! #     foo: u8,
99//! #     bar: u16,
100//! # }
101//! let mut soa = soa![
102//!     Example { foo: 1, bar: 2 },
103//!     Example { foo: 3, bar: 4 },
104//! ];
105//! assert_eq!(soa.foo(), [1, 3]);
106//! ```
107//!
108//! Postpend `_mut` for mutable slices.
109//! ```
110//! # use soa_rs::{soa, Soars};
111//! # #[derive(Soars, Debug, Clone, Copy, PartialEq)]
112//! # #[soa_derive(Debug, PartialEq)]
113//! # struct Example {
114//! #     foo: u8,
115//! #     bar: u16,
116//! # }
117//! # let mut soa = soa![
118//! #     Example { foo: 1, bar: 2 },
119//! #     Example { foo: 3, bar: 4 },
120//! # ];
121//! for foo in soa.foo_mut() {
122//!     *foo += 10;
123//! }
124//! assert_eq!(soa.foo(), [11, 13]);
125//! ```
126//!
127//! For tuple structs, prepend the field number with `f`:
128//! ```
129//! # use soa_rs::{soa, Soars};
130//! #[derive(Soars)]
131//! # #[soa_derive(Debug, PartialEq)]
132//! struct Example(u8);
133//! let soa = soa![Example(5), Example(10)];
134//! assert_eq!(soa.f0(), [5, 10]);
135//! ```
136//!
137//! # Serde
138//!
139//! [`serde`](https://serde.rs/) support is enabled by the `serde` feature
140//! flag.
141//!
142//! ```ignore
143//! #[derive(Soars, serde::Deserialize)]
144//! #[soa_derive(include(Ref), serde::Serialize)]
145//! struct Test(u32);
146//! ```
147//!
148//! [`Soars`]: soa_rs_derive::Soars
149#![warn(missing_docs)]
150#![no_std]
151
152/// `::alloc` is not available at the top level the way that `::std` and
153/// `::core` are. We don't want to do the `extern` inside the macro because
154/// multiple invocations will cause name conflicts. Therefore, we re-export it
155/// from the library for consumption instead.
156#[doc(hidden)]
157pub extern crate alloc as __alloc;
158
159mod soa;
160pub use soa::Soa;
161
162mod index;
163pub use index::SoaIndex;
164
165mod into_iter;
166pub use into_iter::IntoIter;
167
168mod iter;
169pub use iter::Iter;
170
171mod iter_mut;
172pub use iter_mut::IterMut;
173
174mod slice;
175pub use slice::Slice;
176
177mod slice_mut;
178pub use slice_mut::SliceMut;
179
180mod slice_ref;
181pub use slice_ref::SliceRef;
182
183mod soa_deref;
184pub use soa_deref::SoaDeref;
185
186mod soars;
187pub use soars::Soars;
188
189mod soa_raw;
190#[doc(hidden)]
191pub use soa_raw::SoaRaw;
192
193mod chunks_exact;
194pub use chunks_exact::ChunksExact;
195
196mod iter_raw;
197
198mod as_slice;
199pub use as_slice::{AsMutSlice, AsSlice};
200
201mod as_soa_ref;
202pub use as_soa_ref::AsSoaRef;
203
204#[cfg(feature = "serde")]
205mod serde;
206
207/// Derive macro for the [`Soars`] trait.
208///
209/// Deriving Soars for some struct `Foo` will create the following additional
210/// structs:
211///
212/// | Struct         | Field type | Use                                          |
213/// |----------------|------------|----------------------------------------------|
214/// | `FooSoaRaw`    | `*mut T`   | Low-level, unsafe memory handling for SoA    |
215/// | `FooRef`       | `&T`       | SoA element reference                        |
216/// | `FooRefMut`    | `&mut T`   | Mutable SoA element reference                |
217/// | `FooSlices`    | `&[T]`     | SoA fields                                   |
218/// | `FooSlicesMut` | `&mut [T]` | Mutable SoA fields                           |
219/// | `FooArray`     | `[T; N]`   | `const`-compatible SoA                       |
220/// | `FooDeref`     |            | SoA [`Deref`] target, provides slice getters |
221///
222/// The [`Soars`] trait implementation for `Foo` references these as associated
223/// types. [`AsSoaRef`] is also implemented for `Foo`, `FooRef`, and `FooRefMut`.
224///
225/// # Arrays
226///
227/// The `FooArray` type is only generated when the `#[soa_array]` attribute is
228/// added to the struct. Only structs without interior mutability support this
229/// attribute for the time being, due to [this
230/// issue](https://github.com/rust-lang/rust/issues/80384). SOA array types are
231/// stack-allocated like normal arrays and are `const`-initializable.
232///
233/// # Derive for generated types
234///
235/// The `soa_derive` attribute can be used to derive traits for the generated
236/// types. `Copy` and `Clone` are added automatically for `FooRef` and
237/// `FooSlices`. In the following example, we have the following trait
238/// implementations:
239///
240/// | Struct         | `Copy`/`Clone` | `Debug`/`PartialEq` | `Eq` | `PartialOrd` |
241/// |----------------|----------------|---------------------|------|--------------|
242/// | `FooRef`       | ✅             | ✅                  | ✅   |              |
243/// | `FooRefMut`    |                | ✅                  | ✅   | ✅           |
244/// | `FooSlices`    | ✅             | ✅                  |      |              |
245/// | `FooSlicesMut` |                | ✅                  |      | ✅           |
246/// | `FooArray`     |                | ✅                  |      | ✅           |
247///
248/// ```
249/// # use soa_rs::{Soars};
250/// #[derive(Soars)]
251/// #[soa_derive(Debug, PartialEq)]
252/// #[soa_derive(include(Ref, RefMut), Eq)]
253/// #[soa_derive(exclude(Ref, Slices), PartialOrd)]
254/// struct Foo(u8);
255/// ```
256///
257/// # Alignment
258///
259/// Individual fields can be tagged with the `align` attribute to raise their
260/// alignment. The slice for that field will start at a multiple of the
261/// requested alignment if it is greater than or equal to the alignment of the
262/// field's type. This can be useful for vector operations.
263///
264/// ```
265/// # use soa_rs::{Soars};
266/// # #[derive(Soars)]
267/// # #[soa_derive(Debug, PartialEq)]
268/// struct Foo(#[align(8)] u8);
269/// ```
270///
271/// [`Deref`]: core::ops::Deref
272pub use soa_rs_derive::Soars;
273
274/// Creates a [`Soa`] containing the arguments.
275///
276/// `soa!` allows [`Soa`]s to be defined with the same syntax as array
277/// expressions. There are two forms of this macro:
278///
279/// - Create a [`Soa`] containing a given list of elements:
280/// ```
281/// # use soa_rs::{Soars, soa};
282/// # #[derive(Soars, Debug, PartialEq, Copy, Clone)]
283/// # #[soa_derive(Debug, PartialEq, PartialOrd)]
284/// # struct Foo(u8, u16);
285/// let soa = soa![Foo(1, 2), Foo(3, 4)];
286/// assert_eq!(soa, soa![Foo(1, 2), Foo(3, 4)]);
287/// ```
288///
289/// - Create a [`Soa`] from a given element and size:
290///
291/// ```
292/// # use soa_rs::{Soars, soa};
293/// # #[derive(Soars, Debug, PartialEq, Copy, Clone)]
294/// # #[soa_derive(Debug, PartialEq)]
295/// # struct Foo(u8, u16);
296/// let soa = soa![Foo(1, 2); 2];
297/// assert_eq!(soa, soa![Foo(1, 2), Foo(1, 2)]);
298/// ```
299#[macro_export]
300macro_rules! soa {
301    () => {
302        $crate::Soa::new()
303    };
304
305    ($x:expr $(,$xs:expr)* $(,)?) => {
306        {
307            let mut out = $crate::Soa::with($x);
308            $(
309            out.push($xs);
310            )*
311            out
312        }
313    };
314
315    ($elem:expr; 0) => {
316        soa![]
317    };
318
319    ($elem:expr; 1) => {
320        $crate::Soa::with($elem)
321    };
322
323    ($elem:expr; $n:expr) => {
324        {
325            let elem = $elem;
326            let mut out = $crate::Soa::with(elem.clone());
327
328            let mut i = 2;
329            while i < $n {
330                out.push(elem.clone());
331            }
332
333            out.push(elem);
334            out
335        }
336    };
337}
338
339#[doc = include_str!("../README.md")]
340mod readme_tests {}
341
342mod borrow_tests;