Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to nest structs of arrays #41

Merged
merged 21 commits into from
Feb 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
047a931
feat: nested_soa attribute
CurryPseudo Dec 6, 2021
95f5ffd
fix: doc for nested fields and new associated function
CurryPseudo Dec 8, 2021
a98107b
fix: clippy warning
CurryPseudo Dec 8, 2021
d50eb1d
fix: add assertion for empty field back
CurryPseudo Dec 8, 2021
4c99688
doc: update usage for nested_soa, replace no_run by ignore
CurryPseudo Dec 9, 2021
05879c3
fix: revert doc test change
CurryPseudo Dec 13, 2021
5c47809
refactor: fix vec's field layout
CurryPseudo Dec 16, 2021
0c953e7
refactor: fix slice's field layout
CurryPseudo Dec 16, 2021
658ece8
refactor: fix ref's field layout
CurryPseudo Dec 16, 2021
cc2af64
refactor: fix ptr's field layout
CurryPseudo Dec 16, 2021
e37972a
refactor: remove usage for unnested_fields and nested_fields
CurryPseudo Dec 17, 2021
9d22172
refactor: remove unnested_fields and nested_fields
CurryPseudo Dec 17, 2021
1d2f1de
refactor: field_seq_by_nested_soa => fields_seq, intro fold_fields
CurryPseudo Dec 17, 2021
0d0b88c
refactor: use concat to replace fields_seq
CurryPseudo Feb 13, 2022
557e93a
refactor: replace fold_fields by iterator utilities combination
CurryPseudo Feb 13, 2022
3c25aa2
refactor: remove unnecessary get doc fn
CurryPseudo Feb 13, 2022
ef4f550
refactor: remove SoASlice trait
CurryPseudo Feb 13, 2022
aa94ebd
refactor: remove SoARef trait
CurryPseudo Feb 13, 2022
3850e81
refactor: remove SoAPtr trait
CurryPseudo Feb 13, 2022
1edd2fa
doc: add documentation of SoAIter
CurryPseudo Feb 13, 2022
ca6edaf
fix: add a mod in doc test to workaround https://github.com/rust-lang…
CurryPseudo Feb 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,41 @@ for (name, smell, color) in soa_zip!(vec, [name, mut smell, color]) {
}
```

## Nested Struct of Arrays

In order to nest a struct of arrays inside another struct of arrays, one can use the `#[nested_soa]` attribute.

For example, the following code

```rust
#[derive(StructOfArray)]
pub struct Point {
x: f32,
y: f32,
}
#[derive(StructOfArray)]
pub struct Particle {
#[nested_soa]
point: Point,
mass: f32,
}
```

will generate structs that looks like this:

```rust
pub struct PointVec {
x: Vec<f32>,
y: Vec<f32>,
}
pub struct ParticleVec {
point: PointVec, // rather than Vec<Point>
mass: Vec<f32>
}
```

All helper structs will be also nested, for example `PointSlice` will be nested in `ParticleSlice`.

## Documentation

Please see http://lumol.org/soa-derive/soa_derive_example/ for a small
Expand Down
7 changes: 4 additions & 3 deletions example/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
//! the code is generated by a single file:
//!
//! ```no_run
//! #[macro_use]
//! extern crate soa_derive;
//! # fn main() {
//! # mod particle {
//! #[macro_use]
//! use soa_derive::StructOfArray;
//!
//! /// A basic Particle type
//! #[derive(Debug, PartialEq, StructOfArray)]
//! #[soa_derive = "Debug, PartialEq"]
//! #[soa_derive(Debug, PartialEq)]
//! pub struct Particle {
//! /// Mass of the particle
//! pub mass: f64,
Expand Down
121 changes: 82 additions & 39 deletions soa-derive-internal/src/index.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,78 @@
use proc_macro2::TokenStream;
use quote::quote;

use crate::input::Input;
use crate::input::{Input, TokenStreamIterator};

pub fn derive(input: &Input) -> TokenStream {
let vec_name = &input.vec_name();
let slice_name = &input.slice_name();
let slice_mut_name = &input.slice_mut_name();
let ref_name = &input.ref_name();
let ref_mut_name = &input.ref_mut_name();
let slice_name = Input::slice_name(&input.name);
let slice_mut_name = Input::slice_mut_name(&input.name);
let ref_name = Input::ref_name(&input.name);
let ref_mut_name = Input::ref_mut_name(&input.name);
let fields_names = input.fields.iter()
.map(|field| field.ident.clone().unwrap())
.collect::<Vec<_>>();
let fields_names_1 = &fields_names;
let fields_names_2 = &fields_names;

let get_unchecked = input.iter_fields().map(
|(field_ident, _, is_nested)| {
if is_nested {
quote! {
#field_ident: self.clone().get_unchecked(slice.#field_ident),
}
}
else {
quote! {
#field_ident: slice.#field_ident.get_unchecked(self.clone()),
}
}
},
).concat();

let get_unchecked_mut = input.iter_fields().map(
|(field_ident, _, is_nested)| {
if is_nested {
quote! {
#field_ident: self.clone().get_unchecked_mut(slice.#field_ident),
}
}
else {
quote! {
#field_ident: slice.#field_ident.get_unchecked_mut(self.clone()),
}
}
},
).concat();

let index = input.iter_fields().map(
|(field_ident, _, is_nested)| {
if is_nested {
quote! {
#field_ident: self.clone().index(slice.#field_ident),
}
}
else {
quote! {
#field_ident: & slice.#field_ident[self.clone()],
}
}
},
).concat();

let index_mut = input.iter_fields().map(
|(field_ident, _, is_nested)| {
if is_nested {
quote! {
#field_ident: self.clone().index_mut(slice.#field_ident),
}
}
else {
quote! {
#field_ident: &mut slice.#field_ident[self.clone()],
}
}
},
).concat();

let first_field_name = &fields_names[0];

quote!{
Expand All @@ -32,16 +91,12 @@ pub fn derive(input: &Input) -> TokenStream {

#[inline]
unsafe fn get_unchecked(self, soa: &'a #vec_name) -> Self::RefOutput {
#ref_name {
#(#fields_names_1: soa.#fields_names_2.get_unchecked(self),)*
}
self.get_unchecked(soa.as_slice())
}

#[inline]
fn index(self, soa: &'a #vec_name) -> Self::RefOutput {
#ref_name {
#(#fields_names_1: & soa.#fields_names_2[self],)*
}
self.index(soa.as_slice())
}
}

Expand All @@ -59,16 +114,12 @@ pub fn derive(input: &Input) -> TokenStream {

#[inline]
unsafe fn get_unchecked_mut(self, soa: &'a mut #vec_name) -> Self::MutOutput {
#ref_mut_name {
#(#fields_names_1: soa.#fields_names_2.get_unchecked_mut(self),)*
}
self.get_unchecked_mut(soa.as_mut_slice())
}

#[inline]
fn index_mut(self, soa: &'a mut #vec_name) -> Self::MutOutput {
#ref_mut_name {
#(#fields_names_1: &mut soa.#fields_names_2[self],)*
}
self.index_mut(soa.as_mut_slice())
}
}

Expand All @@ -89,16 +140,12 @@ pub fn derive(input: &Input) -> TokenStream {

#[inline]
unsafe fn get_unchecked(self, soa: &'a #vec_name) -> Self::RefOutput {
#slice_name {
#(#fields_names_1: soa.#fields_names_2.get_unchecked(self.clone()),)*
}
self.get_unchecked(soa.as_slice())
}

#[inline]
fn index(self, soa: &'a #vec_name) -> Self::RefOutput {
#slice_name {
#(#fields_names_1: & soa.#fields_names_2[self.clone()],)*
}
self.index(soa.as_slice())
}
}

Expand All @@ -116,16 +163,12 @@ pub fn derive(input: &Input) -> TokenStream {

#[inline]
unsafe fn get_unchecked_mut(self, soa: &'a mut #vec_name) -> Self::MutOutput {
#slice_mut_name {
#(#fields_names_1: soa.#fields_names_2.get_unchecked_mut(self.clone()),)*
}
self.get_unchecked_mut(soa.as_mut_slice())
}

#[inline]
fn index_mut(self, soa: &'a mut #vec_name) -> Self::MutOutput {
#slice_mut_name {
#(#fields_names_1: &mut soa.#fields_names_2[self.clone()],)*
}
self.index_mut(soa.as_mut_slice())
}
}

Expand Down Expand Up @@ -354,14 +397,14 @@ pub fn derive(input: &Input) -> TokenStream {
#[inline]
unsafe fn get_unchecked(self, slice: #slice_name<'a>) -> Self::RefOutput {
#ref_name {
#(#fields_names_1: slice.#fields_names_2.get_unchecked(self),)*
#get_unchecked
}
}

#[inline]
fn index(self, slice: #slice_name<'a>) -> Self::RefOutput {
#ref_name {
#(#fields_names_1: & slice.#fields_names_2[self],)*
#index
}
}
}
Expand All @@ -381,14 +424,14 @@ pub fn derive(input: &Input) -> TokenStream {
#[inline]
unsafe fn get_unchecked_mut(self, slice: #slice_mut_name<'a>) -> Self::MutOutput {
#ref_mut_name {
#(#fields_names_1: slice.#fields_names_2.get_unchecked_mut(self),)*
#get_unchecked_mut
}
}

#[inline]
fn index_mut(self, slice: #slice_mut_name<'a>) -> Self::MutOutput {
#ref_mut_name {
#(#fields_names_1: &mut slice.#fields_names_2[self],)*
#index_mut
}
}
}
Expand All @@ -411,14 +454,14 @@ pub fn derive(input: &Input) -> TokenStream {
#[inline]
unsafe fn get_unchecked(self, slice: #slice_name<'a>) -> Self::RefOutput {
#slice_name {
#(#fields_names_1: slice.#fields_names_2.get_unchecked(self.clone()),)*
#get_unchecked
}
}

#[inline]
fn index(self, slice: #slice_name<'a>) -> Self::RefOutput {
#slice_name {
#(#fields_names_1: & slice.#fields_names_2[self.clone()],)*
#index
}
}
}
Expand All @@ -438,14 +481,14 @@ pub fn derive(input: &Input) -> TokenStream {
#[inline]
unsafe fn get_unchecked_mut(self, slice: #slice_mut_name<'a>) -> Self::MutOutput {
#slice_mut_name {
#(#fields_names_1: slice.#fields_names_2.get_unchecked_mut(self.clone()),)*
#get_unchecked_mut
}
}

#[inline]
fn index_mut(self, slice: #slice_mut_name<'a>) -> Self::MutOutput {
#slice_mut_name {
#(#fields_names_1: &mut slice.#fields_names_2[self.clone()],)*
#index_mut
}
}
}
Expand Down
Loading