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;
158pub(crate) use __alloc::vec::Vec;
159
160mod soa;
161pub use soa::Soa;
162
163mod index;
164pub use index::SoaIndex;
165
166mod into_iter;
167pub use into_iter::IntoIter;
168
169mod iter;
170pub use iter::Iter;
171
172mod iter_mut;
173pub use iter_mut::IterMut;
174
175mod slice;
176pub use slice::Slice;
177
178mod slice_mut;
179pub use slice_mut::SliceMut;
180
181mod slice_ref;
182pub use slice_ref::SliceRef;
183
184mod soa_deref;
185pub use soa_deref::SoaDeref;
186
187mod soars;
188pub use soars::Soars;
189
190mod soa_clone;
191pub use soa_clone::{SoaClone, SoaToOwned};
192
193mod soa_raw;
194#[doc(hidden)]
195pub use soa_raw::SoaRaw;
196
197mod chunks_exact;
198pub use chunks_exact::ChunksExact;
199
200mod iter_raw;
201
202mod as_slice;
203pub use as_slice::{AsMutSlice, AsSlice};
204
205mod as_soa_ref;
206pub use as_soa_ref::AsSoaRef;
207
208#[cfg(feature = "serde")]
209mod serde;
210
211/// Derive macro for the [`Soars`] trait.
212///
213/// Deriving Soars for some struct `Foo` will create the following additional
214/// structs:
215///
216/// | Struct | Field type | Use |
217/// |----------------|------------|----------------------------------------------|
218/// | `FooSoaRaw` | `*mut T` | Low-level, unsafe memory handling for SoA |
219/// | `FooRef` | `&T` | SoA element reference |
220/// | `FooRefMut` | `&mut T` | Mutable SoA element reference |
221/// | `FooSlices` | `&[T]` | SoA fields |
222/// | `FooSlicesMut` | `&mut [T]` | Mutable SoA fields |
223/// | `FooArray` | `[T; N]` | `const`-compatible SoA |
224/// | `FooDeref` | | SoA [`Deref`] target, provides slice getters |
225///
226/// The [`Soars`] trait implementation for `Foo` references these as associated
227/// types. [`AsSoaRef`] is also implemented for `Foo`, `FooRef`, and `FooRefMut`.
228///
229/// # Arrays
230///
231/// The `FooArray` type is only generated when the `#[soa_array]` attribute is
232/// added to the struct. Only structs without interior mutability support this
233/// attribute for the time being, due to [this
234/// issue](https://github.com/rust-lang/rust/issues/80384). SOA array types are
235/// stack-allocated like normal arrays and are `const`-initializable.
236///
237/// # Derive for generated types
238///
239/// The `soa_derive` attribute can be used to derive traits for the generated
240/// types. `Copy` and `Clone` are added automatically for `FooRef` and
241/// `FooSlices`. In the following example, we have the following trait
242/// implementations:
243///
244/// | Struct | `Copy`/`Clone` | `Debug`/`PartialEq` | `Eq` | `PartialOrd` |
245/// |----------------|----------------|---------------------|------|--------------|
246/// | `FooRef` | ✅ | ✅ | ✅ | |
247/// | `FooRefMut` | | ✅ | ✅ | ✅ |
248/// | `FooSlices` | ✅ | ✅ | | |
249/// | `FooSlicesMut` | | ✅ | | ✅ |
250/// | `FooArray` | | ✅ | | ✅ |
251///
252/// ```
253/// # use soa_rs::{Soars};
254/// #[derive(Soars)]
255/// #[soa_derive(Debug, PartialEq)]
256/// #[soa_derive(include(Ref, RefMut), Eq)]
257/// #[soa_derive(exclude(Ref, Slices), PartialOrd)]
258/// struct Foo(u8);
259/// ```
260///
261/// # Alignment
262///
263/// Individual fields can be tagged with the `align` attribute to raise their
264/// alignment. The slice for that field will start at a multiple of the
265/// requested alignment if it is greater than or equal to the alignment of the
266/// field's type. This can be useful for vector operations.
267///
268/// ```
269/// # use soa_rs::{Soars};
270/// # #[derive(Soars)]
271/// # #[soa_derive(Debug, PartialEq)]
272/// struct Foo(#[align(8)] u8);
273/// ```
274///
275/// [`Deref`]: core::ops::Deref
276pub use soa_rs_derive::Soars;
277
278/// Derive macro for the [`SoaClone`] trait.
279///
280/// This macro generates an implementation that constructs an owned value
281/// by cloning all fields from an SoA reference.
282///
283/// # Example
284///
285/// ```
286/// # use soa_rs::{Soars, SoaClone, soa};
287/// #[derive(Soars, SoaClone, Debug, PartialEq, Clone)]
288/// #[soa_derive(Debug)]
289/// struct Foo(u8, u16);
290/// let soa = soa![Foo(1, 2), Foo(3, 4)];
291/// let point_ref = soa.idx(1);
292/// let owned = Foo::soa_clone(point_ref);
293/// assert_eq!(owned, Foo(3, 4));
294/// ```
295pub use soa_rs_derive::SoaClone;
296
297/// Creates a [`Soa`] containing the arguments.
298///
299/// `soa!` allows [`Soa`]s to be defined with the same syntax as array
300/// expressions. There are two forms of this macro:
301///
302/// - Create a [`Soa`] containing a given list of elements:
303/// ```
304/// # use soa_rs::{Soars, soa};
305/// # #[derive(Soars, Debug, PartialEq, Copy, Clone)]
306/// # #[soa_derive(Debug, PartialEq, PartialOrd)]
307/// # struct Foo(u8, u16);
308/// let soa = soa![Foo(1, 2), Foo(3, 4)];
309/// assert_eq!(soa, soa![Foo(1, 2), Foo(3, 4)]);
310/// ```
311///
312/// - Create a [`Soa`] from a given element and size:
313///
314/// ```
315/// # use soa_rs::{Soars, soa};
316/// # #[derive(Soars, Debug, PartialEq, Copy, Clone)]
317/// # #[soa_derive(Debug, PartialEq)]
318/// # struct Foo(u8, u16);
319/// let soa = soa![Foo(1, 2); 5];
320/// assert_eq!(soa, soa![
321/// Foo(1, 2),
322/// Foo(1, 2),
323/// Foo(1, 2),
324/// Foo(1, 2),
325/// Foo(1, 2),
326/// ]);
327/// ```
328#[macro_export]
329macro_rules! soa {
330 () => {
331 $crate::Soa::new()
332 };
333
334 ($x:expr $(,$xs:expr)* $(,)?) => {
335 {
336 let mut out = $crate::Soa::with($x);
337 $(
338 out.push($xs);
339 )*
340 out
341 }
342 };
343
344 ($elem:expr; 0) => {
345 soa![]
346 };
347
348 ($elem:expr; 1) => {
349 $crate::Soa::with($elem)
350 };
351
352 ($elem:expr; $n:expr) => {
353 {
354 let elem = $elem;
355 let mut out = $crate::Soa::with(elem.clone());
356 out.reserve($n);
357
358 let mut i = 2;
359 while i < $n {
360 out.push(elem.clone());
361 i += 1;
362 }
363
364 out.push(elem);
365 out
366 }
367 };
368}
369
370#[doc = include_str!("../README.md")]
371mod readme_tests {}
372
373mod borrow_tests;