Crate soa_derive [−] [src]
This crate provides a custom derive (#[derive(StructOfArray)]
) to
automatically generate code from a given struct T
that allow to replace
Vec<T>
with a struct of arrays. For example, the following code
#[derive(StructOfArray)] pub struct Particle { pub x: f64, pub y: f64, pub z: f64, }
will generate a ParticleVec
struct that looks like this:
pub struct ParticleVec { pub x: Vec<f64>, pub y: Vec<f64>, pub z: Vec<f64>, }
It will also generate the same functions that a Vec<Particle>
would have,
and a few helper structs: ParticleSlice
, ParticleSliceMut
,
ParticleRef
and ParticleRefMut
.
How to use it
Add #[derive(StructOfArray)]
to each struct you want to derive a struct
of array version. If you need the helper structs to derive additional
traits (such as Debug
or PartialEq
), you can add an attribute
#[soa_derive = "Debug, PartialEq"]
to the struct declaration.
#[derive(Debug, PartialEq, StructOfArray)] #[soa_derive = "Debug, PartialEq"] pub struct Particle { pub x: f64, pub y: f64, pub z: f64, }
zip
functions
You can activate generation of two additional functions zip
and
zip_mut
by decorating some fields of the struct with
#[soa_derive(zip)]
. These functions allow to iterate over multiple
fields of the derivated Vec
.
#[derive(StructOfArray)] pub struct Particle { #[soa_derive(zip)] pub x: f64, #[soa_derive(zip)] pub y: f64, #[soa_derive(zip)] pub z: f64, // Do not derive zip for this field pub name: String, }
This generate a zip_particle
module containing marker types used to
request some specific data, like this:
use zip_particle::{X, Y, Z}; let mut vector = ParticleVec::new(); for x in vector.zip(&X) { // x is a &f64 } let mut total = 0.0; for (&x, &z) in vector.zip((&X, &Z)) { total += x * z; } // Mutable iteration is also available with zip_mut for y in vector.zip_mut(&mut Y) { *y += 6.4; } for (&x, z) in vector.zip_mut((&X, &mut Z)) { *z *= x; }
Caveats and limitations
Vec<T>
functionalities rely a lot on references and automatic deref
feature, for getting function from [T]
and indexing. But the SoA vector
(let's call it CheeseVec
, generated from the Cheese
struct) generated
by this crate can not implement Deref<Target=CheeseSlice>
, because
Deref
is required to return a reference, and CheeseSlice
is not a
reference. The same applies to Index
and IndexMut
trait, that can not
return CheeseRef/CheeseRefMut
.
This means that the we can not index into a CheeseVec
, and that a few
functions are duplicated, or require a call to as_ref()/as_mut()
to
change the type used.
Because of the way the code is implemented, the zip
functions can not be
derived on more than 4 fields, as the compilation time grows exponentialy.
Deriving it for 5 fields makes the compilation time goes from 6s to more
than 2 minutes. These functions will only be derived if the struct is
declared as public.
Documentation
Please see http://lumol.org/soa-derive/soa_derive_example/ for a small example and the documentation of all the generated code.
Functions
soa_derive |