Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit for soa using custom derive
- Loading branch information
0 parents
commit da06faa
Showing
4 changed files
with
129 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Cargo.lock | ||
target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "soa-derive" | ||
version = "0.1.0" | ||
authors = ["Luthaf <luthaf@luthaf.fr>"] | ||
repository = "https://github.com/lumol-org/soa-derive" | ||
license = "BSD" | ||
|
||
[dependencies] | ||
syn = "0.10" | ||
quote = "0.3" | ||
|
||
[lib] | ||
proc-macro = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
extern crate proc_macro; | ||
extern crate syn; | ||
#[macro_use] | ||
extern crate quote; | ||
|
||
use syn::{Body, VariantData, MacroInput}; | ||
use proc_macro::TokenStream; | ||
|
||
#[proc_macro_derive(StructOfArray)] | ||
pub fn soa_derive(input: TokenStream) -> TokenStream { | ||
let source = input.to_string(); | ||
let ast = syn::parse_macro_input(&source).unwrap(); | ||
let generated = derive_vec(&ast); | ||
generated.parse().unwrap() | ||
} | ||
|
||
fn derive_vec(input: &MacroInput) -> quote::Tokens { | ||
let ident = &input.ident; | ||
let soa_ident = quote::Ident::from(format!("{}Vec", input.ident)); | ||
let fields = match input.body { | ||
Body::Struct(ref data) => { | ||
match data { | ||
&VariantData::Struct(ref fields) => fields.clone(), | ||
_ => panic!("#[derive(SoA)] only supports structs."), | ||
} | ||
} | ||
_ => panic!("#[derive(SoA)] only supports structs."), | ||
}; | ||
|
||
let vec_fields = fields.iter() | ||
.map(|f| { | ||
let field_ident = f.ident.clone().unwrap(); | ||
let field_ty = &f.ty; | ||
quote!{ | ||
pub #field_ident: Vec<#field_ty> | ||
} | ||
}) | ||
.collect::<Vec<_>>(); | ||
|
||
let field_idents = fields.iter().map(|f| f.ident.clone().unwrap()).collect::<Vec<_>>(); | ||
let field_idents_1 = &field_idents; | ||
let field_idents_2 = &field_idents; | ||
|
||
let first_ident = &field_idents[0]; | ||
|
||
quote!{ | ||
#[derive(Debug)] | ||
struct #soa_ident { | ||
#( | ||
#vec_fields, | ||
)* | ||
} | ||
|
||
impl #soa_ident { | ||
pub fn new() -> Self { | ||
#soa_ident { | ||
#( | ||
#field_idents_1 : Vec::new(), | ||
)* | ||
} | ||
} | ||
|
||
pub fn push(&mut self, value: #ident) { | ||
let #ident{#(#field_idents_1),*} = value; | ||
#( | ||
self.#field_idents_1.push(#field_idents_2); | ||
)* | ||
} | ||
|
||
pub fn len(&self) -> usize { | ||
let len = self.#first_ident.len(); | ||
#( | ||
debug_assert_eq!(self.#field_idents_1.len(), len); | ||
)* | ||
len | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#[macro_use] | ||
extern crate soa_derive; | ||
|
||
#[derive(Debug, StructOfArray)] | ||
struct Particle { | ||
name: String, | ||
mass: f64 | ||
} | ||
|
||
impl Particle { | ||
pub fn new(name: String, mass: f64) -> Self { | ||
Particle { | ||
name: name, | ||
mass: mass, | ||
} | ||
} | ||
} | ||
|
||
#[test] | ||
fn push() { | ||
let mut particles = ParticleVec::new(); | ||
particles.push(Particle::new(String::from("Na"), 56.0)); | ||
|
||
assert_eq!(particles.name[0], "Na"); | ||
assert_eq!(particles.mass[0], 56.0); | ||
} | ||
|
||
#[test] | ||
fn len() { | ||
let mut particles = ParticleVec::new(); | ||
assert_eq!(particles.len(), 0); | ||
|
||
particles.push(Particle::new(String::from("Na"), 56.0)); | ||
assert_eq!(particles.len(), 1); | ||
} |