Skip to main content

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;