Skip to content

Commit

Permalink
Initial commit for soa using custom derive
Browse files Browse the repository at this point in the history
  • Loading branch information
Guillaume Fraux authored and Luthaf committed Mar 10, 2017
0 parents commit da06faa
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
Cargo.lock
target
13 changes: 13 additions & 0 deletions Cargo.toml
@@ -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
79 changes: 79 additions & 0 deletions src/lib.rs
@@ -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
}
}
}
}
35 changes: 35 additions & 0 deletions tests/derive.rs
@@ -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);
}

0 comments on commit da06faa

Please sign in to comment.