diff --git a/Cargo.toml b/Cargo.toml index 013e98b..e7720a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ keywords = ["soa", "dod", "data-oriented", "struct-of-array", "performance"] [features] default = ["std"] std = [] +tuple = ["layout_internal/tuple"] [workspace] members = ["layout-internal"] diff --git a/layout-internal/Cargo.toml b/layout-internal/Cargo.toml index a86a23f..ed9d51d 100644 --- a/layout-internal/Cargo.toml +++ b/layout-internal/Cargo.toml @@ -13,6 +13,9 @@ documentation = "https://docs.rs/layout/" [lib] proc-macro = true +[features] +tuple = [] + [dependencies] syn = { version = "2", features = ["derive", "extra-traits"] } quote = "1" diff --git a/layout-internal/src/iter.rs b/layout-internal/src/iter.rs index 9b7a6cd..ae4c30d 100644 --- a/layout-internal/src/iter.rs +++ b/layout-internal/src/iter.rs @@ -33,6 +33,23 @@ pub fn derive(input: &Input) -> TokenStream { .map(|field| field.ty.clone()) .collect::>(); + let tuple_from_iter_impl = if cfg!(feature = "tuple") { + quote! { + impl core::iter::FromIterator<(#(#fields_types,)*)> for #vec_name { + fn from_iter>(iter: T) -> Self { + let iterator = iter.into_iter(); + let size_hint = iterator.size_hint(); + let capacity = size_hint.1.unwrap_or(size_hint.0); + let mut result = #vec_name::with_capacity(capacity); + iterator.for_each(|(#(#fields_names,)*)| result.push(#name { #(#fields_names,)* })); + result + } + } + } + } else { + quote! {} + }; + let iter_type = input .map_fields_nested_or( |_, field_type| quote! { <#field_type as layout::SoAIter<'a>>::Iter }, @@ -274,6 +291,8 @@ pub fn derive(input: &Input) -> TokenStream { } } + #tuple_from_iter_impl + impl<'a, 'b> IntoIterator for &'a #slice_name<'b> { type Item = #ref_name<'a>; type IntoIter = #iter_name<'a>; diff --git a/tests/iter.rs b/tests/iter.rs index 6b6bd9c..ffc6e5f 100644 --- a/tests/iter.rs +++ b/tests/iter.rs @@ -70,6 +70,28 @@ fn from_iter() { assert_eq!(particles, particles_from_iter) } +#[cfg(feature = "tuple")] +#[test] +fn from_tuple_iter() { + let vec_with_particles = vec![ + Particle::new(String::from("Na"), 0.0), + Particle::new(String::from("Cl"), 1.0), + Particle::new(String::from("Zn"), 2.0), + ]; + + let particles_from_iter: ParticleVec = vec_with_particles + .iter() + .map(|particle| (particle.name.clone(), particle.mass)) + .collect(); + + let mut particles = ParticleVec::new(); + particles.push(Particle::new(String::from("Na"), 0.0)); + particles.push(Particle::new(String::from("Cl"), 1.0)); + particles.push(Particle::new(String::from("Zn"), 2.0)); + + assert_eq!(particles, particles_from_iter) +} + #[test] fn extend() { let vec_with_particles = vec![