From 7841e87df970d25e41fb702b94c367150b073d7f Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Fri, 10 Jan 2025 10:04:39 -0500 Subject: [PATCH 01/37] feat: add traits for sequence-like behaviors already implemented as concrete methods --- soa-derive-internal/src/iter.rs | 14 ++-- soa-derive-internal/src/ptr.rs | 5 ++ soa-derive-internal/src/refs.rs | 24 +++++++ soa-derive-internal/src/slice.rs | 40 ++++++++++++ soa-derive-internal/src/vec.rs | 90 ++++++++++++++++++++++++++ src/lib.rs | 106 ++++++++++++++++++++++++++++--- tests/particles/mod.rs | 7 ++ 7 files changed, 269 insertions(+), 17 deletions(-) diff --git a/soa-derive-internal/src/iter.rs b/soa-derive-internal/src/iter.rs index 1cdc71e..a1eacf5 100644 --- a/soa-derive-internal/src/iter.rs +++ b/soa-derive-internal/src/iter.rs @@ -124,7 +124,7 @@ pub fn derive(input: &Input) -> TokenStream { /// Get an iterator over the #[doc = #ref_doc_url] /// in this vector - pub fn iter(&self) -> #iter_name { + pub fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { self.as_slice().into_iter() } } @@ -133,14 +133,14 @@ pub fn derive(input: &Input) -> TokenStream { /// Get an iterator over the #[doc = #ref_doc_url] /// in this slice. - pub fn iter(&self) -> #iter_name { + pub fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { #iter_name(#create_iter) } /// Get an iterator over the #[doc = #ref_doc_url] /// in this slice. - pub fn into_iter(self) -> #iter_name<'a> { + pub fn into_iter(self) -> <#name as ::soa_derive::SoAIter<'a>>::Iter { #iter_name(#create_into_iter) } } @@ -188,7 +188,7 @@ pub fn derive(input: &Input) -> TokenStream { /// Get a mutable iterator over the #[doc = #ref_mut_doc_url] /// in this vector - pub fn iter_mut(&mut self) -> #iter_mut_name { + pub fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { self.as_mut_slice().into_iter() } } @@ -197,21 +197,21 @@ pub fn derive(input: &Input) -> TokenStream { /// Get an iterator over the #[doc = #ref_doc_url] /// in this vector - pub fn iter(&mut self) -> #iter_name { + pub fn iter(&mut self) -> <#name as ::soa_derive::SoAIter>::Iter { self.as_ref().into_iter() } /// Get a mutable iterator over the #[doc = #ref_mut_doc_url] /// in this vector - pub fn iter_mut(&mut self) -> #iter_mut_name { + pub fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { #iter_mut_name(#create_iter_mut) } /// Get a mutable iterator over the #[doc = #ref_mut_doc_url] /// in this vector - pub fn into_iter(self) -> #iter_mut_name<'a> { + pub fn into_iter(self) -> <#name as ::soa_derive::SoAIter<'a>>::IterMut { #iter_mut_name(#create_mut_into_iter) } } diff --git a/soa-derive-internal/src/ptr.rs b/soa-derive-internal/src/ptr.rs index 48627d6..65d2f81 100644 --- a/soa-derive-internal/src/ptr.rs +++ b/soa-derive-internal/src/ptr.rs @@ -187,6 +187,11 @@ pub fn derive(input: &Input) -> TokenStream { } } + impl ::soa_derive::SoAPointers for #name { + type Ptr = #ptr_name; + type MutPtr = #ptr_mut_name; + } + #[allow(dead_code)] #[allow(clippy::forget_non_drop)] impl #ptr_mut_name { diff --git a/soa-derive-internal/src/refs.rs b/soa-derive-internal/src/refs.rs index 9ab05b5..89eb921 100644 --- a/soa-derive-internal/src/refs.rs +++ b/soa-derive-internal/src/refs.rs @@ -142,6 +142,18 @@ pub fn derive(input: &Input) -> TokenStream { } } + impl<'a> From<#ref_name<'a>> for #name where #( for<'b> #fields_types: Clone, )* { + fn from(value: #ref_name<'a>) -> #name { + value.to_owned() + } + } + + impl<'a> From<&'a #ref_name<'a>> for #name where #( for<'b> #fields_types: Clone, )* { + fn from(value: &'a #ref_name<'a>) -> #name { + value.to_owned() + } + } + impl<'a> #ref_mut_name<'a> { /// Convert a mutable reference to #[doc = #doc_url] @@ -171,5 +183,17 @@ pub fn derive(input: &Input) -> TokenStream { #name{#(#fields_names: #fields_names_hygienic),*} } } + + impl<'a> From<#ref_mut_name<'a>> for #name where #( for<'b> #fields_types: Clone, )* { + fn from(value: #ref_mut_name<'a>) -> #name { + value.to_owned() + } + } + + impl<'a> From<&'a #ref_mut_name<'a>> for #name where #( for<'b> #fields_types: Clone, )* { + fn from(value: &'a #ref_mut_name<'a>) -> #name { + value.to_owned() + } + } } } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index 832f163..bd5ea3a 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -7,6 +7,7 @@ use crate::input::Input; use crate::names; pub fn derive(input: &Input) -> TokenStream { + let name = &input.name; let visibility = &input.visibility; let slice_name = names::slice_name(&input.name); let attrs = &input.attrs.slice; @@ -233,6 +234,22 @@ pub fn derive(input: &Input) -> TokenStream { } } } + + impl<'a> ::soa_derive::SoACollection for #slice_name<'a> { + type Scalar = #name; + + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn as_ptr(&self) -> ::Ptr { + self.as_ptr() + } + } }; if input.attrs.derive_clone { @@ -255,6 +272,7 @@ pub fn derive(input: &Input) -> TokenStream { } pub fn derive_mut(input: &Input) -> TokenStream { + let name = &input.name; let visibility = &input.visibility; let slice_name = names::slice_name(&input.name); let slice_mut_name = names::slice_mut_name(&input.name); @@ -657,6 +675,28 @@ pub fn derive_mut(input: &Input) -> TokenStream { self.apply_permutation(&mut permutation); } } + + impl<'a> ::soa_derive::SoACollection for #slice_mut_name<'a> { + type Scalar = #name; + + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn as_ptr(&self) -> ::Ptr { + self.as_ptr() + } + } + + impl<'a> ::soa_derive::SoACollectionMut for #slice_mut_name<'a> { + fn as_mut_ptr(&mut self) -> ::MutPtr { + self.as_mut_ptr() + } + } }; if input.attrs.derive_clone { diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index 8ae8307..6fa363a 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -445,6 +445,96 @@ pub fn derive(input: &Input) -> TokenStream { } } + impl ::soa_derive::SoACollection for #vec_name { + type Scalar = #name; + + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn as_ptr(&self) -> ::Ptr { + self.as_ptr() + } + } + + impl ::soa_derive::SoACollectionMut for #vec_name { + fn as_mut_ptr(&mut self) -> ::MutPtr { + self.as_mut_ptr() + } + } + impl ::soa_derive::SoAArray for #vec_name { + + + fn new() -> Self { + Self::new() + } + + fn with_capacity(capacity: usize) -> Self { + Self::with_capacity(capacity) + } + + fn capacity(&self) -> usize { + self.capacity() + } + + fn reserve(&mut self, additional: usize) { + self.reserve(additional) + } + + fn reserve_exact(&mut self, additional: usize) { + self.reserve_exact(additional) + } + + fn shrink_to_fit(&mut self) { + self.shrink_to_fit() + } + + fn truncate(&mut self, len: usize) { + self.truncate(len) + } + + fn push(&mut self, value: Self::Scalar) { + self.push(value) + } + + fn swap_remove(&mut self, index: usize) -> Self::Scalar { + self.swap_remove(index) + } + fn insert(&mut self, index: usize, element: Self::Scalar) { + self.insert(index, element); + } + fn replace(&mut self, index: usize, element: Self::Scalar) -> Self::Scalar { + self.replace(index, element) + } + fn remove(&mut self, index: usize) -> Self::Scalar { + self.remove(index) + } + + fn pop(&mut self) -> Option { + self.pop() + } + + fn append(&mut self, other: &mut Self) { + self.append(other) + } + + fn clear(&mut self) { + self.clear() + } + + fn split_off(&mut self, at: usize) -> Self { + self.split_off(at) + } + + fn iter<'a>(&'a self) -> <::Scalar as ::soa_derive::SoAIter<'a>>::Iter where ::Scalar: ::soa_derive::SoAIter<'a> { + self.iter() + } + } + #[allow(clippy::drop_non_drop)] impl Drop for #vec_name { fn drop(&mut self) { diff --git a/src/lib.rs b/src/lib.rs index 63f8dfa..8975d9c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -188,13 +188,13 @@ //! # } //! # } //! ``` -//! +//! //! ## 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 -//! +//! //! ``` //! # mod cheese { //! # use soa_derive::StructOfArray; @@ -211,9 +211,9 @@ //! } //! # } //! ``` -//! +//! //! will generate structs that looks like this: -//! +//! //! ``` //! pub struct PointVec { //! x: Vec, @@ -224,7 +224,7 @@ //! mass: Vec //! } //! ``` -//! +//! //! All helper structs will be also nested, for example `PointSlice` will be nested in `ParticleSlice`. // The proc macro is implemented in soa_derive_internal, and re-exported by this @@ -246,11 +246,11 @@ pub trait StructOfArray { } /// Any struct derived by StructOfArray will auto impl this trait. -/// +/// /// Useful for generic programming and implementation of attribute `nested_soa`. -/// +/// /// `CheeseVec::iter(&'a self)` returns an iterator which has a type `>::Iter` -/// +/// /// `CheeseVec::iter_mut(&mut 'a self)` returns an iterator which has a type `>::IterMut` pub trait SoAIter<'a> { type Iter: 'a; @@ -384,6 +384,92 @@ macro_rules! soa_zip { }}; } +type IdxRange = ::std::ops::Range; +type RangeFull = ::std::ops::RangeFull; + +pub trait SoAPointers { + type Ptr; + type MutPtr; +} + +pub trait SoACollection { + type Scalar: SoAPointers; + + fn len(&self) -> usize; + fn is_empty(&self) -> bool { + self.len() == 0 + } + + fn as_slice<'a>(&'a self) -> >::RefOutput where RangeFull: crate::SoAIndex<&'a Self> { + (..).index(self) + } + + fn slice<'a>(&'a self, range: IdxRange) -> >::RefOutput where IdxRange: crate::SoAIndex<&'a Self> { + range.index(self) + } + + + fn get<'a, I>(&'a self, index: I) -> Option<>::RefOutput> where I: crate::SoAIndex<&'a Self> { + index.get(self) + } + + fn index<'a, I>(&'a self, index: I) -> >::RefOutput where I: crate::SoAIndex<&'a Self> { + index.index(self) + } + + fn as_ptr(&self) -> ::Ptr; +} + + +pub trait SoACollectionMut: SoACollection { + + fn slice_mut<'a>(&'a mut self, range: IdxRange) -> >::MutOutput where IdxRange: crate::SoAIndexMut<&'a Self> { + range.index_mut(self) + } + + fn get_mut<'a, I>(&'a mut self, index: I) -> Option where I: crate::SoAIndexMut<&'a Self> { + index.get_mut(self) + } + + fn index_mut<'a, I>(&'a mut self, index: I) -> I::MutOutput where I: crate::SoAIndexMut<&'a Self> { + index.index_mut(self) + } + + fn as_mut_slice<'a>(&'a mut self) -> >::MutOutput where RangeFull: crate::SoAIndexMut<&'a Self> { + (..).index_mut(self) + } + + fn as_mut_ptr(&mut self) -> ::MutPtr; +} + +pub trait SoAArray: SoACollection + SoACollectionMut { + + fn new() -> Self; + fn with_capacity(capacity: usize) -> Self; + fn capacity(&self) -> usize; + fn reserve(&mut self, additional: usize); + fn reserve_exact(&mut self, additional: usize); + fn shrink_to_fit(&mut self); + fn truncate(&mut self, len: usize); + fn push(&mut self, value: Self::Scalar); + + fn swap_remove(&mut self, index: usize) -> Self::Scalar; + fn insert(&mut self, index: usize, element: Self::Scalar); + fn replace(&mut self, index: usize, element: Self::Scalar) -> Self::Scalar; + fn remove(&mut self, index: usize) -> Self::Scalar; + fn pop(&mut self) -> Option; + fn append(&mut self, other: &mut Self); + fn clear(&mut self); + fn split_off(&mut self, at: usize) -> Self; + + fn iter<'a>(&'a self) -> <::Scalar as SoAIter<'a>>::Iter where ::Scalar: SoAIter<'a>; +} + +pub trait SoACollectionIter<'a>: SoACollection where ::Scalar: SoAIter<'a> { + // fn iter(&'a self) -> <::Scalar as SoAIter>::Iter; +} + + #[macro_export] #[doc(hidden)] macro_rules! soa_zip_impl { diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index 52b815f..cdeb82a 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -15,3 +15,10 @@ impl Particle { } } } + + +impl ParticleVec { + fn my_iter(&self) -> ::Iter { + self.iter() + } +} From ff43c47115eccf4068e32bfe71f69c07252f2615 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Fri, 10 Jan 2025 10:07:37 -0500 Subject: [PATCH 02/37] remove dead code --- tests/particles/mod.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index cdeb82a..52b815f 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -15,10 +15,3 @@ impl Particle { } } } - - -impl ParticleVec { - fn my_iter(&self) -> ::Iter { - self.iter() - } -} From a96d8ff49409ce564b3c06494c60ab2e117d0abb Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Fri, 10 Jan 2025 10:30:52 -0500 Subject: [PATCH 03/37] checkpoint --- soa-derive-internal/src/slice.rs | 9 +++++++++ soa-derive-internal/src/vec.rs | 8 ++++---- src/lib.rs | 27 +++++++++++++++++++++------ tests/particles/mod.rs | 8 +++++++- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index bd5ea3a..bb3c619 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -249,6 +249,10 @@ pub fn derive(input: &Input) -> TokenStream { fn as_ptr(&self) -> ::Ptr { self.as_ptr() } + + fn iter<'b>(&'b self) -> <::Scalar as ::soa_derive::SoAIter<'b>>::Iter where ::Scalar: ::soa_derive::SoAIter<'b> { + self.iter() + } } }; @@ -690,6 +694,11 @@ pub fn derive_mut(input: &Input) -> TokenStream { fn as_ptr(&self) -> ::Ptr { self.as_ptr() } + + + fn iter<'b>(&'b self) -> <::Scalar as ::soa_derive::SoAIter<'b>>::Iter where ::Scalar: ::soa_derive::SoAIter<'b> { + self.iter() + } } impl<'a> ::soa_derive::SoACollectionMut for #slice_mut_name<'a> { diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index 6fa363a..c609fd6 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -459,6 +459,10 @@ pub fn derive(input: &Input) -> TokenStream { fn as_ptr(&self) -> ::Ptr { self.as_ptr() } + + fn iter<'a>(&'a self) -> <::Scalar as ::soa_derive::SoAIter<'a>>::Iter where ::Scalar: ::soa_derive::SoAIter<'a> { + self.iter() + } } impl ::soa_derive::SoACollectionMut for #vec_name { @@ -529,10 +533,6 @@ pub fn derive(input: &Input) -> TokenStream { fn split_off(&mut self, at: usize) -> Self { self.split_off(at) } - - fn iter<'a>(&'a self) -> <::Scalar as ::soa_derive::SoAIter<'a>>::Iter where ::Scalar: ::soa_derive::SoAIter<'a> { - self.iter() - } } #[allow(clippy::drop_non_drop)] diff --git a/src/lib.rs b/src/lib.rs index 8975d9c..8a3f652 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -392,6 +392,25 @@ pub trait SoAPointers { type MutPtr; } + +pub trait IsIndexed<'a>: 'a where + usize: SoAIndex<&'a Self>, + IdxRange: SoAIndex<&'a Self>, + RangeFull: SoAIndex<&'a Self> {} + + +impl<'a, T: 'a> IsIndexed<'a> for T where usize: SoAIndex<&'a Self>, IdxRange: SoAIndex<&'a Self>, RangeFull: SoAIndex<&'a Self> {} + + +pub trait IsIndexedMut<'a>: 'a where + usize: SoAIndexMut<&'a mut Self>, + IdxRange: SoAIndexMut<&'a mut Self>, + RangeFull: SoAIndexMut<&'a mut Self> {} + + +impl<'a, T: 'a> IsIndexedMut<'a> for T where usize: SoAIndexMut<&'a mut Self>, IdxRange: SoAIndexMut<&'a mut Self>, RangeFull: SoAIndexMut<&'a mut Self> {} + + pub trait SoACollection { type Scalar: SoAPointers; @@ -417,6 +436,8 @@ pub trait SoACollection { index.index(self) } + fn iter<'a>(&'a self) -> <::Scalar as SoAIter<'a>>::Iter where ::Scalar: SoAIter<'a>; + fn as_ptr(&self) -> ::Ptr; } @@ -461,12 +482,6 @@ pub trait SoAArray: SoACollection + SoACollectionMut { fn append(&mut self, other: &mut Self); fn clear(&mut self); fn split_off(&mut self, at: usize) -> Self; - - fn iter<'a>(&'a self) -> <::Scalar as SoAIter<'a>>::Iter where ::Scalar: SoAIter<'a>; -} - -pub trait SoACollectionIter<'a>: SoACollection where ::Scalar: SoAIter<'a> { - // fn iter(&'a self) -> <::Scalar as SoAIter>::Iter; } diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index 52b815f..f6048b9 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -1,4 +1,4 @@ -use soa_derive::StructOfArray; +use soa_derive::{StructOfArray, SoAArray, SoACollection}; #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] @@ -15,3 +15,9 @@ impl Particle { } } } + + + +// fn may_i_do_this(vec: &T) { +// let x = vec.get(0usize); +// } \ No newline at end of file From a82e41f074d247563980bca011d55d1a5c673ba7 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Fri, 10 Jan 2025 15:35:13 -0500 Subject: [PATCH 04/37] Switch to lifetime-bound traits not directly attached to `StructOfArrays` --- soa-derive-internal/src/lib.rs | 8 +++ soa-derive-internal/src/slice.rs | 112 +++++++++++++++++++++++++++---- soa-derive-internal/src/vec.rs | 91 ++++++++++++++++++++----- src/lib.rs | 108 +++++++++++------------------ tests/generic.rs | 18 +++++ tests/nested_soa.rs | 23 ++++++- tests/particles/mod.rs | 6 +- 7 files changed, 263 insertions(+), 103 deletions(-) create mode 100644 tests/generic.rs diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index 64027ca..cab9c12 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -42,10 +42,18 @@ use quote::quote; fn derive_trait(input: &Input) -> TokenStream { let name = &input.name; let vec_name = names::vec_name(name); + let slice_name = names::slice_name(name); + let slice_mut_name = names::slice_mut_name(name); quote! { impl soa_derive::StructOfArray for #name { type Type = #vec_name; } + + impl<'a> soa_derive::SoATypes<'a> for #name { + type Vec = #vec_name; + type Slice = #slice_name<'a>; + type MutSlice = #slice_mut_name<'a>; + } } } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index bb3c619..563e20b 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -235,8 +235,9 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoACollection for #slice_name<'a> { - type Scalar = #name; + impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_name<'a> { + type Ref = #ref_name<'a>; + type Slice = #slice_name<'a>; fn len(&self) -> usize { self.len() @@ -246,13 +247,39 @@ pub fn derive(input: &Input) -> TokenStream { self.is_empty() } - fn as_ptr(&self) -> ::Ptr { - self.as_ptr() + fn as_slice(&'a self) -> Self::Slice { + self.as_slice() + } + + fn slice(&'a self, index: impl core::ops::RangeBounds) -> Self::Slice { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.as_slice().len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => self.as_slice().len(), + }; + self.slice(start..end) + } + + fn index(&'a self, index: usize) -> Self::Ref { + self.index(index) + } + + fn get(&'a self, index: usize) -> Option { + self.get(index) } - fn iter<'b>(&'b self) -> <::Scalar as ::soa_derive::SoAIter<'b>>::Iter where ::Scalar: ::soa_derive::SoAIter<'b> { + fn iter(&'a self) -> <#name as ::soa_derive::SoAIter<'a>>::Iter { self.iter() } + + fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { + self.as_ptr() + } } }; @@ -680,8 +707,9 @@ pub fn derive_mut(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoACollection for #slice_mut_name<'a> { - type Scalar = #name; + impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_mut_name<'a> { + type Ref = #ref_name<'a>; + type Slice = #slice_name<'a>; fn len(&self) -> usize { self.len() @@ -691,20 +719,80 @@ pub fn derive_mut(input: &Input) -> TokenStream { self.is_empty() } - fn as_ptr(&self) -> ::Ptr { - self.as_ptr() + fn as_slice(&'a self) -> Self::Slice { + self.as_slice() + } + + fn slice(&'a self, index: impl core::ops::RangeBounds) -> Self::Slice { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.as_slice().len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => self.as_slice().len(), + }; + self.slice(start..end) + } + + fn index(&'a self, index: usize) -> Self::Ref { + self.index(index) } + fn get(&'a self, index: usize) -> Option { + self.get(index) + } - fn iter<'b>(&'b self) -> <::Scalar as ::soa_derive::SoAIter<'b>>::Iter where ::Scalar: ::soa_derive::SoAIter<'b> { + fn iter(&'a self) -> <#name as ::soa_derive::SoAIter<'a>>::Iter { self.iter() } + + fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { + self.as_ptr() + } } - impl<'a> ::soa_derive::SoACollectionMut for #slice_mut_name<'a> { - fn as_mut_ptr(&mut self) -> ::MutPtr { + impl<'a> ::soa_derive::SoAMutSlice<'a, #name> for #slice_mut_name<'a> { + type RefMut = #ref_mut_name<'a>; + + type SliceMut = #slice_mut_name<'a>; + + fn as_mut_slice(&'a mut self) -> Self::SliceMut { + self.as_mut_slice() + } + + fn index_mut(&'a mut self, index: usize) -> Self::RefMut { + self.index_mut(index) + } + + fn slice_mut(&'a mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.as_slice().len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => self.as_slice().len(), + }; + self.slice_mut(start..end) + } + + fn get_mut(&'a mut self, index: usize) -> Option { + self.get_mut(index) + } + + fn iter_mut(&'a mut self) -> <#name as ::soa_derive::SoAIter<'a>>::IterMut { + self.iter_mut() + } + + fn as_mut_ptr(&mut self) -> <#name as ::soa_derive::SoAPointers>::MutPtr { self.as_mut_ptr() } + } }; diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index c609fd6..6026f59 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -445,8 +445,9 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl ::soa_derive::SoACollection for #vec_name { - type Scalar = #name; + impl<'a> ::soa_derive::SoASlice<'a, #name> for #vec_name { + type Ref = #ref_name<'a>; + type Slice = #slice_name<'a>; fn len(&self) -> usize { self.len() @@ -456,23 +457,83 @@ pub fn derive(input: &Input) -> TokenStream { self.is_empty() } - fn as_ptr(&self) -> ::Ptr { - self.as_ptr() + fn as_slice(&'a self) -> Self::Slice { + self.as_slice() + } + + fn slice(&'a self, index: impl core::ops::RangeBounds) -> Self::Slice { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.as_slice().len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => self.as_slice().len(), + }; + self.slice(start..end) + } + + fn index(&'a self, index: usize) -> Self::Ref { + self.index(index) + } + + fn get(&'a self, index: usize) -> Option { + self.get(index) } - fn iter<'a>(&'a self) -> <::Scalar as ::soa_derive::SoAIter<'a>>::Iter where ::Scalar: ::soa_derive::SoAIter<'a> { + fn iter(&'a self) -> <#name as ::soa_derive::SoAIter<'a>>::Iter { self.iter() } + + fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { + self.as_ptr() + } } - impl ::soa_derive::SoACollectionMut for #vec_name { - fn as_mut_ptr(&mut self) -> ::MutPtr { + impl<'a> ::soa_derive::SoAMutSlice<'a, #name> for #vec_name { + type RefMut = #ref_mut_name<'a>; + + type SliceMut = #slice_mut_name<'a>; + + fn as_mut_slice(&'a mut self) -> Self::SliceMut { + self.as_mut_slice() + } + + fn index_mut(&'a mut self, index: usize) -> Self::RefMut { + self.index_mut(index) + } + + fn slice_mut(&'a mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.as_slice().len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => self.as_slice().len(), + }; + self.slice_mut(start..end) + } + + fn get_mut(&'a mut self, index: usize) -> Option { + self.get_mut(index) + } + + fn iter_mut(&'a mut self) -> <#name as ::soa_derive::SoAIter<'a>>::IterMut { + self.iter_mut() + } + + fn as_mut_ptr(&mut self) -> <#name as ::soa_derive::SoAPointers>::MutPtr { self.as_mut_ptr() } - } - impl ::soa_derive::SoAArray for #vec_name { + } + impl<'a> ::soa_derive::SoAVec<'a, #name> for #vec_name { fn new() -> Self { Self::new() } @@ -501,24 +562,24 @@ pub fn derive(input: &Input) -> TokenStream { self.truncate(len) } - fn push(&mut self, value: Self::Scalar) { + fn push(&mut self, value: #name) { self.push(value) } - fn swap_remove(&mut self, index: usize) -> Self::Scalar { + fn swap_remove(&mut self, index: usize) -> #name { self.swap_remove(index) } - fn insert(&mut self, index: usize, element: Self::Scalar) { + fn insert(&mut self, index: usize, element: #name) { self.insert(index, element); } - fn replace(&mut self, index: usize, element: Self::Scalar) -> Self::Scalar { + fn replace(&mut self, index: usize, element: #name) -> #name { self.replace(index, element) } - fn remove(&mut self, index: usize) -> Self::Scalar { + fn remove(&mut self, index: usize) -> #name { self.remove(index) } - fn pop(&mut self) -> Option { + fn pop(&mut self) -> Option<#name> { self.pop() } diff --git a/src/lib.rs b/src/lib.rs index 8a3f652..5272cf4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -384,87 +384,45 @@ macro_rules! soa_zip { }}; } -type IdxRange = ::std::ops::Range; -type RangeFull = ::std::ops::RangeFull; - pub trait SoAPointers { type Ptr; type MutPtr; } +pub trait SoAProps<'a> : StructOfArray + SoAIter<'a> + SoAPointers {} -pub trait IsIndexed<'a>: 'a where - usize: SoAIndex<&'a Self>, - IdxRange: SoAIndex<&'a Self>, - RangeFull: SoAIndex<&'a Self> {} - - -impl<'a, T: 'a> IsIndexed<'a> for T where usize: SoAIndex<&'a Self>, IdxRange: SoAIndex<&'a Self>, RangeFull: SoAIndex<&'a Self> {} - - -pub trait IsIndexedMut<'a>: 'a where - usize: SoAIndexMut<&'a mut Self>, - IdxRange: SoAIndexMut<&'a mut Self>, - RangeFull: SoAIndexMut<&'a mut Self> {} - +impl<'a, T> SoAProps<'a> for T where T: StructOfArray + SoAIter<'a> + SoAPointers {} -impl<'a, T: 'a> IsIndexedMut<'a> for T where usize: SoAIndexMut<&'a mut Self>, IdxRange: SoAIndexMut<&'a mut Self>, RangeFull: SoAIndexMut<&'a mut Self> {} - - -pub trait SoACollection { - type Scalar: SoAPointers; +pub trait SoASlice<'a, T: SoAProps<'a>> { + type Ref; + type Slice; fn len(&self) -> usize; - fn is_empty(&self) -> bool { - self.len() == 0 - } - - fn as_slice<'a>(&'a self) -> >::RefOutput where RangeFull: crate::SoAIndex<&'a Self> { - (..).index(self) - } - - fn slice<'a>(&'a self, range: IdxRange) -> >::RefOutput where IdxRange: crate::SoAIndex<&'a Self> { - range.index(self) - } - + fn is_empty(&self) -> bool; - fn get<'a, I>(&'a self, index: I) -> Option<>::RefOutput> where I: crate::SoAIndex<&'a Self> { - index.get(self) - } + fn as_slice(&'a self) -> Self::Slice; + fn index(&'a self, index: usize) -> Self::Ref; + fn slice(&'a self, index: impl core::ops::RangeBounds) -> Self::Slice; + fn get(&'a self, index: usize) -> Option; + fn iter(&'a self) -> T::Iter; - fn index<'a, I>(&'a self, index: I) -> >::RefOutput where I: crate::SoAIndex<&'a Self> { - index.index(self) - } - - fn iter<'a>(&'a self) -> <::Scalar as SoAIter<'a>>::Iter where ::Scalar: SoAIter<'a>; - - fn as_ptr(&self) -> ::Ptr; + fn as_ptr(&self) -> T::Ptr; } +pub trait SoAMutSlice<'a, T: SoAProps<'a>>: SoASlice<'a, T> { + type RefMut; + type SliceMut; -pub trait SoACollectionMut: SoACollection { - - fn slice_mut<'a>(&'a mut self, range: IdxRange) -> >::MutOutput where IdxRange: crate::SoAIndexMut<&'a Self> { - range.index_mut(self) - } - - fn get_mut<'a, I>(&'a mut self, index: I) -> Option where I: crate::SoAIndexMut<&'a Self> { - index.get_mut(self) - } - - fn index_mut<'a, I>(&'a mut self, index: I) -> I::MutOutput where I: crate::SoAIndexMut<&'a Self> { - index.index_mut(self) - } - - fn as_mut_slice<'a>(&'a mut self) -> >::MutOutput where RangeFull: crate::SoAIndexMut<&'a Self> { - (..).index_mut(self) - } + fn as_mut_slice(&'a mut self) -> Self::SliceMut; + fn index_mut(&'a mut self, index: usize) -> Self::RefMut; + fn slice_mut(&'a mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut; + fn get_mut(&'a mut self, index: usize) -> Option; + fn iter_mut(&'a mut self) -> T::IterMut; - fn as_mut_ptr(&mut self) -> ::MutPtr; + fn as_mut_ptr(&mut self) -> T::MutPtr; } -pub trait SoAArray: SoACollection + SoACollectionMut { - +pub trait SoAVec<'a, T: SoAProps<'a>>: SoASlice<'a, T> + SoAMutSlice<'a, T> { fn new() -> Self; fn with_capacity(capacity: usize) -> Self; fn capacity(&self) -> usize; @@ -472,18 +430,28 @@ pub trait SoAArray: SoACollection + SoACollectionMut { fn reserve_exact(&mut self, additional: usize); fn shrink_to_fit(&mut self); fn truncate(&mut self, len: usize); - fn push(&mut self, value: Self::Scalar); + fn push(&mut self, value: T); - fn swap_remove(&mut self, index: usize) -> Self::Scalar; - fn insert(&mut self, index: usize, element: Self::Scalar); - fn replace(&mut self, index: usize, element: Self::Scalar) -> Self::Scalar; - fn remove(&mut self, index: usize) -> Self::Scalar; - fn pop(&mut self) -> Option; + fn swap_remove(&mut self, index: usize) -> T; + fn insert(&mut self, index: usize, element: T); + fn replace(&mut self, index: usize, element: T) -> T; + fn remove(&mut self, index: usize) -> T; + fn pop(&mut self) -> Option; fn append(&mut self, other: &mut Self); fn clear(&mut self); fn split_off(&mut self, at: usize) -> Self; } +pub trait SoATypes<'a>: SoAProps<'a> + Sized { + type Vec: SoAVec<'a, Self>; + type Slice: SoASlice<'a, Self>; + type MutSlice: SoAMutSlice<'a, Self>; +} + +pub mod prelude { + pub use super::{SoAVec, SoAIter, SoAProps, SoASlice, SoAMutSlice, SoAPointers, SoATypes, StructOfArray}; +} + #[macro_export] #[doc(hidden)] diff --git a/tests/generic.rs b/tests/generic.rs new file mode 100644 index 0000000..b8a0976 --- /dev/null +++ b/tests/generic.rs @@ -0,0 +1,18 @@ +use soa_derive::prelude::*; + +mod particles; +use self::particles::Particle; + +fn may_i_do_this<'a, T: SoATypes<'a>>(vec: &'a T::Vec) -> T::Iter { + let x= vec.iter(); + x +} + +#[test] +fn test_generic_type_behavior() { + let mut x = ::Vec::new(); + x.push(Particle::new("foo".into(), 100.0)); + let y: Vec<_> = may_i_do_this::(&x).collect(); + assert_eq!(x.len(), y.len()); + assert_eq!(x.get(0).as_ref(), y.get(0)); +} \ No newline at end of file diff --git a/tests/nested_soa.rs b/tests/nested_soa.rs index 3a91dea..946b5ba 100644 --- a/tests/nested_soa.rs +++ b/tests/nested_soa.rs @@ -1,4 +1,4 @@ -use soa_derive::StructOfArray; +use soa_derive::{StructOfArray, prelude::*}; #[derive(Debug, Clone, PartialEq, StructOfArray)] pub struct Point { @@ -58,3 +58,24 @@ fn nested_soa() { a: vec![255, 23], }); } + +fn generic_f<'a, T: SoATypes<'a>>(vec: &'a T::Vec) { + assert_eq!(vec.len(), 2); +} + +#[test] +fn test_nested_generic() { + let mut particle_vec = ParticleVec::new(); + particle_vec.push(Particle { + point: Point { x: 1.0, y: 2.0 }, + color: Color { r: 255, g: 0, b: 0, a: 255 }, + mass: 1.0, + }); + particle_vec.push(Particle { + point: Point { x: 2.0, y: 3.0 }, + color: Color { r: 128, g: 255, b: 100, a: 23 }, + mass: 2.0, + }); + + generic_f::(&particle_vec); +} \ No newline at end of file diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index f6048b9..b54bcc1 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -1,4 +1,4 @@ -use soa_derive::{StructOfArray, SoAArray, SoACollection}; +use soa_derive::StructOfArray; #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] @@ -17,7 +17,3 @@ impl Particle { } - -// fn may_i_do_this(vec: &T) { -// let x = vec.get(0usize); -// } \ No newline at end of file From 38029d9c1f95637dd3e775ed4e1bf3b72fe1d103 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Fri, 10 Jan 2025 18:33:45 -0500 Subject: [PATCH 05/37] checkpoint two lifetimes --- soa-derive-internal/src/iter.rs | 2 ++ soa-derive-internal/src/lib.rs | 6 +++++- soa-derive-internal/src/slice.rs | 6 +++--- soa-derive-internal/src/vec.rs | 7 +++---- src/lib.rs | 28 +++++++++++++++++++--------- tests/generic.rs | 2 +- tests/nested_soa.rs | 2 +- tests/particles/mod.rs | 24 +++++++++++++++++++++++- 8 files changed, 57 insertions(+), 20 deletions(-) diff --git a/soa-derive-internal/src/iter.rs b/soa-derive-internal/src/iter.rs index a1eacf5..00ea08a 100644 --- a/soa-derive-internal/src/iter.rs +++ b/soa-derive-internal/src/iter.rs @@ -217,6 +217,8 @@ pub fn derive(input: &Input) -> TokenStream { } impl<'a> soa_derive::SoAIter<'a> for #name { + type Ref = #ref_name<'a>; + type RefMut = #ref_mut_name<'a>; type Iter = #iter_name<'a>; type IterMut = #iter_mut_name<'a>; } diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index cab9c12..4ae48d8 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -44,16 +44,20 @@ fn derive_trait(input: &Input) -> TokenStream { let vec_name = names::vec_name(name); let slice_name = names::slice_name(name); let slice_mut_name = names::slice_mut_name(name); + let ref_name = names::ref_name(name); + let ref_mut_name = names::ref_mut_name(name); quote! { impl soa_derive::StructOfArray for #name { type Type = #vec_name; } - impl<'a> soa_derive::SoATypes<'a> for #name { + impl<'a: 'b, 'b> soa_derive::SoATypes<'a, 'b> for #name { type Vec = #vec_name; type Slice = #slice_name<'a>; type MutSlice = #slice_mut_name<'a>; + type Ref = #ref_name<'a>; + type RefMut = #ref_mut_name<'a>; } } } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index 563e20b..e9ac5c6 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -235,7 +235,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_name<'a> { + impl<'a: 'b, 'b> ::soa_derive::SoASlice<'a, 'b, #name> for #slice_name<'a> { type Ref = #ref_name<'a>; type Slice = #slice_name<'a>; @@ -707,7 +707,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_mut_name<'a> { + impl<'a: 'b, 'b> ::soa_derive::SoASlice<'a, 'b, #name> for #slice_mut_name<'a> { type Ref = #ref_name<'a>; type Slice = #slice_name<'a>; @@ -754,7 +754,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAMutSlice<'a, #name> for #slice_mut_name<'a> { + impl<'a: 'b, 'b> ::soa_derive::SoAMutSlice<'a, 'b, #name> for #slice_mut_name<'a> { type RefMut = #ref_mut_name<'a>; type SliceMut = #slice_mut_name<'a>; diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index 6026f59..e73c4d0 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -445,7 +445,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoASlice<'a, #name> for #vec_name { + impl<'a: 'b, 'b> ::soa_derive::SoASlice<'a, 'b, #name> for #vec_name { type Ref = #ref_name<'a>; type Slice = #slice_name<'a>; @@ -492,7 +492,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAMutSlice<'a, #name> for #vec_name { + impl<'a: 'b, 'b> ::soa_derive::SoAMutSlice<'a, 'b, #name> for #vec_name { type RefMut = #ref_mut_name<'a>; type SliceMut = #slice_mut_name<'a>; @@ -530,10 +530,9 @@ pub fn derive(input: &Input) -> TokenStream { fn as_mut_ptr(&mut self) -> <#name as ::soa_derive::SoAPointers>::MutPtr { self.as_mut_ptr() } - } - impl<'a> ::soa_derive::SoAVec<'a, #name> for #vec_name { + impl<'a: 'b, 'b> ::soa_derive::SoAVec<'a, 'b, #name> for #vec_name { fn new() -> Self { Self::new() } diff --git a/src/lib.rs b/src/lib.rs index 5272cf4..428984e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -253,8 +253,10 @@ pub trait StructOfArray { /// /// `CheeseVec::iter_mut(&mut 'a self)` returns an iterator which has a type `>::IterMut` pub trait SoAIter<'a> { - type Iter: 'a; - type IterMut: 'a; + type Ref; + type RefMut; + type Iter: 'a + Iterator + IntoIterator; + type IterMut: 'a + Iterator + IntoIterator; } mod private_soa_indexes { @@ -393,7 +395,7 @@ pub trait SoAProps<'a> : StructOfArray + SoAIter<'a> + SoAPointers {} impl<'a, T> SoAProps<'a> for T where T: StructOfArray + SoAIter<'a> + SoAPointers {} -pub trait SoASlice<'a, T: SoAProps<'a>> { +pub trait SoASlice<'a: 'b, 'b, T: SoAProps<'a>> { type Ref; type Slice; @@ -409,7 +411,7 @@ pub trait SoASlice<'a, T: SoAProps<'a>> { fn as_ptr(&self) -> T::Ptr; } -pub trait SoAMutSlice<'a, T: SoAProps<'a>>: SoASlice<'a, T> { +pub trait SoAMutSlice<'a: 'b, 'b, T: SoAProps<'a>>: SoASlice<'a, 'b, T> { type RefMut; type SliceMut; @@ -422,7 +424,13 @@ pub trait SoAMutSlice<'a, T: SoAProps<'a>>: SoASlice<'a, T> { fn as_mut_ptr(&mut self) -> T::MutPtr; } -pub trait SoAVec<'a, T: SoAProps<'a>>: SoASlice<'a, T> + SoAMutSlice<'a, T> { +// pub trait SoASort<'a, T: SoAProps<'a>>: SoAMutSlice<'a, 'b, T> { +// fn sort_by(&mut self, f: F) +// where +// F: FnMut(Self::Ref, Self::Ref) -> std::cmp::Ordering; +// } + +pub trait SoAVec<'a: 'b, 'b, T: SoAProps<'a>>: SoASlice<'a, 'b, T> + SoAMutSlice<'a, 'b, T> { fn new() -> Self; fn with_capacity(capacity: usize) -> Self; fn capacity(&self) -> usize; @@ -442,10 +450,12 @@ pub trait SoAVec<'a, T: SoAProps<'a>>: SoASlice<'a, T> + SoAMutSlice<'a, T> { fn split_off(&mut self, at: usize) -> Self; } -pub trait SoATypes<'a>: SoAProps<'a> + Sized { - type Vec: SoAVec<'a, Self>; - type Slice: SoASlice<'a, Self>; - type MutSlice: SoAMutSlice<'a, Self>; +pub trait SoATypes<'a: 'b, 'b>: SoAProps<'a> + Sized { + type Vec: SoAVec<'a, 'b, Self>; + type Slice: SoASlice<'a, 'b, Self>; + type MutSlice: SoAMutSlice<'a, 'b, Self>; + type Ref: 'a; + type RefMut: 'a; } pub mod prelude { diff --git a/tests/generic.rs b/tests/generic.rs index b8a0976..81fdb0f 100644 --- a/tests/generic.rs +++ b/tests/generic.rs @@ -3,7 +3,7 @@ use soa_derive::prelude::*; mod particles; use self::particles::Particle; -fn may_i_do_this<'a, T: SoATypes<'a>>(vec: &'a T::Vec) -> T::Iter { +fn may_i_do_this<'a: 'b, 'b, T: SoATypes<'a, 'b>>(vec: &'a T::Vec) -> T::Iter { let x= vec.iter(); x } diff --git a/tests/nested_soa.rs b/tests/nested_soa.rs index 946b5ba..bfc1e9d 100644 --- a/tests/nested_soa.rs +++ b/tests/nested_soa.rs @@ -59,7 +59,7 @@ fn nested_soa() { }); } -fn generic_f<'a, T: SoATypes<'a>>(vec: &'a T::Vec) { +fn generic_f<'a: 'b, 'b, T: SoATypes<'a, 'b>>(vec: &'a T::Vec) { assert_eq!(vec.len(), 2); } diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index b54bcc1..23941ab 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -1,4 +1,4 @@ -use soa_derive::StructOfArray; +use soa_derive::{SoASlice, StructOfArray}; #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] @@ -7,6 +7,28 @@ pub struct Particle { pub mass: f64, } +// impl<'b, 'a: 'b> ::soa_derive::SoASort<'a, Particle> for ParticleSliceMut<'a> { +// fn sort_by(&mut self, mut f: F) +// where +// F: FnMut(Self::Ref, Self::Ref) -> std::cmp::Ordering { +// use soa_derive::Permutation; + +// let mut permutation: Vec = (0..self.len()).collect(); +// permutation.sort_by(|j, k| { +// let view = self.reborrow(); +// let xj = view.index(*j); +// let xk = view.index(*k); +// let result = f(xj, xk); +// drop(xj); +// drop(xk); +// result +// }); + +// let mut permutation = Permutation::oneline(permutation).inverse(); +// self.apply_permutation(&mut permutation); +// } +// } + impl Particle { pub fn new(name: String, mass: f64) -> Self { Particle { From b69298e9926af6ae08bcf217387f1ef61d4e3507 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sat, 11 Jan 2025 18:21:01 -0500 Subject: [PATCH 06/37] Fix most of the lifetime mess, polish interface, add documentation --- soa-derive-internal/src/lib.rs | 4 +- soa-derive-internal/src/slice.rs | 124 +++++++++--------- soa-derive-internal/src/vec.rs | 99 +++++++------- src/lib.rs | 213 +++++++++++++++++++++++++++---- tests/generic.rs | 90 ++++++++++++- tests/nested_soa.rs | 2 +- tests/particles/mod.rs | 24 +--- 7 files changed, 399 insertions(+), 157 deletions(-) diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index 4ae48d8..ad1474f 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -52,10 +52,10 @@ fn derive_trait(input: &Input) -> TokenStream { type Type = #vec_name; } - impl<'a: 'b, 'b> soa_derive::SoATypes<'a, 'b> for #name { + impl<'a> soa_derive::SoATypes<'a> for #name { type Vec = #vec_name; type Slice = #slice_name<'a>; - type MutSlice = #slice_mut_name<'a>; + type SliceMut = #slice_mut_name<'a>; type Ref = #ref_name<'a>; type RefMut = #ref_mut_name<'a>; } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index e9ac5c6..42a907a 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -235,9 +235,9 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a: 'b, 'b> ::soa_derive::SoASlice<'a, 'b, #name> for #slice_name<'a> { - type Ref = #ref_name<'a>; - type Slice = #slice_name<'a>; + impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_name<'a> { + type Ref<'t> = #ref_name<'t> where 'a: 't; + type Reborrow<'t> = #slice_name<'t> where 'a: 't; fn len(&self) -> usize { self.len() @@ -247,40 +247,41 @@ pub fn derive(input: &Input) -> TokenStream { self.is_empty() } - fn as_slice(&'a self) -> Self::Slice { - self.as_slice() + fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c { + self.reborrow() + } + + fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { + self.iter() + } + + fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + self.get(index) } - fn slice(&'a self, index: impl core::ops::RangeBounds) -> Self::Slice { + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + self.index(index) + } + + fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, }; - let n = self.as_slice().len(); + let n = self.len(); let end = match index.end_bound() { std::ops::Bound::Included(i) => (*i + 1).min(n), std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => self.as_slice().len(), + std::ops::Bound::Unbounded => n, }; - self.slice(start..end) - } - - fn index(&'a self, index: usize) -> Self::Ref { - self.index(index) - } - - fn get(&'a self, index: usize) -> Option { - self.get(index) - } - - fn iter(&'a self) -> <#name as ::soa_derive::SoAIter<'a>>::Iter { - self.iter() + self.index(start..end) } fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { self.as_ptr() } } + }; if input.attrs.derive_clone { @@ -707,9 +708,9 @@ pub fn derive_mut(input: &Input) -> TokenStream { } } - impl<'a: 'b, 'b> ::soa_derive::SoASlice<'a, 'b, #name> for #slice_mut_name<'a> { - type Ref = #ref_name<'a>; - type Slice = #slice_name<'a>; + impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_mut_name<'a> { + type Ref<'t> = #ref_name<'t> where 'a: 't; + type Reborrow<'t> = #slice_name<'t> where 'a: 't; fn len(&self) -> usize { self.len() @@ -719,34 +720,34 @@ pub fn derive_mut(input: &Input) -> TokenStream { self.is_empty() } - fn as_slice(&'a self) -> Self::Slice { + fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c { self.as_slice() } - fn slice(&'a self, index: impl core::ops::RangeBounds) -> Self::Slice { + fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { + self.as_ref().into_iter() + } + + fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + self.get(index) + } + + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + self.index(index) + } + + fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, }; - let n = self.as_slice().len(); + let n = self.len(); let end = match index.end_bound() { std::ops::Bound::Included(i) => (*i + 1).min(n), std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => self.as_slice().len(), + std::ops::Bound::Unbounded => n, }; - self.slice(start..end) - } - - fn index(&'a self, index: usize) -> Self::Ref { - self.index(index) - } - - fn get(&'a self, index: usize) -> Option { - self.get(index) - } - - fn iter(&'a self) -> <#name as ::soa_derive::SoAIter<'a>>::Iter { - self.iter() + self.index(start..end) } fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { @@ -754,46 +755,51 @@ pub fn derive_mut(input: &Input) -> TokenStream { } } - impl<'a: 'b, 'b> ::soa_derive::SoAMutSlice<'a, 'b, #name> for #slice_mut_name<'a> { - type RefMut = #ref_mut_name<'a>; - - type SliceMut = #slice_mut_name<'a>; + impl<'a> ::soa_derive::SoAMutSlice<'a, #name> for #slice_mut_name<'a> { + type RefMut<'t> = #ref_mut_name<'t> where 'a: 't, Self: 't; - fn as_mut_slice(&'a mut self) -> Self::SliceMut { - self.as_mut_slice() - } + type ReborrowMut<'t> = #slice_mut_name<'t> where 'a: 't, Self: 't; - fn index_mut(&'a mut self, index: usize) -> Self::RefMut { - self.index_mut(index) - } - - fn slice_mut(&'a mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut { + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::ReborrowMut<'c> where 'a: 'c { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, }; - let n = self.as_slice().len(); + let n = self.len(); let end = match index.end_bound() { std::ops::Bound::Included(i) => (*i + 1).min(n), std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => self.as_slice().len(), + std::ops::Bound::Unbounded => n, }; - self.slice_mut(start..end) + self.index_mut(start..end) } - fn get_mut(&'a mut self, index: usize) -> Option { + fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { self.get_mut(index) } - fn iter_mut(&'a mut self) -> <#name as ::soa_derive::SoAIter<'a>>::IterMut { + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { + self.index_mut(index) + } + + fn as_mut_slice<'c>(&'c mut self) -> Self::ReborrowMut<'c> where 'a: 'c { + self.reborrow() + } + + fn apply_index(&mut self, indices: &[usize]) { + let mut perm = soa_derive::Permutation::oneline(indices).inverse(); + self.apply_permutation(&mut perm); + } + + fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { self.iter_mut() } fn as_mut_ptr(&mut self) -> <#name as ::soa_derive::SoAPointers>::MutPtr { self.as_mut_ptr() } - } + }; if input.attrs.derive_clone { diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index e73c4d0..7fdbb2a 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -445,9 +445,10 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a: 'b, 'b> ::soa_derive::SoASlice<'a, 'b, #name> for #vec_name { - type Ref = #ref_name<'a>; - type Slice = #slice_name<'a>; + + impl<'a> ::soa_derive::SoASlice<'a, #name> for #vec_name { + type Ref<'t> = #ref_name<'t> where 'a: 't; + type Reborrow<'t> = #slice_name<'t> where 'a: 't; fn len(&self) -> usize { self.len() @@ -457,34 +458,34 @@ pub fn derive(input: &Input) -> TokenStream { self.is_empty() } - fn as_slice(&'a self) -> Self::Slice { + fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c { self.as_slice() } - fn slice(&'a self, index: impl core::ops::RangeBounds) -> Self::Slice { + fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { + self.iter() + } + + fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + self.get(index) + } + + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + self.index(index) + } + + fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, }; - let n = self.as_slice().len(); + let n = self.len(); let end = match index.end_bound() { std::ops::Bound::Included(i) => (*i + 1).min(n), std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => self.as_slice().len(), + std::ops::Bound::Unbounded => n, }; - self.slice(start..end) - } - - fn index(&'a self, index: usize) -> Self::Ref { - self.index(index) - } - - fn get(&'a self, index: usize) -> Option { - self.get(index) - } - - fn iter(&'a self) -> <#name as ::soa_derive::SoAIter<'a>>::Iter { - self.iter() + self.index(start..end) } fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { @@ -492,38 +493,43 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a: 'b, 'b> ::soa_derive::SoAMutSlice<'a, 'b, #name> for #vec_name { - type RefMut = #ref_mut_name<'a>; + impl<'a> ::soa_derive::SoAMutSlice<'a, #name> for #vec_name { + type RefMut<'t> = #ref_mut_name<'t> where 'a: 't, Self: 't; - type SliceMut = #slice_mut_name<'a>; + type ReborrowMut<'t> = #slice_mut_name<'t> where 'a: 't, Self: 't; - fn as_mut_slice(&'a mut self) -> Self::SliceMut { - self.as_mut_slice() - } - - fn index_mut(&'a mut self, index: usize) -> Self::RefMut { - self.index_mut(index) - } - - fn slice_mut(&'a mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut { + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::ReborrowMut<'c> where 'a: 'c { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, }; - let n = self.as_slice().len(); + let n = self.len(); let end = match index.end_bound() { std::ops::Bound::Included(i) => (*i + 1).min(n), std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => self.as_slice().len(), + std::ops::Bound::Unbounded => n, }; - self.slice_mut(start..end) + self.index_mut(start..end) } - fn get_mut(&'a mut self, index: usize) -> Option { + fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { self.get_mut(index) } - fn iter_mut(&'a mut self) -> <#name as ::soa_derive::SoAIter<'a>>::IterMut { + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { + self.index_mut(index) + } + + fn as_mut_slice<'c>(&'c mut self) -> Self::ReborrowMut<'c> where 'a: 'c { + self.as_mut_slice() + } + + fn apply_index(&mut self, indices: &[usize]) { + let mut perm = soa_derive::Permutation::oneline(indices).inverse(); + self.as_mut_slice().apply_permutation(&mut perm); + } + + fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { self.iter_mut() } @@ -532,7 +538,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a: 'b, 'b> ::soa_derive::SoAVec<'a, 'b, #name> for #vec_name { + impl<'a> ::soa_derive::SoAVec<'a, #name> for #vec_name { fn new() -> Self { Self::new() } @@ -546,34 +552,37 @@ pub fn derive(input: &Input) -> TokenStream { } fn reserve(&mut self, additional: usize) { - self.reserve(additional) + self.reserve(additional); } fn reserve_exact(&mut self, additional: usize) { - self.reserve_exact(additional) + self.reserve_exact(additional); } fn shrink_to_fit(&mut self) { - self.shrink_to_fit() + self.shrink_to_fit(); } fn truncate(&mut self, len: usize) { - self.truncate(len) + self.truncate(len); } fn push(&mut self, value: #name) { - self.push(value) + self.push(value); } fn swap_remove(&mut self, index: usize) -> #name { self.swap_remove(index) } + fn insert(&mut self, index: usize, element: #name) { self.insert(index, element); } + fn replace(&mut self, index: usize, element: #name) -> #name { self.replace(index, element) } + fn remove(&mut self, index: usize) -> #name { self.remove(index) } @@ -583,11 +592,11 @@ pub fn derive(input: &Input) -> TokenStream { } fn append(&mut self, other: &mut Self) { - self.append(other) + self.append(other); } fn clear(&mut self) { - self.clear() + self.clear(); } fn split_off(&mut self, at: usize) -> Self { diff --git a/src/lib.rs b/src/lib.rs index 428984e..bd2c86c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -395,69 +395,232 @@ pub trait SoAProps<'a> : StructOfArray + SoAIter<'a> + SoAPointers {} impl<'a, T> SoAProps<'a> for T where T: StructOfArray + SoAIter<'a> + SoAPointers {} -pub trait SoASlice<'a: 'b, 'b, T: SoAProps<'a>> { - type Ref; - type Slice; + +/** + * The interface for the `Slice` immutable slice struct-of-arrays type. + */ +pub trait SoASlice<'a, T: SoAProps<'a>> { + type Ref<'t> where 'a: 't, Self: 't; + type Reborrow<'t> where 'a: 't, Self: 't; fn len(&self) -> usize; fn is_empty(&self) -> bool; + fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c; + + /// Create a slice of this vector matching the given `range`. This + /// is analogous to `Index>`. + fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c; + + /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) + fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c; + + /// Analogous to [`std::ops::Index::index()`] for `usize` + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c; - fn as_slice(&'a self) -> Self::Slice; - fn index(&'a self, index: usize) -> Self::Ref; - fn slice(&'a self, index: impl core::ops::RangeBounds) -> Self::Slice; - fn get(&'a self, index: usize) -> Option; + /// Create an immutable iterator fn iter(&'a self) -> T::Iter; + /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) + fn first<'c>(&'c self) -> Option> where 'a: 'c { + self.get(0) + } + + /// Analogous to [`slice::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last) + fn last<'c>(&'c self) -> Option> where 'a: 'c { + self.get(self.len().saturating_sub(1)) + } + + /// Obtain a `const` pointer type for this data fn as_ptr(&self) -> T::Ptr; } -pub trait SoAMutSlice<'a: 'b, 'b, T: SoAProps<'a>>: SoASlice<'a, 'b, T> { - type RefMut; - type SliceMut; +/** + * The interface for the `SliceMut` mutable slice struct-of-arrays type. A generalization of [`SoASlice`] + * whose methods can modify elements of the arrays + */ +pub trait SoAMutSlice<'a, T: SoAProps<'a>>: SoASlice<'a, T> { + type RefMut<'t> where 'a: 't, Self: 't; + type ReborrowMut<'t> where 'a: 't, Self: 't; + + /// Analogous to [`Vec::as_mut_slice()`] + fn as_mut_slice<'c>(&'c mut self) -> Self::ReborrowMut<'c> where 'a: 'c; - fn as_mut_slice(&'a mut self) -> Self::SliceMut; - fn index_mut(&'a mut self, index: usize) -> Self::RefMut; - fn slice_mut(&'a mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut; - fn get_mut(&'a mut self, index: usize) -> Option; + /// Create a mutable slice of this vector matching the given + /// `range`. This is analogous to `IndexMut>`. + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::ReborrowMut<'c> where 'a: 'c; + + /// Analogous to [`slice::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut) + fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c; + + /// Analogous to [`std::ops::IndexMut::index_mut()`] for `usize` + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c; + + /// Creates a mutable iterator fn iter_mut(&'a mut self) -> T::IterMut; + /** Re-order the arrays using the provided indices. This is provided so that generic sorting methods + can be implemented because closure-passing trait methods encounter difficulties with lifetimes. + + # Example + + ``` + use soa_derive::{StructOfArray, prelude::*}; + + #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] + #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] + pub struct Particle { + pub name: String, + pub mass: f64, + } + # fn may_sort(vec: &mut ::Vec) { + // vec: &mut ::Vec + let mut indices: Vec<_> = (0..vec.len()).collect(); + + indices.sort_by(|j, k| { + let a = vec.index(*j); + let b = vec.index(*k); + a.mass.total_cmp(b.mass).reverse() + }); + + vec.apply_index(&indices); + # } + ``` + */ + fn apply_index(&mut self, indices: &[usize]); + + /// Analogous to [`slice::first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut) + fn first_mut<'c>(&'c mut self) -> Option> where 'a: 'c { + self.get_mut(0) + } + + /// Analogous to [`slice::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut) + fn last_mut<'c>(&'c mut self) -> Option> where 'a: 'c { + self.get_mut(self.len().saturating_sub(1)) + } + + /// Obtain a `mut` pointer type for this data fn as_mut_ptr(&mut self) -> T::MutPtr; } -// pub trait SoASort<'a, T: SoAProps<'a>>: SoAMutSlice<'a, 'b, T> { -// fn sort_by(&mut self, f: F) -// where -// F: FnMut(Self::Ref, Self::Ref) -> std::cmp::Ordering; -// } - -pub trait SoAVec<'a: 'b, 'b, T: SoAProps<'a>>: SoASlice<'a, 'b, T> + SoAMutSlice<'a, 'b, T> { +/** + * The interface for the `Vec`-like struct-of-arrays type. A generalization of [`SoAMutSlice`] whose methods can + * also re-size the underlying arrays. + * + * **NOTE**: This interface is incomplete and additional methods may be added as needed. + */ +pub trait SoAVec<'a, T: SoAProps<'a>>: SoASlice<'a, T> + SoAMutSlice<'a, T> { + /// Create a new, empty struct of arrays fn new() -> Self; + + /// Create a new, empty struct of arrays with the specified capacity fn with_capacity(capacity: usize) -> Self; + + /// Analogous to [`Vec::capacity`] fn capacity(&self) -> usize; + + /// Analogous to [`Vec::reserve`] fn reserve(&mut self, additional: usize); + + /// Analogous to [`Vec::reserve_exact`] fn reserve_exact(&mut self, additional: usize); + + /// Analogous to [`Vec::shrink_to_fit`] fn shrink_to_fit(&mut self); + + /// Analogous to [`Vec::truncate`] fn truncate(&mut self, len: usize); + + /// Add a singular value of `T` to the arrays. Analogous to [`Vec::push`] fn push(&mut self, value: T); + /// Analogous to [`Vec::swap_remove`] fn swap_remove(&mut self, index: usize) -> T; + + /// Analogous to [`Vec::insert`] fn insert(&mut self, index: usize, element: T); + + /// Analogous to [`Vec::replace`] fn replace(&mut self, index: usize, element: T) -> T; + + /// Analogous to [`Vec::remove`] fn remove(&mut self, index: usize) -> T; + + /// Analogous to [`Vec::pop`] fn pop(&mut self) -> Option; + + /// Analogous to [`Vec::append`] fn append(&mut self, other: &mut Self); + + /// Analogous to [`Vec::clear`] fn clear(&mut self); + + /// Analogous to [`Vec::split_off`] fn split_off(&mut self, at: usize) -> Self; } -pub trait SoATypes<'a: 'b, 'b>: SoAProps<'a> + Sized { - type Vec: SoAVec<'a, 'b, Self>; - type Slice: SoASlice<'a, 'b, Self>; - type MutSlice: SoAMutSlice<'a, 'b, Self>; +/** A collection of types that represent the different facets of a [`StructOfArray`] type. + + It is a convenience type that can be used as a trait bound, but because it introduces + a lifetime, it is not folded directly into [`StructOfArray`] itself. It also ensures + that the associated types interlock between all facets. + + # Example + + Suppose one has a generic type that needs to be generic *over* [`StructOfArray`] + types. This trait is a convenient means of claiming all the appropriate behaviors + are available in one place: + ``` +use soa_derive::prelude::*; +#[derive(Debug, Clone)] +struct Swarm<'a, T: SoATypes<'a>> { + entries: T::Vec, +} + +impl<'a, T: SoATypes<'a>> Swarm<'a, T> { + fn new() -> Self { + Self { + entries: T::Vec::new() + } + } + + fn push(&mut self, value: T) { + self.entries.push(value); + } + + fn iter(&'a self) -> T::Iter { + self.entries.iter() + } +} + ``` + + Without this, the generic type wouldn't be able to access any methods of `self.entries` because + the associate type provided by [`StructOfArray`] has *no* bounds, which means it proves no methods + are available. +*/ +pub trait SoATypes<'a>: SoAProps<'a> + Sized { + /// The [`Vec`]-like type + type Vec: SoAVec<'a, Self, + Ref<'a> = >::Ref, + Reborrow<'a> = Self::Slice, + RefMut<'a> = >::RefMut, + ReborrowMut<'a> = Self::SliceMut, + > + 'a; + /// The immutable `&[Self]`-like type + type Slice: SoASlice<'a, Self, Ref<'a> =>::Ref, Reborrow<'a> = Self::Slice> + 'a; + /// The mutable `&[Self]`-like type + type SliceMut: SoAMutSlice< + 'a, Self, + Ref<'a> =>::Ref, + Reborrow<'a> = Self::Slice, + RefMut<'a> = >::RefMut, + ReborrowMut<'a> = Self::SliceMut, + > + 'a; + type Ref: 'a; type RefMut: 'a; } +/// A collection of supporting traits for [`StructOfArray`] bundled in one place for ease-of-access pub mod prelude { pub use super::{SoAVec, SoAIter, SoAProps, SoASlice, SoAMutSlice, SoAPointers, SoATypes, StructOfArray}; } diff --git a/tests/generic.rs b/tests/generic.rs index 81fdb0f..5540206 100644 --- a/tests/generic.rs +++ b/tests/generic.rs @@ -3,16 +3,102 @@ use soa_derive::prelude::*; mod particles; use self::particles::Particle; -fn may_i_do_this<'a: 'b, 'b, T: SoATypes<'a, 'b>>(vec: &'a T::Vec) -> T::Iter { +fn may_iter<'a, T: SoATypes<'a>>(vec: &'a T::Vec) -> T::Iter { let x= vec.iter(); x } +fn may_push<'a, T: SoATypes<'a>>(vec: &'a mut T::Vec, val: T) { + vec.push(val); +} + +fn may_sort(vec: &mut ::Vec) { + let mut indices: Vec<_> = (0..vec.len()).collect(); + + indices.sort_by(|j, k| { + let a = vec.index(*j); + let b = vec.index(*k); + a.mass.total_cmp(b.mass).reverse() + }); + + vec.apply_index(&indices); +} + + +fn may_closure_sort(vec: &mut ::Vec, mut f: F) where F: FnMut(::Ref, ::Ref) -> std::cmp::Ordering { + let mut indices: Vec<_> = (0..vec.len()).collect(); + + indices.sort_by(|j, k| { + let a = vec.index(*j); + let b = vec.index(*k); + f(a, b) + }); + + vec.apply_index(&indices); +} + + #[test] fn test_generic_type_behavior() { let mut x = ::Vec::new(); x.push(Particle::new("foo".into(), 100.0)); - let y: Vec<_> = may_i_do_this::(&x).collect(); + let y: Vec<_> = may_iter::(&x).collect(); assert_eq!(x.len(), y.len()); assert_eq!(x.get(0).as_ref(), y.get(0)); + drop(y); + + let z = Particle::new("bar".into(), 1000.0); + may_push(&mut x, z); + assert_eq!(x.len(), 2); + may_sort(&mut x); + let a = x.index(0); + let b = x.index(1); + assert!(a.mass > b.mass); + + may_closure_sort(&mut x, |a, b| a.mass.total_cmp(&b.mass)); + + let a = x.index(0); + let b = x.index(1); + assert!(a.mass < b.mass); +} + + +#[derive(Debug, Clone)] +struct Swarm<'a, T: soa_derive::SoATypes<'a>> { + entries: T::Vec, +} + +impl<'a, T: soa_derive::SoATypes<'a>> Swarm<'a, T> { + fn new() -> Self { + Self { + entries: T::Vec::new() + } + } + + fn push(&mut self, value: T) { + self.entries.push(value); + } + + fn iter(&'a self) -> T::Iter { + self.entries.iter() + } + + fn view(&'a self) -> T::Slice { + self.entries.as_slice() + } +} + +#[test] +fn test_wrapped() { + let mut this: Swarm<'_, Particle> = Swarm::new(); + let x= Particle::new("foo".into(), 100.0); + this.push(x); + let x = Particle::new("bar".into(), 1000.0); + this.push(x); + let x = Particle::new("baz".into(), 10.0); + this.push(x); + + assert_eq!(this.iter().count(), 3); + + assert_eq!(this.view().len(), 3); } \ No newline at end of file diff --git a/tests/nested_soa.rs b/tests/nested_soa.rs index bfc1e9d..946b5ba 100644 --- a/tests/nested_soa.rs +++ b/tests/nested_soa.rs @@ -59,7 +59,7 @@ fn nested_soa() { }); } -fn generic_f<'a: 'b, 'b, T: SoATypes<'a, 'b>>(vec: &'a T::Vec) { +fn generic_f<'a, T: SoATypes<'a>>(vec: &'a T::Vec) { assert_eq!(vec.len(), 2); } diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index 23941ab..b54bcc1 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -1,4 +1,4 @@ -use soa_derive::{SoASlice, StructOfArray}; +use soa_derive::StructOfArray; #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] @@ -7,28 +7,6 @@ pub struct Particle { pub mass: f64, } -// impl<'b, 'a: 'b> ::soa_derive::SoASort<'a, Particle> for ParticleSliceMut<'a> { -// fn sort_by(&mut self, mut f: F) -// where -// F: FnMut(Self::Ref, Self::Ref) -> std::cmp::Ordering { -// use soa_derive::Permutation; - -// let mut permutation: Vec = (0..self.len()).collect(); -// permutation.sort_by(|j, k| { -// let view = self.reborrow(); -// let xj = view.index(*j); -// let xk = view.index(*k); -// let result = f(xj, xk); -// drop(xj); -// drop(xk); -// result -// }); - -// let mut permutation = Permutation::oneline(permutation).inverse(); -// self.apply_permutation(&mut permutation); -// } -// } - impl Particle { pub fn new(name: String, mass: f64) -> Self { Particle { From d679b90795756413d2ffb1715df26fc306ea35ea Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sat, 11 Jan 2025 19:19:53 -0500 Subject: [PATCH 07/37] checkpoint --- soa-derive-internal/src/lib.rs | 2 +- src/lib.rs | 31 ++++++++++++++++--------------- tests/generic.rs | 14 +++++++------- tests/nested_soa.rs | 2 +- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index ad1474f..db4e031 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -52,7 +52,7 @@ fn derive_trait(input: &Input) -> TokenStream { type Type = #vec_name; } - impl<'a> soa_derive::SoATypes<'a> for #name { + impl<'a: 't, 't> soa_derive::SoATypes<'a, 't> for #name { type Vec = #vec_name; type Slice = #slice_name<'a>; type SliceMut = #slice_mut_name<'a>; diff --git a/src/lib.rs b/src/lib.rs index bd2c86c..2254eb7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -255,8 +255,8 @@ pub trait StructOfArray { pub trait SoAIter<'a> { type Ref; type RefMut; - type Iter: 'a + Iterator + IntoIterator; - type IterMut: 'a + Iterator + IntoIterator; + type Iter: 'a + Iterator; + type IterMut: 'a + Iterator; } mod private_soa_indexes { @@ -472,8 +472,8 @@ pub trait SoAMutSlice<'a, T: SoAProps<'a>>: SoASlice<'a, T> { pub name: String, pub mass: f64, } - # fn may_sort(vec: &mut ::Vec) { - // vec: &mut ::Vec + # fn may_sort<'a>(vec: &mut >::Vec) { + // vec: &mut >::Vec let mut indices: Vec<_> = (0..vec.len()).collect(); indices.sort_by(|j, k| { @@ -572,11 +572,11 @@ pub trait SoAVec<'a, T: SoAProps<'a>>: SoASlice<'a, T> + SoAMutSlice<'a, T> { ``` use soa_derive::prelude::*; #[derive(Debug, Clone)] -struct Swarm<'a, T: SoATypes<'a>> { +struct Swarm<'a: 't, 't, T: SoATypes<'a, 't> + 'a> { entries: T::Vec, } -impl<'a, T: SoATypes<'a>> Swarm<'a, T> { +impl<'a: 't, 't, T: SoATypes<'a, 't> + 'a> Swarm<'a, 't, T> { fn new() -> Self { Self { entries: T::Vec::new() @@ -597,27 +597,28 @@ impl<'a, T: SoATypes<'a>> Swarm<'a, T> { the associate type provided by [`StructOfArray`] has *no* bounds, which means it proves no methods are available. */ -pub trait SoATypes<'a>: SoAProps<'a> + Sized { +pub trait SoATypes<'a: 't, 't>: SoAProps<'a> + Sized { /// The [`Vec`]-like type type Vec: SoAVec<'a, Self, - Ref<'a> = >::Ref, + Ref<'a> = >::Ref, Reborrow<'a> = Self::Slice, - RefMut<'a> = >::RefMut, + RefMut<'a> = >::RefMut, ReborrowMut<'a> = Self::SliceMut, - > + 'a; + > + 'a where Self: 'a; /// The immutable `&[Self]`-like type - type Slice: SoASlice<'a, Self, Ref<'a> =>::Ref, Reborrow<'a> = Self::Slice> + 'a; + type Slice: SoASlice<'a, Self, Ref<'a> =>::Ref, Reborrow<'a> = Self::Slice> + 'a where Self: 'a; /// The mutable `&[Self]`-like type type SliceMut: SoAMutSlice< 'a, Self, - Ref<'a> =>::Ref, + Ref<'a> =>::Ref, Reborrow<'a> = Self::Slice, - RefMut<'a> = >::RefMut, + RefMut<'a> = >::RefMut, ReborrowMut<'a> = Self::SliceMut, - > + 'a; + > + 'a where Self: 'a; - type Ref: 'a; + type Ref: 't; type RefMut: 'a; + } /// A collection of supporting traits for [`StructOfArray`] bundled in one place for ease-of-access diff --git a/tests/generic.rs b/tests/generic.rs index 5540206..e3a96c8 100644 --- a/tests/generic.rs +++ b/tests/generic.rs @@ -3,16 +3,16 @@ use soa_derive::prelude::*; mod particles; use self::particles::Particle; -fn may_iter<'a, T: SoATypes<'a>>(vec: &'a T::Vec) -> T::Iter { +fn may_iter<'a: 't, 't, T: SoATypes<'a, 't>>(vec: &'a T::Vec) -> T::Iter { let x= vec.iter(); x } -fn may_push<'a, T: SoATypes<'a>>(vec: &'a mut T::Vec, val: T) { +fn may_push<'a: 't, 't, T: SoATypes<'a, 't>>(vec: &'a mut T::Vec, val: T) { vec.push(val); } -fn may_sort(vec: &mut ::Vec) { +fn may_sort<'a: 't, 't>(vec: &mut >::Vec) { let mut indices: Vec<_> = (0..vec.len()).collect(); indices.sort_by(|j, k| { @@ -25,7 +25,7 @@ fn may_sort(vec: &mut ::Vec) { } -fn may_closure_sort(vec: &mut ::Vec, mut f: F) where F: FnMut(::Ref, ::Ref) -> std::cmp::Ordering { +fn may_closure_sort<'a: 't, 't, F>(vec: &mut >::Vec, mut f: F) where F: FnMut(::Ref, ::Ref) -> std::cmp::Ordering { let mut indices: Vec<_> = (0..vec.len()).collect(); indices.sort_by(|j, k| { @@ -64,11 +64,11 @@ fn test_generic_type_behavior() { #[derive(Debug, Clone)] -struct Swarm<'a, T: soa_derive::SoATypes<'a>> { +struct Swarm<'a: 't, 't, T: soa_derive::SoATypes<'a, 't> + 'a> { entries: T::Vec, } -impl<'a, T: soa_derive::SoATypes<'a>> Swarm<'a, T> { +impl<'a: 't, 't, T: soa_derive::SoATypes<'a, 't>> Swarm<'a, 't, T> { fn new() -> Self { Self { entries: T::Vec::new() @@ -90,7 +90,7 @@ impl<'a, T: soa_derive::SoATypes<'a>> Swarm<'a, T> { #[test] fn test_wrapped() { - let mut this: Swarm<'_, Particle> = Swarm::new(); + let mut this: Swarm<'_, '_, Particle> = Swarm::new(); let x= Particle::new("foo".into(), 100.0); this.push(x); let x = Particle::new("bar".into(), 1000.0); diff --git a/tests/nested_soa.rs b/tests/nested_soa.rs index 946b5ba..5e55660 100644 --- a/tests/nested_soa.rs +++ b/tests/nested_soa.rs @@ -59,7 +59,7 @@ fn nested_soa() { }); } -fn generic_f<'a, T: SoATypes<'a>>(vec: &'a T::Vec) { +fn generic_f<'a, 't, T: SoATypes<'a, 't>>(vec: &'a T::Vec) { assert_eq!(vec.len(), 2); } From 4566a50dee2d011722cb354e3004d65fe88ec1bd Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sat, 11 Jan 2025 22:26:50 -0500 Subject: [PATCH 08/37] checkpoint --- soa-derive-internal/src/slice.rs | 8 ++++++++ soa-derive-internal/src/vec.rs | 5 +++++ src/lib.rs | 2 +- tests/generic.rs | 12 ++++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index 42a907a..4dfd8c0 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -55,6 +55,9 @@ pub fn derive(input: &Input) -> TokenStream { |ident, _| quote! { ::std::slice::from_raw_parts(data.#ident, len) }, ).collect::>(); + #[allow(unused)] + let iter_name = names::iter_name(name); + let mut generated = quote! { /// A slice of #[doc = #doc_url] @@ -380,6 +383,11 @@ pub fn derive_mut(input: &Input) -> TokenStream { |ident, _| quote! { permutation.apply_slice_in_place(&mut self.#ident) }, ).collect::>(); + #[allow(unused)] + let iter_name = names::iter_name(name); + #[allow(unused)] + let iter_mut_name = names::iter_mut_name(name); + let mut generated = quote! { /// A mutable slice of #[doc = #doc_url] diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index 7fdbb2a..0139a53 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -67,6 +67,11 @@ pub fn derive(input: &Input) -> TokenStream { |ident, _| quote! { ::std::mem::replace(&mut self.#ident[index], field) }, ).collect::>(); + #[allow(unused)] + let iter_name = names::iter_name(name); + #[allow(unused)] + let iter_mut_name = names::iter_mut_name(name); + let mut generated = quote! { /// An analog to ` #[doc = #vec_name_str] diff --git a/src/lib.rs b/src/lib.rs index 2254eb7..6e7d0a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -617,7 +617,7 @@ pub trait SoATypes<'a: 't, 't>: SoAProps<'a> + Sized { > + 'a where Self: 'a; type Ref: 't; - type RefMut: 'a; + type RefMut: 't; } diff --git a/tests/generic.rs b/tests/generic.rs index e3a96c8..c97ab95 100644 --- a/tests/generic.rs +++ b/tests/generic.rs @@ -25,6 +25,18 @@ fn may_sort<'a: 't, 't>(vec: &mut >::Vec) { } +fn may_sort_generic<'a: 't, 't: 'c, 'c, T: SoATypes<'a, 't>>(vec: &'c mut >::Vec) { + let mut indices: Vec<_> = (0..vec.len()).collect(); + + indices.sort_by(|j, k| { + let a = vec.index(*j); + let b = vec.index(*k); + std::cmp::Ordering::Equal + }); + +} + + fn may_closure_sort<'a: 't, 't, F>(vec: &mut >::Vec, mut f: F) where F: FnMut(::Ref, ::Ref) -> std::cmp::Ordering { let mut indices: Vec<_> = (0..vec.len()).collect(); From 0e0348dd2a2c2da11c0cdfd40eeb46e7dc9bf8a3 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sun, 12 Jan 2025 09:43:49 -0500 Subject: [PATCH 09/37] checkpoint: rewrite --- soa-derive-internal/src/lib.rs | 22 +-- soa-derive-internal/src/slice.rs | 276 +++++++++++++-------------- soa-derive-internal/src/vec.rs | 315 ++++++++++++++++--------------- src/lib.rs | 67 ++++--- tests/generic.rs | 223 +++++++++++----------- tests/nested_soa.rs | 36 ++-- 6 files changed, 481 insertions(+), 458 deletions(-) diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index db4e031..e0f88b6 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -42,22 +42,22 @@ use quote::quote; fn derive_trait(input: &Input) -> TokenStream { let name = &input.name; let vec_name = names::vec_name(name); - let slice_name = names::slice_name(name); - let slice_mut_name = names::slice_mut_name(name); - let ref_name = names::ref_name(name); - let ref_mut_name = names::ref_mut_name(name); + // let slice_name = names::slice_name(name); + // let slice_mut_name = names::slice_mut_name(name); + // let ref_name = names::ref_name(name); + // let ref_mut_name = names::ref_mut_name(name); quote! { impl soa_derive::StructOfArray for #name { type Type = #vec_name; } - impl<'a: 't, 't> soa_derive::SoATypes<'a, 't> for #name { - type Vec = #vec_name; - type Slice = #slice_name<'a>; - type SliceMut = #slice_mut_name<'a>; - type Ref = #ref_name<'a>; - type RefMut = #ref_mut_name<'a>; - } + // impl<'a: 't, 't> soa_derive::SoATypes<'a, 't> for #name { + // type Vec = #vec_name; + // type Slice = #slice_name<'a>; + // type SliceMut = #slice_mut_name<'a>; + // type Ref = #ref_name<'a>; + // type RefMut = #ref_mut_name<'a>; + // } } } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index 4dfd8c0..7cbe6c8 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -238,52 +238,53 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_name<'a> { - type Ref<'t> = #ref_name<'t> where 'a: 't; - type Reborrow<'t> = #slice_name<'t> where 'a: 't; - - fn len(&self) -> usize { - self.len() - } - - fn is_empty(&self) -> bool { - self.is_empty() - } - - fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c { - self.reborrow() - } - - fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { - self.iter() - } - - fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { - self.get(index) - } - - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { - self.index(index) - } - - fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index(start..end) - } - - fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { - self.as_ptr() - } - } + // impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_name<'a> { + // type Ref<'t> = #ref_name<'t> where 'a: 't; + // type Reborrow<'t> = #slice_name<'t> where 'a: 't; + + // fn len(&self) -> usize { + // self.len() + // } + + // fn is_empty(&self) -> bool { + // self.is_empty() + // } + + // fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c { + // self.reborrow() + // } + + // fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { + // self.iter() + // } + + // fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + // self.get(index) + // } + + // fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + // let view: #slice_name<'c> = self.reborrow::<'c>(); + // ::soa_derive::SoAIndex::index(index, view) + // } + + // fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c { + // let start = match index.start_bound() { + // std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + // std::ops::Bound::Unbounded => 0, + // }; + // let n = self.len(); + // let end = match index.end_bound() { + // std::ops::Bound::Included(i) => (*i + 1).min(n), + // std::ops::Bound::Excluded(i) => *i, + // std::ops::Bound::Unbounded => n, + // }; + // self.index(start..end) + // } + + // fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { + // self.as_ptr() + // } + // } }; @@ -716,97 +717,98 @@ pub fn derive_mut(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_mut_name<'a> { - type Ref<'t> = #ref_name<'t> where 'a: 't; - type Reborrow<'t> = #slice_name<'t> where 'a: 't; - - fn len(&self) -> usize { - self.len() - } - - fn is_empty(&self) -> bool { - self.is_empty() - } - - fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c { - self.as_slice() - } - - fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { - self.as_ref().into_iter() - } - - fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { - self.get(index) - } - - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { - self.index(index) - } - - fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index(start..end) - } - - fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { - self.as_ptr() - } - } - - impl<'a> ::soa_derive::SoAMutSlice<'a, #name> for #slice_mut_name<'a> { - type RefMut<'t> = #ref_mut_name<'t> where 'a: 't, Self: 't; - - type ReborrowMut<'t> = #slice_mut_name<'t> where 'a: 't, Self: 't; - - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::ReborrowMut<'c> where 'a: 'c { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index_mut(start..end) - } - - fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { - self.get_mut(index) - } - - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { - self.index_mut(index) - } - - fn as_mut_slice<'c>(&'c mut self) -> Self::ReborrowMut<'c> where 'a: 'c { - self.reborrow() - } - - fn apply_index(&mut self, indices: &[usize]) { - let mut perm = soa_derive::Permutation::oneline(indices).inverse(); - self.apply_permutation(&mut perm); - } - - fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { - self.iter_mut() - } - - fn as_mut_ptr(&mut self) -> <#name as ::soa_derive::SoAPointers>::MutPtr { - self.as_mut_ptr() - } - } + // impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_mut_name<'a> { + // type Ref<'t> = #ref_name<'t> where 'a: 't; + // type Reborrow<'t> = #slice_name<'t> where 'a: 't; + + // fn len(&self) -> usize { + // self.len() + // } + + // fn is_empty(&self) -> bool { + // self.is_empty() + // } + + // fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c { + // self.as_slice() + // } + + // fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { + // self.as_ref().into_iter() + // } + + // fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + // self.get(index) + // } + + // fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + // let slice: #slice_name<'c> = self.as_slice(); + // ::soa_derive::SoAIndex::index(index, slice) + // } + + // fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c { + // let start = match index.start_bound() { + // std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + // std::ops::Bound::Unbounded => 0, + // }; + // let n = self.len(); + // let end = match index.end_bound() { + // std::ops::Bound::Included(i) => (*i + 1).min(n), + // std::ops::Bound::Excluded(i) => *i, + // std::ops::Bound::Unbounded => n, + // }; + // self.index(start..end) + // } + + // fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { + // self.as_ptr() + // } + // } + + // impl<'a> ::soa_derive::SoAMutSlice<'a, #name> for #slice_mut_name<'a> { + // type RefMut<'t> = #ref_mut_name<'t> where 'a: 't, Self: 't; + + // type ReborrowMut<'t> = #slice_mut_name<'t> where 'a: 't, Self: 't; + + // fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::ReborrowMut<'c> where 'a: 'c { + // let start = match index.start_bound() { + // std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + // std::ops::Bound::Unbounded => 0, + // }; + // let n = self.len(); + // let end = match index.end_bound() { + // std::ops::Bound::Included(i) => (*i + 1).min(n), + // std::ops::Bound::Excluded(i) => *i, + // std::ops::Bound::Unbounded => n, + // }; + // self.index_mut(start..end) + // } + + // fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { + // self.get_mut(index) + // } + + // fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { + // self.index_mut(index) + // } + + // fn as_mut_slice<'c>(&'c mut self) -> Self::ReborrowMut<'c> where 'a: 'c { + // self.reborrow() + // } + + // fn apply_index(&mut self, indices: &[usize]) { + // let mut perm = soa_derive::Permutation::oneline(indices).inverse(); + // self.apply_permutation(&mut perm); + // } + + // fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { + // self.iter_mut() + // } + + // fn as_mut_ptr(&mut self) -> <#name as ::soa_derive::SoAPointers>::MutPtr { + // self.as_mut_ptr() + // } + // } }; diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index 0139a53..302e002 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -451,163 +451,164 @@ pub fn derive(input: &Input) -> TokenStream { } - impl<'a> ::soa_derive::SoASlice<'a, #name> for #vec_name { - type Ref<'t> = #ref_name<'t> where 'a: 't; - type Reborrow<'t> = #slice_name<'t> where 'a: 't; - - fn len(&self) -> usize { - self.len() - } - - fn is_empty(&self) -> bool { - self.is_empty() - } - - fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c { - self.as_slice() - } - - fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { - self.iter() - } - - fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { - self.get(index) - } - - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { - self.index(index) - } - - fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index(start..end) - } - - fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { - self.as_ptr() - } - } - - impl<'a> ::soa_derive::SoAMutSlice<'a, #name> for #vec_name { - type RefMut<'t> = #ref_mut_name<'t> where 'a: 't, Self: 't; - - type ReborrowMut<'t> = #slice_mut_name<'t> where 'a: 't, Self: 't; - - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::ReborrowMut<'c> where 'a: 'c { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index_mut(start..end) - } - - fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { - self.get_mut(index) - } - - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { - self.index_mut(index) - } - - fn as_mut_slice<'c>(&'c mut self) -> Self::ReborrowMut<'c> where 'a: 'c { - self.as_mut_slice() - } - - fn apply_index(&mut self, indices: &[usize]) { - let mut perm = soa_derive::Permutation::oneline(indices).inverse(); - self.as_mut_slice().apply_permutation(&mut perm); - } - - fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { - self.iter_mut() - } - - fn as_mut_ptr(&mut self) -> <#name as ::soa_derive::SoAPointers>::MutPtr { - self.as_mut_ptr() - } - } - - impl<'a> ::soa_derive::SoAVec<'a, #name> for #vec_name { - fn new() -> Self { - Self::new() - } - - fn with_capacity(capacity: usize) -> Self { - Self::with_capacity(capacity) - } - - fn capacity(&self) -> usize { - self.capacity() - } - - fn reserve(&mut self, additional: usize) { - self.reserve(additional); - } - - fn reserve_exact(&mut self, additional: usize) { - self.reserve_exact(additional); - } - - fn shrink_to_fit(&mut self) { - self.shrink_to_fit(); - } - - fn truncate(&mut self, len: usize) { - self.truncate(len); - } - - fn push(&mut self, value: #name) { - self.push(value); - } - - fn swap_remove(&mut self, index: usize) -> #name { - self.swap_remove(index) - } - - fn insert(&mut self, index: usize, element: #name) { - self.insert(index, element); - } - - fn replace(&mut self, index: usize, element: #name) -> #name { - self.replace(index, element) - } - - fn remove(&mut self, index: usize) -> #name { - self.remove(index) - } - - fn pop(&mut self) -> Option<#name> { - self.pop() - } - - fn append(&mut self, other: &mut Self) { - self.append(other); - } - - fn clear(&mut self) { - self.clear(); - } - - fn split_off(&mut self, at: usize) -> Self { - self.split_off(at) - } - } + // impl<'a> ::soa_derive::SoASlice<'a, #name> for #vec_name { + // type Ref<'t> = #ref_name<'t> where 'a: 't; + // type Reborrow<'t> = #slice_name<'t> where 'a: 't; + + // fn len(&self) -> usize { + // self.len() + // } + + // fn is_empty(&self) -> bool { + // self.is_empty() + // } + + // fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c { + // self.as_slice() + // } + + // fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { + // self.iter() + // } + + // fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + // self.get(index) + // } + + // fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + // let slice: #slice_name<'c> = self.as_slice(); + // ::soa_derive::SoAIndex::index(index, slice) + // } + + // fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c { + // let start = match index.start_bound() { + // std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + // std::ops::Bound::Unbounded => 0, + // }; + // let n = self.len(); + // let end = match index.end_bound() { + // std::ops::Bound::Included(i) => (*i + 1).min(n), + // std::ops::Bound::Excluded(i) => *i, + // std::ops::Bound::Unbounded => n, + // }; + // self.index(start..end) + // } + + // fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { + // self.as_ptr() + // } + // } + + // impl<'a> ::soa_derive::SoAMutSlice<'a, #name> for #vec_name { + // type RefMut<'t> = #ref_mut_name<'t> where 'a: 't, Self: 't; + + // type ReborrowMut<'t> = #slice_mut_name<'t> where 'a: 't, Self: 't; + + // fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::ReborrowMut<'c> where 'a: 'c { + // let start = match index.start_bound() { + // std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + // std::ops::Bound::Unbounded => 0, + // }; + // let n = self.len(); + // let end = match index.end_bound() { + // std::ops::Bound::Included(i) => (*i + 1).min(n), + // std::ops::Bound::Excluded(i) => *i, + // std::ops::Bound::Unbounded => n, + // }; + // self.index_mut(start..end) + // } + + // fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { + // self.get_mut(index) + // } + + // fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { + // self.index_mut(index) + // } + + // fn as_mut_slice<'c>(&'c mut self) -> Self::ReborrowMut<'c> where 'a: 'c { + // self.as_mut_slice() + // } + + // fn apply_index(&mut self, indices: &[usize]) { + // let mut perm = soa_derive::Permutation::oneline(indices).inverse(); + // self.as_mut_slice().apply_permutation(&mut perm); + // } + + // fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { + // self.iter_mut() + // } + + // fn as_mut_ptr(&mut self) -> <#name as ::soa_derive::SoAPointers>::MutPtr { + // self.as_mut_ptr() + // } + // } + + // impl<'a> ::soa_derive::SoAVec<'a, #name> for #vec_name { + // fn new() -> Self { + // Self::new() + // } + + // fn with_capacity(capacity: usize) -> Self { + // Self::with_capacity(capacity) + // } + + // fn capacity(&self) -> usize { + // self.capacity() + // } + + // fn reserve(&mut self, additional: usize) { + // self.reserve(additional); + // } + + // fn reserve_exact(&mut self, additional: usize) { + // self.reserve_exact(additional); + // } + + // fn shrink_to_fit(&mut self) { + // self.shrink_to_fit(); + // } + + // fn truncate(&mut self, len: usize) { + // self.truncate(len); + // } + + // fn push(&mut self, value: #name) { + // self.push(value); + // } + + // fn swap_remove(&mut self, index: usize) -> #name { + // self.swap_remove(index) + // } + + // fn insert(&mut self, index: usize, element: #name) { + // self.insert(index, element); + // } + + // fn replace(&mut self, index: usize, element: #name) -> #name { + // self.replace(index, element) + // } + + // fn remove(&mut self, index: usize) -> #name { + // self.remove(index) + // } + + // fn pop(&mut self) -> Option<#name> { + // self.pop() + // } + + // fn append(&mut self, other: &mut Self) { + // self.append(other); + // } + + // fn clear(&mut self) { + // self.clear(); + // } + + // fn split_off(&mut self, at: usize) -> Self { + // self.split_off(at) + // } + // } #[allow(clippy::drop_non_drop)] impl Drop for #vec_name { diff --git a/src/lib.rs b/src/lib.rs index 6e7d0a9..1a4add5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -597,33 +597,52 @@ impl<'a: 't, 't, T: SoATypes<'a, 't> + 'a> Swarm<'a, 't, T> { the associate type provided by [`StructOfArray`] has *no* bounds, which means it proves no methods are available. */ -pub trait SoATypes<'a: 't, 't>: SoAProps<'a> + Sized { - /// The [`Vec`]-like type - type Vec: SoAVec<'a, Self, - Ref<'a> = >::Ref, - Reborrow<'a> = Self::Slice, - RefMut<'a> = >::RefMut, - ReborrowMut<'a> = Self::SliceMut, - > + 'a where Self: 'a; - /// The immutable `&[Self]`-like type - type Slice: SoASlice<'a, Self, Ref<'a> =>::Ref, Reborrow<'a> = Self::Slice> + 'a where Self: 'a; - /// The mutable `&[Self]`-like type - type SliceMut: SoAMutSlice< - 'a, Self, - Ref<'a> =>::Ref, - Reborrow<'a> = Self::Slice, - RefMut<'a> = >::RefMut, - ReborrowMut<'a> = Self::SliceMut, - > + 'a where Self: 'a; - - type Ref: 't; - type RefMut: 't; - -} +// pub trait SoATypes<'a: 't, 't>: SoAProps<'a> + Sized { +// /// The [`Vec`]-like type +// type Vec: SoAVec<'a, Self> + 'a where Self: 'a; +// /// The immutable `&[Self]`-like type +// type Slice: SoASlice< +// 'a, +// Self, +// Ref<'t> = < +// >::Vec +// as SoASlice<'a, Self> +// >::Ref<'t>, +// Reborrow<'t> = < +// >::Vec +// as SoASlice<'a, Self> +// >::Reborrow<'t> +// > + 'a where Self: 'a; +// /// The mutable `&[Self]`-like type +// type SliceMut: SoAMutSlice< +// 'a, Self, +// Ref<'t> = < +// >::Vec +// as SoASlice<'a, Self> +// >::Ref<'t>, +// Reborrow<'t> = < +// >::Vec +// as SoASlice<'a, Self> +// >::Reborrow<'t>, + +// RefMut<'t> = < +// >::Vec +// as SoAMutSlice<'a, Self> +// >::RefMut<'t>, +// ReborrowMut<'t> = < +// >::Vec +// as SoAMutSlice<'a, Self> +// >::ReborrowMut<'t>, +// > + 'a where Self: 'a; + +// type Ref: 't; +// type RefMut: 't; + +// } /// A collection of supporting traits for [`StructOfArray`] bundled in one place for ease-of-access pub mod prelude { - pub use super::{SoAVec, SoAIter, SoAProps, SoASlice, SoAMutSlice, SoAPointers, SoATypes, StructOfArray}; + // pub use super::{SoAVec, SoAIter, SoAProps, SoASlice, SoAMutSlice, SoAPointers, SoATypes, StructOfArray}; } diff --git a/tests/generic.rs b/tests/generic.rs index c97ab95..bd25504 100644 --- a/tests/generic.rs +++ b/tests/generic.rs @@ -1,116 +1,117 @@ -use soa_derive::prelude::*; +// use soa_derive::prelude::*; -mod particles; -use self::particles::Particle; +// mod particles; +// use self::particles::Particle; -fn may_iter<'a: 't, 't, T: SoATypes<'a, 't>>(vec: &'a T::Vec) -> T::Iter { - let x= vec.iter(); - x -} - -fn may_push<'a: 't, 't, T: SoATypes<'a, 't>>(vec: &'a mut T::Vec, val: T) { - vec.push(val); -} +// fn may_iter<'a: 't, 't, T: SoATypes<'a, 't>>(vec: &'a T::Vec) -> T::Iter { +// let x= vec.iter(); +// x +// } -fn may_sort<'a: 't, 't>(vec: &mut >::Vec) { - let mut indices: Vec<_> = (0..vec.len()).collect(); - - indices.sort_by(|j, k| { - let a = vec.index(*j); - let b = vec.index(*k); - a.mass.total_cmp(b.mass).reverse() - }); - - vec.apply_index(&indices); -} - - -fn may_sort_generic<'a: 't, 't: 'c, 'c, T: SoATypes<'a, 't>>(vec: &'c mut >::Vec) { - let mut indices: Vec<_> = (0..vec.len()).collect(); - - indices.sort_by(|j, k| { - let a = vec.index(*j); - let b = vec.index(*k); - std::cmp::Ordering::Equal - }); - -} - - -fn may_closure_sort<'a: 't, 't, F>(vec: &mut >::Vec, mut f: F) where F: FnMut(::Ref, ::Ref) -> std::cmp::Ordering { - let mut indices: Vec<_> = (0..vec.len()).collect(); - - indices.sort_by(|j, k| { - let a = vec.index(*j); - let b = vec.index(*k); - f(a, b) - }); - - vec.apply_index(&indices); -} - - -#[test] -fn test_generic_type_behavior() { - let mut x = ::Vec::new(); - x.push(Particle::new("foo".into(), 100.0)); - let y: Vec<_> = may_iter::(&x).collect(); - assert_eq!(x.len(), y.len()); - assert_eq!(x.get(0).as_ref(), y.get(0)); - drop(y); - - let z = Particle::new("bar".into(), 1000.0); - may_push(&mut x, z); - assert_eq!(x.len(), 2); - may_sort(&mut x); - let a = x.index(0); - let b = x.index(1); - assert!(a.mass > b.mass); - - may_closure_sort(&mut x, |a, b| a.mass.total_cmp(&b.mass)); - - let a = x.index(0); - let b = x.index(1); - assert!(a.mass < b.mass); -} - - -#[derive(Debug, Clone)] -struct Swarm<'a: 't, 't, T: soa_derive::SoATypes<'a, 't> + 'a> { - entries: T::Vec, -} - -impl<'a: 't, 't, T: soa_derive::SoATypes<'a, 't>> Swarm<'a, 't, T> { - fn new() -> Self { - Self { - entries: T::Vec::new() - } - } - - fn push(&mut self, value: T) { - self.entries.push(value); - } - - fn iter(&'a self) -> T::Iter { - self.entries.iter() - } - - fn view(&'a self) -> T::Slice { - self.entries.as_slice() - } -} +// fn may_push<'a: 't, 't, T: SoATypes<'a, 't>>(vec: &'a mut T::Vec, val: T) { +// vec.push(val); +// } -#[test] -fn test_wrapped() { - let mut this: Swarm<'_, '_, Particle> = Swarm::new(); - let x= Particle::new("foo".into(), 100.0); - this.push(x); - let x = Particle::new("bar".into(), 1000.0); - this.push(x); - let x = Particle::new("baz".into(), 10.0); - this.push(x); - - assert_eq!(this.iter().count(), 3); +// fn may_sort<'a: 't, 't>(vec: &mut >::Vec) { +// let mut indices: Vec<_> = (0..vec.len()).collect(); - assert_eq!(this.view().len(), 3); -} \ No newline at end of file +// indices.sort_by(|j, k| { +// let a = vec.index(*j); +// let b = vec.index(*k); +// a.mass.total_cmp(b.mass).reverse() +// }); + +// vec.apply_index(&indices); +// } + + +// fn may_sort_generic<'a: 't, 't: 'c, 'c, T: SoATypes<'a, 't>>(vec: &'c mut >::Vec) where <>::Vec as SoASlice<'a, T>>::Ref<'t> : PartialOrd { +// let mut indices: Vec<_> = (0..vec.len()).collect(); + +// indices.sort_by(|j, k| { + +// let a: <>::Vec as SoASlice<'a, T>>::Ref<'_> = vec.index(*j); +// let b: <>::Vec as SoASlice<'a, T>>::Ref<'_> = vec.index(*k); +// a.partial_cmp(&b).unwrap() +// }); + +// } + + +// fn may_closure_sort<'a: 't, 't, F>(vec: &mut >::Vec, mut f: F) where F: FnMut(::Ref, ::Ref) -> std::cmp::Ordering { +// let mut indices: Vec<_> = (0..vec.len()).collect(); + +// indices.sort_by(|j, k| { +// let a = vec.index(*j); +// let b = vec.index(*k); +// f(a, b) +// }); + +// vec.apply_index(&indices); +// } + + +// #[test] +// fn test_generic_type_behavior() { +// let mut x = ::Vec::new(); +// x.push(Particle::new("foo".into(), 100.0)); +// let y: Vec<_> = may_iter::(&x).collect(); +// assert_eq!(x.len(), y.len()); +// assert_eq!(x.get(0).as_ref(), y.get(0)); +// drop(y); + +// let z = Particle::new("bar".into(), 1000.0); +// may_push(&mut x, z); +// assert_eq!(x.len(), 2); +// may_sort(&mut x); +// let a = x.index(0); +// let b = x.index(1); +// assert!(a.mass > b.mass); + +// may_closure_sort(&mut x, |a, b| a.mass.total_cmp(&b.mass)); + +// let a = x.index(0); +// let b = x.index(1); +// assert!(a.mass < b.mass); +// } + + +// #[derive(Debug, Clone)] +// struct Swarm<'a: 't, 't, T: soa_derive::SoATypes<'a, 't> + 'a> { +// entries: T::Vec, +// } + +// impl<'a: 't, 't, T: soa_derive::SoATypes<'a, 't>> Swarm<'a, 't, T> { +// fn new() -> Self { +// Self { +// entries: T::Vec::new() +// } +// } + +// fn push(&mut self, value: T) { +// self.entries.push(value); +// } + +// fn iter(&'a self) -> T::Iter { +// self.entries.iter() +// } + +// fn view(&'a self) -> <>::Vec as SoASlice<'a, T>>::Reborrow<'a> { +// self.entries.as_slice() +// } +// } + +// #[test] +// fn test_wrapped() { +// let mut this: Swarm<'_, '_, Particle> = Swarm::new(); +// let x= Particle::new("foo".into(), 100.0); +// this.push(x); +// let x = Particle::new("bar".into(), 1000.0); +// this.push(x); +// let x = Particle::new("baz".into(), 10.0); +// this.push(x); + +// assert_eq!(this.iter().count(), 3); + +// assert_eq!(this.view().len(), 3); +// } \ No newline at end of file diff --git a/tests/nested_soa.rs b/tests/nested_soa.rs index 5e55660..17253d9 100644 --- a/tests/nested_soa.rs +++ b/tests/nested_soa.rs @@ -59,23 +59,23 @@ fn nested_soa() { }); } -fn generic_f<'a, 't, T: SoATypes<'a, 't>>(vec: &'a T::Vec) { - assert_eq!(vec.len(), 2); -} +// fn generic_f<'a, 't, T: SoATypes<'a, 't>>(vec: &'a T::Vec) { +// assert_eq!(vec.len(), 2); +// } -#[test] -fn test_nested_generic() { - let mut particle_vec = ParticleVec::new(); - particle_vec.push(Particle { - point: Point { x: 1.0, y: 2.0 }, - color: Color { r: 255, g: 0, b: 0, a: 255 }, - mass: 1.0, - }); - particle_vec.push(Particle { - point: Point { x: 2.0, y: 3.0 }, - color: Color { r: 128, g: 255, b: 100, a: 23 }, - mass: 2.0, - }); +// #[test] +// fn test_nested_generic() { +// let mut particle_vec = ParticleVec::new(); +// particle_vec.push(Particle { +// point: Point { x: 1.0, y: 2.0 }, +// color: Color { r: 255, g: 0, b: 0, a: 255 }, +// mass: 1.0, +// }); +// particle_vec.push(Particle { +// point: Point { x: 2.0, y: 3.0 }, +// color: Color { r: 128, g: 255, b: 100, a: 23 }, +// mass: 2.0, +// }); - generic_f::(&particle_vec); -} \ No newline at end of file +// generic_f::(&particle_vec); +// } \ No newline at end of file From 9ba23587e5e547a2c2ba53983dc46234e5999738 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Tue, 14 Jan 2025 15:43:06 -0500 Subject: [PATCH 10/37] checkpoint --- soa-derive-internal/src/lib.rs | 40 ++- soa-derive-internal/src/slice.rs | 278 ++++++++++----------- soa-derive-internal/src/vec.rs | 315 ++++++++++++----------- src/lib.rs | 206 +++++++++++++-- tests/generic.rs | 6 +- tests/nested_soa.rs | 2 +- tests/particles/mod.rs | 414 ++++++++++++++++++++++++++++++- 7 files changed, 933 insertions(+), 328 deletions(-) diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index e0f88b6..f6c2ecb 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -39,25 +39,43 @@ pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { use crate::input::Input; use quote::quote; + +#[allow(unused)] fn derive_trait(input: &Input) -> TokenStream { let name = &input.name; let vec_name = names::vec_name(name); - // let slice_name = names::slice_name(name); - // let slice_mut_name = names::slice_mut_name(name); - // let ref_name = names::ref_name(name); - // let ref_mut_name = names::ref_mut_name(name); + let slice_name = names::slice_name(name); + let slice_mut_name = names::slice_mut_name(name); + let ref_name = names::ref_name(name); + let ref_mut_name = names::ref_mut_name(name); + let ptr_name = names::ptr_name(name); + let ptr_mut_name = names::ptr_mut_name(name); quote! { impl soa_derive::StructOfArray for #name { type Type = #vec_name; } - // impl<'a: 't, 't> soa_derive::SoATypes<'a, 't> for #name { - // type Vec = #vec_name; - // type Slice = #slice_name<'a>; - // type SliceMut = #slice_mut_name<'a>; - // type Ref = #ref_name<'a>; - // type RefMut = #ref_mut_name<'a>; - // } + /* + impl<'a> ::soa_derive::SoATypes<'a> for #name { + type Ptr = #ptr_name; + + type PtrMut = #ptr_mut_name; + + type Vec<'t> = #vec_name where 'a: 't, Self: 'a; + + type Ref<'t> = #ref_name<'t> where Self: 't, Self: 'a, 'a: 't; + + type Iter<'t> = <#vec_name as ::soa_derive::SoAVec<'a, Self>>::Iter<'t> where >::Vec<'t>: 't, Self: 'a, 'a: 't; + + type Slice<'t> = #slice_name<'t> where Self: 'a, Self::Vec<'t>: 't, 'a: 't; + + type RefMut<'t> = #ref_mut_name<'t> where Self: 't, Self: 'a, 'a: 't; + + type SliceMut<'t> = #slice_mut_name<'t> where Self: 'a, Self::Vec<'t>: 't, 'a: 't; + + type IterMut<'t> = <#vec_name as ::soa_derive::SoAVec<'a, Self>>::IterMut<'t> where >::Vec<'t>: 't, Self: 'a, 'a: 't; + } + */ } } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index 7cbe6c8..1af9467 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -238,53 +238,54 @@ pub fn derive(input: &Input) -> TokenStream { } } - // impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_name<'a> { - // type Ref<'t> = #ref_name<'t> where 'a: 't; - // type Reborrow<'t> = #slice_name<'t> where 'a: 't; - - // fn len(&self) -> usize { - // self.len() - // } - - // fn is_empty(&self) -> bool { - // self.is_empty() - // } - - // fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c { - // self.reborrow() - // } - - // fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { - // self.iter() - // } - - // fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { - // self.get(index) - // } - - // fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { - // let view: #slice_name<'c> = self.reborrow::<'c>(); - // ::soa_derive::SoAIndex::index(index, view) - // } - - // fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c { - // let start = match index.start_bound() { - // std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - // std::ops::Bound::Unbounded => 0, - // }; - // let n = self.len(); - // let end = match index.end_bound() { - // std::ops::Bound::Included(i) => (*i + 1).min(n), - // std::ops::Bound::Excluded(i) => *i, - // std::ops::Bound::Unbounded => n, - // }; - // self.index(start..end) - // } - - // fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { - // self.as_ptr() - // } - // } + impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_name<'a> { + type Ref<'t> = #ref_name<'t> where Self: 't, 'a: 't; + type Slice<'t> = #slice_name<'t> where Self: 't, 'a: 't; + type Iter<'t> = #iter_name<'t> where Self: 't, 'a: 't; + type Ptr = #ptr_name; + + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c { + self.reborrow::<'c>() + } + + fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index(start..end) + } + + fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + self.get(index) + } + + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + self.index(index) + } + + fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c { + self.iter() + } + + fn as_ptr(&self) -> Self::Ptr { + self.as_ptr() + } + } }; @@ -717,98 +718,97 @@ pub fn derive_mut(input: &Input) -> TokenStream { } } - // impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_mut_name<'a> { - // type Ref<'t> = #ref_name<'t> where 'a: 't; - // type Reborrow<'t> = #slice_name<'t> where 'a: 't; - - // fn len(&self) -> usize { - // self.len() - // } - - // fn is_empty(&self) -> bool { - // self.is_empty() - // } - - // fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c { - // self.as_slice() - // } - - // fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { - // self.as_ref().into_iter() - // } - - // fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { - // self.get(index) - // } - - // fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { - // let slice: #slice_name<'c> = self.as_slice(); - // ::soa_derive::SoAIndex::index(index, slice) - // } - - // fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c { - // let start = match index.start_bound() { - // std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - // std::ops::Bound::Unbounded => 0, - // }; - // let n = self.len(); - // let end = match index.end_bound() { - // std::ops::Bound::Included(i) => (*i + 1).min(n), - // std::ops::Bound::Excluded(i) => *i, - // std::ops::Bound::Unbounded => n, - // }; - // self.index(start..end) - // } - - // fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { - // self.as_ptr() - // } - // } - - // impl<'a> ::soa_derive::SoAMutSlice<'a, #name> for #slice_mut_name<'a> { - // type RefMut<'t> = #ref_mut_name<'t> where 'a: 't, Self: 't; - - // type ReborrowMut<'t> = #slice_mut_name<'t> where 'a: 't, Self: 't; - - // fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::ReborrowMut<'c> where 'a: 'c { - // let start = match index.start_bound() { - // std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - // std::ops::Bound::Unbounded => 0, - // }; - // let n = self.len(); - // let end = match index.end_bound() { - // std::ops::Bound::Included(i) => (*i + 1).min(n), - // std::ops::Bound::Excluded(i) => *i, - // std::ops::Bound::Unbounded => n, - // }; - // self.index_mut(start..end) - // } - - // fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { - // self.get_mut(index) - // } - - // fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { - // self.index_mut(index) - // } - - // fn as_mut_slice<'c>(&'c mut self) -> Self::ReborrowMut<'c> where 'a: 'c { - // self.reborrow() - // } - - // fn apply_index(&mut self, indices: &[usize]) { - // let mut perm = soa_derive::Permutation::oneline(indices).inverse(); - // self.apply_permutation(&mut perm); - // } - - // fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { - // self.iter_mut() - // } - - // fn as_mut_ptr(&mut self) -> <#name as ::soa_derive::SoAPointers>::MutPtr { - // self.as_mut_ptr() - // } - // } + impl<'a> ::soa_derive::SoASliceMut<'a, #name> for #slice_mut_name<'a> { + type Ref<'t> = #ref_name<'t> where Self: 't, 'a: 't; + type Slice<'t> = #slice_name<'t> where Self: 't, 'a: 't; + type Iter<'t> = #iter_name<'t> where Self: 't, 'a: 't; + type Ptr = #ptr_name; + + type RefMut<'t> = #ref_mut_name<'t> where 'a: 't, Self: 't; + type SliceMut<'t> = #slice_mut_name<'t> where 'a: 't, Self: 't; + type IterMut<'t> = #iter_mut_name<'t> where 'a: 't, Self: 't; + type PtrMut = #ptr_mut_name; + + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c { + self.as_slice() + } + + fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index(start..end) + } + + fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + self.get(index) + } + + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + self.index(index) + } + + fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c { + self.as_ref().into_iter() + } + + fn as_mut_slice<'c>(&'c mut self) -> Self::SliceMut<'c> where 'a: 'c { + self.reborrow() + } + + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> where 'a: 'c { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index_mut(start..end) + } + + fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { + self.get_mut(index) + } + + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { + self.index_mut(index) + } + + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> where 'a: 'c { + self.iter_mut() + } + + fn apply_index(&mut self, indices: &[usize]) { + self.apply_permutation(&mut ::soa_derive::Permutation::oneline(indices).inverse()); + } + + fn as_ptr(&self) -> Self::Ptr { + self.as_ptr() + } + + fn as_mut_ptr(&mut self) -> Self::PtrMut { + self.as_mut_ptr() + } + } }; diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index 302e002..e49d30e 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -450,166 +450,165 @@ pub fn derive(input: &Input) -> TokenStream { } } +/* + impl<'a> ::soa_derive::SoAVec<'a, #name> for #vec_name { + type Ref<'t> = #ref_name<'t> where Self: 't, 'a: 't; + type Slice<'t> = #slice_name<'t> where Self: 't, 'a: 't; + type Iter<'t> = #iter_name<'t> where Self: 't, 'a: 't; + type Ptr = #ptr_name; - // impl<'a> ::soa_derive::SoASlice<'a, #name> for #vec_name { - // type Ref<'t> = #ref_name<'t> where 'a: 't; - // type Reborrow<'t> = #slice_name<'t> where 'a: 't; - - // fn len(&self) -> usize { - // self.len() - // } - - // fn is_empty(&self) -> bool { - // self.is_empty() - // } - - // fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c { - // self.as_slice() - // } - - // fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { - // self.iter() - // } - - // fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { - // self.get(index) - // } - - // fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { - // let slice: #slice_name<'c> = self.as_slice(); - // ::soa_derive::SoAIndex::index(index, slice) - // } - - // fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c { - // let start = match index.start_bound() { - // std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - // std::ops::Bound::Unbounded => 0, - // }; - // let n = self.len(); - // let end = match index.end_bound() { - // std::ops::Bound::Included(i) => (*i + 1).min(n), - // std::ops::Bound::Excluded(i) => *i, - // std::ops::Bound::Unbounded => n, - // }; - // self.index(start..end) - // } - - // fn as_ptr(&self) -> <#name as ::soa_derive::SoAPointers>::Ptr { - // self.as_ptr() - // } - // } - - // impl<'a> ::soa_derive::SoAMutSlice<'a, #name> for #vec_name { - // type RefMut<'t> = #ref_mut_name<'t> where 'a: 't, Self: 't; - - // type ReborrowMut<'t> = #slice_mut_name<'t> where 'a: 't, Self: 't; - - // fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::ReborrowMut<'c> where 'a: 'c { - // let start = match index.start_bound() { - // std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - // std::ops::Bound::Unbounded => 0, - // }; - // let n = self.len(); - // let end = match index.end_bound() { - // std::ops::Bound::Included(i) => (*i + 1).min(n), - // std::ops::Bound::Excluded(i) => *i, - // std::ops::Bound::Unbounded => n, - // }; - // self.index_mut(start..end) - // } - - // fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { - // self.get_mut(index) - // } - - // fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { - // self.index_mut(index) - // } - - // fn as_mut_slice<'c>(&'c mut self) -> Self::ReborrowMut<'c> where 'a: 'c { - // self.as_mut_slice() - // } - - // fn apply_index(&mut self, indices: &[usize]) { - // let mut perm = soa_derive::Permutation::oneline(indices).inverse(); - // self.as_mut_slice().apply_permutation(&mut perm); - // } - - // fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { - // self.iter_mut() - // } - - // fn as_mut_ptr(&mut self) -> <#name as ::soa_derive::SoAPointers>::MutPtr { - // self.as_mut_ptr() - // } - // } - - // impl<'a> ::soa_derive::SoAVec<'a, #name> for #vec_name { - // fn new() -> Self { - // Self::new() - // } - - // fn with_capacity(capacity: usize) -> Self { - // Self::with_capacity(capacity) - // } - - // fn capacity(&self) -> usize { - // self.capacity() - // } - - // fn reserve(&mut self, additional: usize) { - // self.reserve(additional); - // } - - // fn reserve_exact(&mut self, additional: usize) { - // self.reserve_exact(additional); - // } - - // fn shrink_to_fit(&mut self) { - // self.shrink_to_fit(); - // } - - // fn truncate(&mut self, len: usize) { - // self.truncate(len); - // } - - // fn push(&mut self, value: #name) { - // self.push(value); - // } - - // fn swap_remove(&mut self, index: usize) -> #name { - // self.swap_remove(index) - // } - - // fn insert(&mut self, index: usize, element: #name) { - // self.insert(index, element); - // } - - // fn replace(&mut self, index: usize, element: #name) -> #name { - // self.replace(index, element) - // } - - // fn remove(&mut self, index: usize) -> #name { - // self.remove(index) - // } - - // fn pop(&mut self) -> Option<#name> { - // self.pop() - // } - - // fn append(&mut self, other: &mut Self) { - // self.append(other); - // } - - // fn clear(&mut self) { - // self.clear(); - // } - - // fn split_off(&mut self, at: usize) -> Self { - // self.split_off(at) - // } - // } + type RefMut<'t> = #ref_mut_name<'t> where Self: 't, 'a: 't; + type SliceMut<'t> = #slice_mut_name<'t> where Self: 't, 'a: 't; + type IterMut<'t> = #iter_mut_name<'t> where Self: 't, 'a: 't; + type PtrMut = #ptr_mut_name; + + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c { + self.as_slice() + } + + fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index(start..end) + } + + fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + ::soa_derive::SoAIndex::get(index, self) + } + + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + ::soa_derive::SoAIndex::index(index, self) + } + + fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c { + self.iter() + } + + fn as_mut_slice<'c>(&'c mut self) -> Self::SliceMut<'c> where 'a: 'c { + self.as_mut_slice() + } + + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> where 'a: 'c { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index_mut(start..end) + } + + fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { + self.get_mut(index) + } + + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { + self.index_mut(index) + } + + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> where 'a: 'c { + self.iter_mut() + } + + fn apply_index(&mut self, indices: &[usize]) { + let mut view = self.as_mut_slice(); + ::soa_derive::SoASliceMut::apply_index(&mut view, indices); + } + + fn new() -> Self { + Self::new() + } + + fn with_capacity(capacity: usize) -> Self { + Self::with_capacity(capacity) + } + + fn capacity(&self) -> usize { + self.capacity() + } + + fn reserve(&mut self, additional: usize) { + self.reserve(additional); + } + + fn reserve_exact(&mut self, additional: usize) { + self.reserve_exact(additional); + } + + fn shrink_to_fit(&mut self) { + self.shrink_to_fit(); + } + + fn truncate(&mut self, len: usize) { + self.truncate(len); + } + + fn push(&mut self, value: #name) { + self.push(value); + } + + fn swap_remove(&mut self, index: usize) -> #name { + self.swap_remove(index) + } + + fn insert(&mut self, index: usize, element: #name) { + self.insert(index, element); + } + + fn replace(&mut self, index: usize, element: #name) -> #name { + self.replace(index, element) + } + + fn remove(&mut self, index: usize) -> #name { + self.remove(index) + } + + fn pop(&mut self) -> Option<#name> { + self.pop() + } + + fn append(&mut self, other: &mut Self) { + self.append(other); + } + + fn clear(&mut self) { + self.clear(); + } + + fn split_off(&mut self, at: usize) -> Self { + self.split_off(at) + } + + fn as_ptr(&self) -> Self::Ptr { + self.as_ptr() + } + + fn as_mut_ptr(&mut self) -> Self::PtrMut { + self.as_mut_ptr() + } + } +*/ #[allow(clippy::drop_non_drop)] impl Drop for #vec_name { fn drop(&mut self) { diff --git a/src/lib.rs b/src/lib.rs index 1a4add5..5ef81c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -399,17 +399,19 @@ impl<'a, T> SoAProps<'a> for T where T: StructOfArray + SoAIter<'a> + SoAPointer /** * The interface for the `Slice` immutable slice struct-of-arrays type. */ -pub trait SoASlice<'a, T: SoAProps<'a>> { - type Ref<'t> where 'a: 't, Self: 't; - type Reborrow<'t> where 'a: 't, Self: 't; +pub trait SoASlice<'a, T> { + type Ref<'t> where Self: 'a, 'a: 't; + type Slice<'t>: SoASlice<'t, T> where Self: 't, 'a: 't; + type Iter<'t>: Iterator> where Self: 'a, 'a: 't; + type Ptr; fn len(&self) -> usize; fn is_empty(&self) -> bool; - fn as_slice<'c>(&'c self) -> Self::Reborrow<'c> where 'a: 'c; + fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c; /// Create a slice of this vector matching the given `range`. This /// is analogous to `Index>`. - fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Reborrow<'c> where 'a: 'c; + fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c; /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c; @@ -418,7 +420,7 @@ pub trait SoASlice<'a, T: SoAProps<'a>> { fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c; /// Create an immutable iterator - fn iter(&'a self) -> T::Iter; + fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c; /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) fn first<'c>(&'c self) -> Option> where 'a: 'c { @@ -431,23 +433,60 @@ pub trait SoASlice<'a, T: SoAProps<'a>> { } /// Obtain a `const` pointer type for this data - fn as_ptr(&self) -> T::Ptr; + fn as_ptr(&self) -> Self::Ptr; } /** * The interface for the `SliceMut` mutable slice struct-of-arrays type. A generalization of [`SoASlice`] * whose methods can modify elements of the arrays */ -pub trait SoAMutSlice<'a, T: SoAProps<'a>>: SoASlice<'a, T> { +pub trait SoASliceMut<'a, T: StructOfArray> { + type Ref<'t> where Self: 'a, 'a: 't; + type Slice<'t>: SoASlice<'t, T> where Self: 't, 'a: 't; + type Iter<'t>: Iterator> where Self: 'a, 'a: 't; + type Ptr; + type RefMut<'t> where 'a: 't, Self: 't; - type ReborrowMut<'t> where 'a: 't, Self: 't; + type SliceMut<'t>: SoASliceMut<'t, T> where 'a: 't, Self: 't; + type IterMut<'t>: Iterator> where 'a: 't, Self: 't; + type PtrMut; + + fn len(&self) -> usize; + fn is_empty(&self) -> bool; + fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c; + + /// Create a slice of this vector matching the given `range`. This + /// is analogous to `Index>`. + fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c; + + /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) + fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c; + + /// Analogous to [`std::ops::Index::index()`] for `usize` + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c; + + /// Create an immutable iterator + fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c; + + /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) + fn first<'c>(&'c self) -> Option> where 'a: 'c { + self.get(0) + } + + /// Analogous to [`slice::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last) + fn last<'c>(&'c self) -> Option> where 'a: 'c { + self.get(self.len().saturating_sub(1)) + } + + /// Obtain a `const` pointer type for this data + fn as_ptr(&self) -> Self::Ptr; /// Analogous to [`Vec::as_mut_slice()`] - fn as_mut_slice<'c>(&'c mut self) -> Self::ReborrowMut<'c> where 'a: 'c; + fn as_mut_slice<'c>(&'c mut self) -> Self::SliceMut<'c> where 'a: 'c; /// Create a mutable slice of this vector matching the given /// `range`. This is analogous to `IndexMut>`. - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::ReborrowMut<'c> where 'a: 'c; + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> where 'a: 'c; /// Analogous to [`slice::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut) fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c; @@ -456,7 +495,7 @@ pub trait SoAMutSlice<'a, T: SoAProps<'a>>: SoASlice<'a, T> { fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c; /// Creates a mutable iterator - fn iter_mut(&'a mut self) -> T::IterMut; + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> where 'a: 'c; /** Re-order the arrays using the provided indices. This is provided so that generic sorting methods can be implemented because closure-passing trait methods encounter difficulties with lifetimes. @@ -499,7 +538,7 @@ pub trait SoAMutSlice<'a, T: SoAProps<'a>>: SoASlice<'a, T> { } /// Obtain a `mut` pointer type for this data - fn as_mut_ptr(&mut self) -> T::MutPtr; + fn as_mut_ptr(&mut self) -> Self::PtrMut; } /** @@ -508,7 +547,106 @@ pub trait SoAMutSlice<'a, T: SoAProps<'a>>: SoASlice<'a, T> { * * **NOTE**: This interface is incomplete and additional methods may be added as needed. */ -pub trait SoAVec<'a, T: SoAProps<'a>>: SoASlice<'a, T> + SoAMutSlice<'a, T> { +pub trait SoAVec<'a, T: StructOfArray>: 'a { + type Ref<'t> where 'a: 't; + type Slice<'t>: SoASlice<'t, T> where Self: 'a, 'a: 't; + type Iter<'t>: Iterator> where 'a: 't; + type Ptr; + + type RefMut<'t> where Self: 'a, 'a: 't; + type SliceMut<'t>: SoASliceMut<'t, T> where Self: 'a, 'a: 't; + type IterMut<'t>: Iterator> where Self: 'a, 'a: 't; + type PtrMut; + + fn len(&self) -> usize; + fn is_empty(&self) -> bool; + fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c; + + /// Create a slice of this vector matching the given `range`. This + /// is analogous to `Index>`. + fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c; + + /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) + fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c; + + /// Analogous to [`std::ops::Index::index()`] for `usize` + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c; + + /// Create an immutable iterator + fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c; + + /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) + fn first<'c>(&'c self) -> Option> where 'a: 'c { + self.get(0) + } + + /// Analogous to [`slice::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last) + fn last<'c>(&'c self) -> Option> where 'a: 'c { + self.get(self.len().saturating_sub(1)) + } + + /// Obtain a `const` pointer type for this data + fn as_ptr(&self) -> Self::Ptr; + + /// Analogous to [`Vec::as_mut_slice()`] + fn as_mut_slice<'c>(&'c mut self) -> Self::SliceMut<'c> where 'a: 'c; + + /// Create a mutable slice of this vector matching the given + /// `range`. This is analogous to `IndexMut>`. + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> where 'a: 'c; + + /// Analogous to [`slice::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut) + fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c; + + /// Analogous to [`std::ops::IndexMut::index_mut()`] for `usize` + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c; + + /// Creates a mutable iterator + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> where 'a: 'c; + + /** Re-order the arrays using the provided indices. This is provided so that generic sorting methods + can be implemented because closure-passing trait methods encounter difficulties with lifetimes. + + # Example + + ``` + use soa_derive::{StructOfArray, prelude::*}; + + #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] + #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] + pub struct Particle { + pub name: String, + pub mass: f64, + } + # fn may_sort<'a>(vec: &mut >::Vec) { + // vec: &mut >::Vec + let mut indices: Vec<_> = (0..vec.len()).collect(); + + indices.sort_by(|j, k| { + let a = vec.index(*j); + let b = vec.index(*k); + a.mass.total_cmp(b.mass).reverse() + }); + + vec.apply_index(&indices); + # } + ``` + */ + fn apply_index(&mut self, indices: &[usize]); + + /// Analogous to [`slice::first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut) + fn first_mut<'c>(&'c mut self) -> Option> { + self.get_mut(0) + } + + /// Analogous to [`slice::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut) + fn last_mut<'c>(&'c mut self) -> Option> { + self.get_mut(self.len().saturating_sub(1)) + } + + /// Obtain a `mut` pointer type for this data + fn as_mut_ptr(&mut self) -> Self::PtrMut; + /// Create a new, empty struct of arrays fn new() -> Self; @@ -558,6 +696,44 @@ pub trait SoAVec<'a, T: SoAProps<'a>>: SoASlice<'a, T> + SoAMutSlice<'a, T> { fn split_off(&mut self, at: usize) -> Self; } + pub trait SoATypes<'a>: StructOfArray + Sized { + type Ref<'t> where Self: 't, Self: 'a, 'a: 't; + type RefMut<'t> where Self: 't, Self: 'a, 'a: 't; + + type Ptr; + type PtrMut; + + type Iter<'t>: Iterator> where Self: 'a, 'a: 't; + type Slice<'t>: SoASlice< + 't, + Self, + Ref<'t> = Self::Ref<'t>, + Iter<'t> = Self::Iter<'t>, + Ptr = Self::Ptr, + > where Self: 'a, 'a: 't; + + type SliceMut<'t>: SoASliceMut< + 't, + Self, + Ref<'t> = Self::Ref<'t>, + Iter<'t> = Self::Iter<'t>, + RefMut<'t> = Self::RefMut<'t>, + IterMut<'t> = Self::IterMut<'t>, + Ptr = Self::Ptr, + PtrMut = Self::PtrMut, + > where Self: 'a, 'a: 't; + type IterMut<'t>: Iterator> where Self: 'a, 'a: 't; + + type Vec<'t>: SoAVec<'a, + Self, + Ref<'a> = Self::Ref<'a>, + RefMut<'a> = Self::RefMut<'a>, + Ptr = Self::Ptr, + PtrMut = Self::PtrMut, + Slice<'a> = Self::Slice<'a> + > where 'a: 't, Self: 'a; +} + /** A collection of types that represent the different facets of a [`StructOfArray`] type. It is a convenience type that can be used as a trait bound, but because it introduces @@ -642,7 +818,7 @@ impl<'a: 't, 't, T: SoATypes<'a, 't> + 'a> Swarm<'a, 't, T> { /// A collection of supporting traits for [`StructOfArray`] bundled in one place for ease-of-access pub mod prelude { - // pub use super::{SoAVec, SoAIter, SoAProps, SoASlice, SoAMutSlice, SoAPointers, SoATypes, StructOfArray}; + pub use super::{SoAVec, SoAIter, SoAProps, SoASlice, SoASliceMut, SoAPointers, SoATypes, StructOfArray}; } diff --git a/tests/generic.rs b/tests/generic.rs index bd25504..cef0a38 100644 --- a/tests/generic.rs +++ b/tests/generic.rs @@ -1,7 +1,7 @@ // use soa_derive::prelude::*; -// mod particles; -// use self::particles::Particle; +mod particles; +use self::particles::Particle; // fn may_iter<'a: 't, 't, T: SoATypes<'a, 't>>(vec: &'a T::Vec) -> T::Iter { // let x= vec.iter(); @@ -114,4 +114,4 @@ // assert_eq!(this.iter().count(), 3); // assert_eq!(this.view().len(), 3); -// } \ No newline at end of file +// } diff --git a/tests/nested_soa.rs b/tests/nested_soa.rs index 17253d9..ee976ae 100644 --- a/tests/nested_soa.rs +++ b/tests/nested_soa.rs @@ -59,7 +59,7 @@ fn nested_soa() { }); } -// fn generic_f<'a, 't, T: SoATypes<'a, 't>>(vec: &'a T::Vec) { +// fn generic_f<'a, T: SoATypes<'a>>(vec: &'a T::Vec<'a>) { // assert_eq!(vec.len(), 2); // } diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index b54bcc1..dda35d2 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -1,4 +1,5 @@ -use soa_derive::StructOfArray; +use soa_derive::{Permutation, SoATypes, StructOfArray}; +use soa_derive::{SoAIndex, SoAIndexMut, SoASliceMut, SoASlice, SoAVec}; #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] @@ -17,3 +18,414 @@ impl Particle { } +/* +impl<'a> SoASlice<'a, Particle> for ParticleSlice<'a> { + type Ref<'t> = ParticleRef<'t> where Self: 't, 'a: 't; + type Slice<'t> = ParticleSlice<'t> where Self: 't, 'a: 't; + type Iter<'t> = ParticleIter<'t> where Self: 't, 'a: 't; + type Ptr = ParticlePtr; +*/ + +// fn len(&self) -> usize { +// self.len() +// } + +// fn is_empty(&self) -> bool { +// self.is_empty() +// } + +// fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c { +// self.reborrow::<'c>() +// } + +// fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c { +// let start = match index.start_bound() { +// std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, +// std::ops::Bound::Unbounded => 0, +// }; +// let n = self.len(); +// let end = match index.end_bound() { +// std::ops::Bound::Included(i) => (*i + 1).min(n), +// std::ops::Bound::Excluded(i) => *i, +// std::ops::Bound::Unbounded => n, +// }; +// self.index(start..end) +// } + +// fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { +// self.get(index) +// } + +// fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { +// self.index(index) +// } + +// fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c { +// self.iter() +// } + +// fn as_ptr(&self) -> Self::Ptr { +// self.as_ptr() +// } +// } + +/* +impl<'a> SoASliceMut<'a, Particle> for ParticleSliceMut<'a> { + type Ref<'t> = ParticleRef<'t> where Self: 't, 'a: 't; + type Slice<'t> = ParticleSlice<'t> where Self: 't, 'a: 't; + type Iter<'t> = ParticleIter<'t> where Self: 't, 'a: 't; + type Ptr = ParticlePtr; + + type RefMut<'t> = ParticleRefMut<'t> where 'a: 't, Self: 't; + type SliceMut<'t> = ParticleSliceMut<'t> where 'a: 't, Self: 't; + type IterMut<'t> = ParticleIterMut<'t> where 'a: 't, Self: 't; + type PtrMut = ParticlePtrMut; + + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c { + self.as_slice() + } + + fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index(start..end) + } + + fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + self.get(index) + } + + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + self.index(index) + } + + fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c { + self.as_ref().into_iter() + } + + fn as_mut_slice<'c>(&'c mut self) -> Self::SliceMut<'c> where 'a: 'c { + self.reborrow() + } + + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> where 'a: 'c { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index_mut(start..end) + } + + fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { + self.get_mut(index) + } + + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { + self.index_mut(index) + } + + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> where 'a: 'c { + self.iter_mut() + } + + fn apply_index(&mut self, indices: &[usize]) { + self.apply_permutation(&mut Permutation::oneline(indices).inverse()); + } + + fn as_ptr(&self) -> Self::Ptr { + self.as_ptr() + } + + fn as_mut_ptr(&mut self) -> Self::PtrMut { + self.as_mut_ptr() + } +} + */ + +impl<'a> SoAVec<'a, Particle> for ParticleVec { + type Ref<'t> = ParticleRef<'t> where 'a: 't; + type Slice<'t> = ParticleSlice<'t> where Self: 'a, 'a: 't; + type Iter<'t> = ParticleIter<'t> where Self: 'a, 'a: 't; + type Ptr = ParticlePtr; + + type RefMut<'t> = ParticleRefMut<'t> where Self: 'a, 'a: 't; + type SliceMut<'t> = ParticleSliceMut<'t> where Self: 'a, 'a: 't; + type IterMut<'t> = ParticleIterMut<'t> where Self: 'a, 'a: 't; + type PtrMut = ParticlePtrMut; + + + + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c { + self.as_slice() + } + + fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index(start..end) + } + + fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + self.get(index) + } + + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + self.index(index) + } + + fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c { + self.iter() + } + + fn as_mut_slice<'c>(&'c mut self) -> Self::SliceMut<'c> where 'a: 'c { + self.as_mut_slice() + } + + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> where 'a: 'c { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index_mut(start..end) + } + + fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { + self.get_mut(index) + } + + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { + self.index_mut(index) + } + + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> where 'a: 'c { + self.iter_mut() + } + + fn apply_index(&mut self, indices: &[usize]) { + self.as_mut_slice().apply_index(indices); + } + + fn new() -> Self { + Self::new() + } + + fn with_capacity(capacity: usize) -> Self { + Self::with_capacity(capacity) + } + + fn capacity(&self) -> usize { + self.capacity() + } + + fn reserve(&mut self, additional: usize) { + self.reserve(additional); + } + + fn reserve_exact(&mut self, additional: usize) { + self.reserve_exact(additional); + } + + fn shrink_to_fit(&mut self) { + self.shrink_to_fit(); + } + + fn truncate(&mut self, len: usize) { + self.truncate(len); + } + + fn push(&mut self, value: Particle) { + self.push(value); + } + + fn swap_remove(&mut self, index: usize) -> Particle { + self.swap_remove(index) + } + + fn insert(&mut self, index: usize, element: Particle) { + self.insert(index, element); + } + + fn replace(&mut self, index: usize, element: Particle) -> Particle { + self.replace(index, element) + } + + fn remove(&mut self, index: usize) -> Particle { + self.remove(index) + } + + fn pop(&mut self) -> Option { + self.pop() + } + + fn append(&mut self, other: &mut Self) { + self.append(other); + } + + fn clear(&mut self) { + self.clear(); + } + + fn split_off(&mut self, at: usize) -> Self { + self.split_off(at) + } + + fn as_ptr(&self) -> Self::Ptr { + self.as_ptr() + } + + fn as_mut_ptr(&mut self) -> Self::PtrMut { + self.as_mut_ptr() + } +} + + + impl<'a> SoATypes<'a> for Particle { + type Ptr = ParticlePtr; + + type PtrMut = ParticlePtrMut; + + type Vec<'t> = ParticleVec where 'a: 't, Self: 'a; + + type Ref<'t> = ParticleRef<'t> where Self: 'a, 'a: 't; + + type Iter<'t> = ParticleIter<'t> where Self: 'a, 'a: 't; + + type Slice<'t> = ParticleSlice<'t> where Self: 'a, 'a: 't; + + type RefMut<'t> = ParticleRefMut<'t> where Self: 'a, 'a: 't; + + type SliceMut<'t> = ParticleSliceMut<'t> where Self: 'a, 'a: 't; + + type IterMut<'t> = ParticleIterMut<'t> where Self: 'a, 'a: 't; +} + +fn order_concrete<'a>(vec: &mut ParticleVec) { + let mut indices: Vec<_> = (0..vec.len()).collect(); + indices.sort_by(|j, k| { + let a = vec.index(*j); + let b = vec.index(*k); + a.partial_cmp(&b).unwrap() + }); +} + +fn order_generic<'a, T: StructOfArray, V: SoASlice<'a, T> + 'a>(vec: &'a V) where V::Ref<'a>: PartialOrd { + let mut indices: Vec<_> = (0..vec.len()).collect(); + indices.sort_by(|j, k| { + let a = vec.index(*j); + let b = vec.index(*k); + a.partial_cmp(&b).unwrap() + }); +} + +fn iter_max_generic<'a, T: StructOfArray, V: SoASlice<'a, T> + 'a>(vec: &'a V) -> Option> where V::Ref<'a>: PartialOrd { + let x= vec.iter().reduce(|a, b| { + if a.partial_cmp(&b).unwrap().is_ge() { + a + } else { + b + } + }); + x +} + +fn iter_max_generic_iter<'a, T: SoATypes<'a>>(it: T::Iter<'a>) -> Option> where T::Ref<'a>: PartialOrd { + it.reduce(|a: T::Ref<'_>, b: T::Ref<'_>| { + if a.partial_cmp(&b).unwrap().is_ge() { + a + } else { + b + } + }) +} + +fn iter_max_generic_slice<'a, V: StructOfArray, T: SoAVec<'a, V>>(vec: &'a mut T) -> Option> where T::Ref<'a>: PartialOrd { + let mut indices: Vec<_> = (0..vec.len()).collect(); + indices.sort_by(|j, k| { + let a = vec.index(*j); + let b = vec.index(*k); + a.partial_cmp(&b).unwrap() + }); + let i = indices.iter().position(|x| *x == 0).unwrap(); + vec.get(i) +} + +fn iter_max_concrete<'a>(vec: &'a mut ParticleVec) -> Option<>::Ref<'a>> { + let mut indices: Vec<_> = (0..vec.len()).collect(); + indices.sort_by(|j, k| { + let a = >::index(&vec, *j); + let b = >::index(&vec, *k); + a.partial_cmp(&b).unwrap() + }); + let i = indices.iter().position(|x| *x == 0).unwrap(); + vec.get(i) +} + +fn sort_generic<'a: 't, 't: 'c, 'c, T: StructOfArray, V: SoAVec<'t, T>>(vec: &'a mut V) where V::Ref<'t>: PartialOrd { + let mut indices: Vec<_> = (0..vec.len()).collect(); + indices.sort_by(|j, k| { + let a: V::Ref<'c> = vec.index::<'c>(*j); + let b: V::Ref<'_> = vec.index(*k); + let r = a.partial_cmp(&b).unwrap(); + r + }); +} + +#[test] +fn test_ops() { + let mut vec = ParticleVec::new(); + vec.push(Particle::new("foo".into(), 100.0)); + vec.push(Particle::new("bar".into(), 1000.0)); + vec.push(Particle::new("baz".into(), 50.0)); + let view = vec.as_slice(); + let x = iter_max_generic(&view); + eprintln!("{x:?}"); + let y = iter_max_generic_iter::(vec.iter()); + eprintln!("{y:?}"); + let y = iter_max_generic_iter::(view.iter()); + eprintln!("{y:?}"); + let y = iter_max_generic_slice::(&view); + eprintln!("{y:?}"); +} \ No newline at end of file From 3c210491f99565ceb0151aa7c29642efe9ccc335 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Thu, 16 Jan 2025 10:57:24 -0500 Subject: [PATCH 11/37] unbundle traits --- soa-derive-internal/src/lib.rs | 22 --- soa-derive-internal/src/slice.rs | 50 +++-- soa-derive-internal/src/vec.rs | 46 +++-- src/lib.rs | 312 +++++++++---------------------- tests/generic.rs | 218 ++++++++++----------- tests/particles/mod.rs | 297 ++++++++++++++--------------- 6 files changed, 386 insertions(+), 559 deletions(-) diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index f6c2ecb..75724a9 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -55,27 +55,5 @@ fn derive_trait(input: &Input) -> TokenStream { impl soa_derive::StructOfArray for #name { type Type = #vec_name; } - - /* - impl<'a> ::soa_derive::SoATypes<'a> for #name { - type Ptr = #ptr_name; - - type PtrMut = #ptr_mut_name; - - type Vec<'t> = #vec_name where 'a: 't, Self: 'a; - - type Ref<'t> = #ref_name<'t> where Self: 't, Self: 'a, 'a: 't; - - type Iter<'t> = <#vec_name as ::soa_derive::SoAVec<'a, Self>>::Iter<'t> where >::Vec<'t>: 't, Self: 'a, 'a: 't; - - type Slice<'t> = #slice_name<'t> where Self: 'a, Self::Vec<'t>: 't, 'a: 't; - - type RefMut<'t> = #ref_mut_name<'t> where Self: 't, Self: 'a, 'a: 't; - - type SliceMut<'t> = #slice_mut_name<'t> where Self: 'a, Self::Vec<'t>: 't, 'a: 't; - - type IterMut<'t> = <#vec_name as ::soa_derive::SoAVec<'a, Self>>::IterMut<'t> where >::Vec<'t>: 't, Self: 'a, 'a: 't; - } - */ } } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index 1af9467..6d72569 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -238,7 +238,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoASlice<'a, #name> for #slice_name<'a> { + impl<'a> ::soa_derive::SoASlice<#name> for #slice_name<'a> { type Ref<'t> = #ref_name<'t> where Self: 't, 'a: 't; type Slice<'t> = #slice_name<'t> where Self: 't, 'a: 't; type Iter<'t> = #iter_name<'t> where Self: 't, 'a: 't; @@ -252,11 +252,11 @@ pub fn derive(input: &Input) -> TokenStream { self.is_empty() } - fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c { + fn as_slice<'c>(&'c self) -> Self::Slice<'c> { self.reborrow::<'c>() } - fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c { + fn slice<'c, 'b: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'b { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, @@ -270,15 +270,15 @@ pub fn derive(input: &Input) -> TokenStream { self.index(start..end) } - fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + fn get<'c>(&'c self, index: usize) -> Option> { self.get(index) } - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { self.index(index) } - fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c { + fn iter<'c>(&'c self) -> Self::Iter<'c> { self.iter() } @@ -286,7 +286,6 @@ pub fn derive(input: &Input) -> TokenStream { self.as_ptr() } } - }; if input.attrs.derive_clone { @@ -718,15 +717,15 @@ pub fn derive_mut(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoASliceMut<'a, #name> for #slice_mut_name<'a> { - type Ref<'t> = #ref_name<'t> where Self: 't, 'a: 't; - type Slice<'t> = #slice_name<'t> where Self: 't, 'a: 't; - type Iter<'t> = #iter_name<'t> where Self: 't, 'a: 't; + impl<'a> ::soa_derive::SoASliceMut<#name> for #slice_mut_name<'a> { + type Ref<'t> = #ref_name<'t> where Self: 't; + type Slice<'t> = #slice_name<'t> where Self: 't; + type Iter<'t> = #iter_name<'t> where Self: 't; type Ptr = #ptr_name; - type RefMut<'t> = #ref_mut_name<'t> where 'a: 't, Self: 't; - type SliceMut<'t> = #slice_mut_name<'t> where 'a: 't, Self: 't; - type IterMut<'t> = #iter_mut_name<'t> where 'a: 't, Self: 't; + type RefMut<'t> = #ref_mut_name<'t> where Self: 't; + type SliceMut<'t> = #slice_mut_name<'t> where Self: 't; + type IterMut<'t> = #iter_mut_name<'t> where Self: 't; type PtrMut = #ptr_mut_name; fn len(&self) -> usize { @@ -737,11 +736,11 @@ pub fn derive_mut(input: &Input) -> TokenStream { self.is_empty() } - fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c { + fn as_slice<'c>(&'c self) -> Self::Slice<'c> { self.as_slice() } - fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c { + fn slice<'c, 'b: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'b { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, @@ -755,23 +754,23 @@ pub fn derive_mut(input: &Input) -> TokenStream { self.index(start..end) } - fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + fn get<'c>(&'c self, index: usize) -> Option> { self.get(index) } - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { self.index(index) } - fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c { + fn iter<'c>(&'c self) -> Self::Iter<'c> { self.as_ref().into_iter() } - fn as_mut_slice<'c>(&'c mut self) -> Self::SliceMut<'c> where 'a: 'c { + fn as_mut_slice<'c: 'b, 'b>(&'c mut self) -> Self::SliceMut<'c> where Self: 'b { self.reborrow() } - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> where 'a: 'c { + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, @@ -785,15 +784,15 @@ pub fn derive_mut(input: &Input) -> TokenStream { self.index_mut(start..end) } - fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { + fn get_mut<'c>(&'c mut self, index: usize) -> Option> { self.get_mut(index) } - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> { self.index_mut(index) } - fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> where 'a: 'c { + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> { self.iter_mut() } @@ -808,8 +807,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { fn as_mut_ptr(&mut self) -> Self::PtrMut { self.as_mut_ptr() } - } - +} }; if input.attrs.derive_clone { diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index e49d30e..0fe727e 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -450,19 +450,17 @@ pub fn derive(input: &Input) -> TokenStream { } } -/* - impl<'a> ::soa_derive::SoAVec<'a, #name> for #vec_name { - type Ref<'t> = #ref_name<'t> where Self: 't, 'a: 't; - type Slice<'t> = #slice_name<'t> where Self: 't, 'a: 't; - type Iter<'t> = #iter_name<'t> where Self: 't, 'a: 't; + impl ::soa_derive::SoAVec<#name> for #vec_name { + type Ref<'t> = #ref_name<'t>; + type Slice<'t> = #slice_name<'t>; + type Iter<'t> = #iter_name<'t>; type Ptr = #ptr_name; - type RefMut<'t> = #ref_mut_name<'t> where Self: 't, 'a: 't; - type SliceMut<'t> = #slice_mut_name<'t> where Self: 't, 'a: 't; - type IterMut<'t> = #iter_mut_name<'t> where Self: 't, 'a: 't; + type RefMut<'t> = #ref_mut_name<'t>; + type SliceMut<'t> = #slice_mut_name<'t>; + type IterMut<'t> = #iter_mut_name<'t>; type PtrMut = #ptr_mut_name; - fn len(&self) -> usize { self.len() } @@ -471,11 +469,11 @@ pub fn derive(input: &Input) -> TokenStream { self.is_empty() } - fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c { + fn as_slice<'c, 'a: 'c>(&'c self) -> Self::Slice<'c> where Self: 'a { self.as_slice() } - fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c { + fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, @@ -489,23 +487,23 @@ pub fn derive(input: &Input) -> TokenStream { self.index(start..end) } - fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { - ::soa_derive::SoAIndex::get(index, self) + fn get<'c>(&'c self, index: usize) -> Option> { + self.get(index) } - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { - ::soa_derive::SoAIndex::index(index, self) + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { + self.index(index) } - fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c { + fn iter<'c>(&'c self) -> Self::Iter<'c> { self.iter() } - fn as_mut_slice<'c>(&'c mut self) -> Self::SliceMut<'c> where 'a: 'c { + fn as_mut_slice<'c, 'a: 'c>(&'c mut self) -> Self::SliceMut<'c> where Self: 'a { self.as_mut_slice() } - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> where 'a: 'c { + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, @@ -519,21 +517,21 @@ pub fn derive(input: &Input) -> TokenStream { self.index_mut(start..end) } - fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { + fn get_mut<'c>(&'c mut self, index: usize) -> Option> { self.get_mut(index) } - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> { self.index_mut(index) } - fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> where 'a: 'c { + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> { self.iter_mut() } fn apply_index(&mut self, indices: &[usize]) { - let mut view = self.as_mut_slice(); - ::soa_derive::SoASliceMut::apply_index(&mut view, indices); + use ::soa_derive::SoASliceMut; + self.as_mut_slice().apply_index(indices); } fn new() -> Self { @@ -608,7 +606,7 @@ pub fn derive(input: &Input) -> TokenStream { self.as_mut_ptr() } } -*/ + #[allow(clippy::drop_non_drop)] impl Drop for #vec_name { fn drop(&mut self) { diff --git a/src/lib.rs b/src/lib.rs index 5ef81c2..4aec469 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -242,7 +242,7 @@ pub use permutation::permutation::*; /// `CheeseVec`; This will helpful in generics programing that generate struct /// can be expressed as `::Type` pub trait StructOfArray { - type Type; + type Type: SoAVec where Self: Sized; } /// Any struct derived by StructOfArray will auto impl this trait. @@ -391,44 +391,39 @@ pub trait SoAPointers { type MutPtr; } -pub trait SoAProps<'a> : StructOfArray + SoAIter<'a> + SoAPointers {} - -impl<'a, T> SoAProps<'a> for T where T: StructOfArray + SoAIter<'a> + SoAPointers {} - - /** - * The interface for the `Slice` immutable slice struct-of-arrays type. +The interface for the `Slice` immutable slice struct-of-arrays type. */ -pub trait SoASlice<'a, T> { - type Ref<'t> where Self: 'a, 'a: 't; - type Slice<'t>: SoASlice<'t, T> where Self: 't, 'a: 't; - type Iter<'t>: Iterator> where Self: 'a, 'a: 't; +pub trait SoASlice { + type Ref<'t> where Self: 't; + type Slice<'t>: SoASlice where Self: 't; + type Iter<'t>: Iterator> where Self: 't; type Ptr; fn len(&self) -> usize; fn is_empty(&self) -> bool; - fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c; + fn as_slice<'c>(&'c self) -> Self::Slice<'c>; /// Create a slice of this vector matching the given `range`. This /// is analogous to `Index>`. - fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c; + fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a; /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) - fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c; + fn get<'c>(&'c self, index: usize) -> Option>; /// Analogous to [`std::ops::Index::index()`] for `usize` - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c; + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c>; /// Create an immutable iterator - fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c; + fn iter<'c>(&'c self) -> Self::Iter<'c>; /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) - fn first<'c>(&'c self) -> Option> where 'a: 'c { + fn first<'c>(&'c self) -> Option> { self.get(0) } /// Analogous to [`slice::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last) - fn last<'c>(&'c self) -> Option> where 'a: 'c { + fn last<'c>(&'c self) -> Option> { self.get(self.len().saturating_sub(1)) } @@ -437,44 +432,44 @@ pub trait SoASlice<'a, T> { } /** - * The interface for the `SliceMut` mutable slice struct-of-arrays type. A generalization of [`SoASlice`] - * whose methods can modify elements of the arrays +The interface for the `SliceMut` mutable slice struct-of-arrays type. A generalization of [`SoASlice`] +whose methods can modify elements of the arrays */ -pub trait SoASliceMut<'a, T: StructOfArray> { - type Ref<'t> where Self: 'a, 'a: 't; - type Slice<'t>: SoASlice<'t, T> where Self: 't, 'a: 't; - type Iter<'t>: Iterator> where Self: 'a, 'a: 't; +pub trait SoASliceMut { + type Ref<'t> where Self: 't; + type Slice<'t>: SoASlice where Self: 't; + type Iter<'t>: Iterator> where Self: 't; type Ptr; - type RefMut<'t> where 'a: 't, Self: 't; - type SliceMut<'t>: SoASliceMut<'t, T> where 'a: 't, Self: 't; - type IterMut<'t>: Iterator> where 'a: 't, Self: 't; + type RefMut<'t> where Self: 't; + type SliceMut<'t>: SoASliceMut where Self: 't; + type IterMut<'t>: Iterator> where Self: 't; type PtrMut; fn len(&self) -> usize; fn is_empty(&self) -> bool; - fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c; + fn as_slice<'c>(&'c self) -> Self::Slice<'c>; /// Create a slice of this vector matching the given `range`. This /// is analogous to `Index>`. - fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c; + fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a; /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) - fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c; + fn get<'c>(&'c self, index: usize) -> Option>; /// Analogous to [`std::ops::Index::index()`] for `usize` - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c; + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c>; /// Create an immutable iterator - fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c; + fn iter<'c>(&'c self) -> Self::Iter<'c>; /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) - fn first<'c>(&'c self) -> Option> where 'a: 'c { + fn first<'c>(&'c self) -> Option> { self.get(0) } /// Analogous to [`slice::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last) - fn last<'c>(&'c self) -> Option> where 'a: 'c { + fn last<'c>(&'c self) -> Option> { self.get(self.len().saturating_sub(1)) } @@ -482,58 +477,50 @@ pub trait SoASliceMut<'a, T: StructOfArray> { fn as_ptr(&self) -> Self::Ptr; /// Analogous to [`Vec::as_mut_slice()`] - fn as_mut_slice<'c>(&'c mut self) -> Self::SliceMut<'c> where 'a: 'c; + fn as_mut_slice<'c: 'b, 'b>(&'c mut self) -> Self::SliceMut<'c> where Self: 'b; /// Create a mutable slice of this vector matching the given /// `range`. This is analogous to `IndexMut>`. - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> where 'a: 'c; + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c>; /// Analogous to [`slice::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut) - fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c; + fn get_mut<'c>(&'c mut self, index: usize) -> Option>; /// Analogous to [`std::ops::IndexMut::index_mut()`] for `usize` - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c; + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c>; /// Creates a mutable iterator - fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> where 'a: 'c; + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c>; /** Re-order the arrays using the provided indices. This is provided so that generic sorting methods can be implemented because closure-passing trait methods encounter difficulties with lifetimes. + */ + fn apply_index(&mut self, indices: &[usize]); - # Example + fn sort_by(&mut self, mut f: F) where F: FnMut(Self::Ref<'_>, Self::Ref<'_>) -> std::cmp::Ordering { + let mut permutation: Vec = (0..self.len()).collect(); + permutation.sort_by(|j, k| f(self.index(*j), self.index(*k))); - ``` - use soa_derive::{StructOfArray, prelude::*}; + self.apply_index(&permutation); + } + + fn sort_by_key(&mut self, mut f: F) where + F: FnMut(Self::Ref<'_>) -> K, + K: Ord, + { + let mut permutation: Vec = (0..self.len()).collect(); + permutation.sort_by_key(|j| f(self.index(*j))); - #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] - #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] - pub struct Particle { - pub name: String, - pub mass: f64, + self.apply_index(&permutation); } - # fn may_sort<'a>(vec: &mut >::Vec) { - // vec: &mut >::Vec - let mut indices: Vec<_> = (0..vec.len()).collect(); - - indices.sort_by(|j, k| { - let a = vec.index(*j); - let b = vec.index(*k); - a.mass.total_cmp(b.mass).reverse() - }); - - vec.apply_index(&indices); - # } - ``` - */ - fn apply_index(&mut self, indices: &[usize]); /// Analogous to [`slice::first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut) - fn first_mut<'c>(&'c mut self) -> Option> where 'a: 'c { + fn first_mut<'c>(&'c mut self) -> Option> { self.get_mut(0) } /// Analogous to [`slice::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut) - fn last_mut<'c>(&'c mut self) -> Option> where 'a: 'c { + fn last_mut<'c>(&'c mut self) -> Option> { self.get_mut(self.len().saturating_sub(1)) } @@ -547,41 +534,41 @@ pub trait SoASliceMut<'a, T: StructOfArray> { * * **NOTE**: This interface is incomplete and additional methods may be added as needed. */ -pub trait SoAVec<'a, T: StructOfArray>: 'a { - type Ref<'t> where 'a: 't; - type Slice<'t>: SoASlice<'t, T> where Self: 'a, 'a: 't; - type Iter<'t>: Iterator> where 'a: 't; +pub trait SoAVec { + type Ref<'t> where Self: 't; + type Slice<'t>: SoASlice where Self:'t; + type Iter<'t>: Iterator> where Self: 't; type Ptr; - type RefMut<'t> where Self: 'a, 'a: 't; - type SliceMut<'t>: SoASliceMut<'t, T> where Self: 'a, 'a: 't; - type IterMut<'t>: Iterator> where Self: 'a, 'a: 't; + type RefMut<'t> where Self: 't; + type SliceMut<'t>: SoASliceMut where Self: 't; + type IterMut<'t>: Iterator> where Self: 't; type PtrMut; fn len(&self) -> usize; fn is_empty(&self) -> bool; - fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c; + fn as_slice<'c, 'a: 'c>(&'c self) -> Self::Slice<'c> where Self: 'a; /// Create a slice of this vector matching the given `range`. This /// is analogous to `Index>`. - fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c; + fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a; /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) - fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c; + fn get<'c>(&'c self, index: usize) -> Option>; /// Analogous to [`std::ops::Index::index()`] for `usize` - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c; + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c>; /// Create an immutable iterator - fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c; + fn iter<'c>(&'c self) -> Self::Iter<'c>; /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) - fn first<'c>(&'c self) -> Option> where 'a: 'c { + fn first<'c>(&'c self) -> Option> { self.get(0) } /// Analogous to [`slice::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last) - fn last<'c>(&'c self) -> Option> where 'a: 'c { + fn last<'c>(&'c self) -> Option> { self.get(self.len().saturating_sub(1)) } @@ -589,50 +576,42 @@ pub trait SoAVec<'a, T: StructOfArray>: 'a { fn as_ptr(&self) -> Self::Ptr; /// Analogous to [`Vec::as_mut_slice()`] - fn as_mut_slice<'c>(&'c mut self) -> Self::SliceMut<'c> where 'a: 'c; + fn as_mut_slice<'c, 'a: 'c>(&'c mut self) -> Self::SliceMut<'c> where Self: 'a; /// Create a mutable slice of this vector matching the given /// `range`. This is analogous to `IndexMut>`. - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> where 'a: 'c; + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c>; /// Analogous to [`slice::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut) - fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c; + fn get_mut<'c>(&'c mut self, index: usize) -> Option>; /// Analogous to [`std::ops::IndexMut::index_mut()`] for `usize` - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c; + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c>; /// Creates a mutable iterator - fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> where 'a: 'c; + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c>; /** Re-order the arrays using the provided indices. This is provided so that generic sorting methods can be implemented because closure-passing trait methods encounter difficulties with lifetimes. + */ + fn apply_index(&mut self, indices: &[usize]); - # Example + fn sort_by(&mut self, mut f: F) where F: FnMut(Self::Ref<'_>, Self::Ref<'_>) -> std::cmp::Ordering { + let mut permutation: Vec = (0..self.len()).collect(); + permutation.sort_by(|j, k| f(self.index(*j), self.index(*k))); - ``` - use soa_derive::{StructOfArray, prelude::*}; + self.apply_index(&permutation); + } + + fn sort_by_key(&mut self, mut f: F) where + F: FnMut(Self::Ref<'_>) -> K, + K: Ord, + { + let mut permutation: Vec = (0..self.len()).collect(); + permutation.sort_by_key(|j| f(self.index(*j))); - #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] - #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] - pub struct Particle { - pub name: String, - pub mass: f64, + self.apply_index(&permutation); } - # fn may_sort<'a>(vec: &mut >::Vec) { - // vec: &mut >::Vec - let mut indices: Vec<_> = (0..vec.len()).collect(); - - indices.sort_by(|j, k| { - let a = vec.index(*j); - let b = vec.index(*k); - a.mass.total_cmp(b.mass).reverse() - }); - - vec.apply_index(&indices); - # } - ``` - */ - fn apply_index(&mut self, indices: &[usize]); /// Analogous to [`slice::first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut) fn first_mut<'c>(&'c mut self) -> Option> { @@ -696,129 +675,10 @@ pub trait SoAVec<'a, T: StructOfArray>: 'a { fn split_off(&mut self, at: usize) -> Self; } - pub trait SoATypes<'a>: StructOfArray + Sized { - type Ref<'t> where Self: 't, Self: 'a, 'a: 't; - type RefMut<'t> where Self: 't, Self: 'a, 'a: 't; - - type Ptr; - type PtrMut; - - type Iter<'t>: Iterator> where Self: 'a, 'a: 't; - type Slice<'t>: SoASlice< - 't, - Self, - Ref<'t> = Self::Ref<'t>, - Iter<'t> = Self::Iter<'t>, - Ptr = Self::Ptr, - > where Self: 'a, 'a: 't; - - type SliceMut<'t>: SoASliceMut< - 't, - Self, - Ref<'t> = Self::Ref<'t>, - Iter<'t> = Self::Iter<'t>, - RefMut<'t> = Self::RefMut<'t>, - IterMut<'t> = Self::IterMut<'t>, - Ptr = Self::Ptr, - PtrMut = Self::PtrMut, - > where Self: 'a, 'a: 't; - type IterMut<'t>: Iterator> where Self: 'a, 'a: 't; - - type Vec<'t>: SoAVec<'a, - Self, - Ref<'a> = Self::Ref<'a>, - RefMut<'a> = Self::RefMut<'a>, - Ptr = Self::Ptr, - PtrMut = Self::PtrMut, - Slice<'a> = Self::Slice<'a> - > where 'a: 't, Self: 'a; -} - -/** A collection of types that represent the different facets of a [`StructOfArray`] type. - - It is a convenience type that can be used as a trait bound, but because it introduces - a lifetime, it is not folded directly into [`StructOfArray`] itself. It also ensures - that the associated types interlock between all facets. - - # Example - - Suppose one has a generic type that needs to be generic *over* [`StructOfArray`] - types. This trait is a convenient means of claiming all the appropriate behaviors - are available in one place: - ``` -use soa_derive::prelude::*; -#[derive(Debug, Clone)] -struct Swarm<'a: 't, 't, T: SoATypes<'a, 't> + 'a> { - entries: T::Vec, -} - -impl<'a: 't, 't, T: SoATypes<'a, 't> + 'a> Swarm<'a, 't, T> { - fn new() -> Self { - Self { - entries: T::Vec::new() - } - } - - fn push(&mut self, value: T) { - self.entries.push(value); - } - - fn iter(&'a self) -> T::Iter { - self.entries.iter() - } -} - ``` - - Without this, the generic type wouldn't be able to access any methods of `self.entries` because - the associate type provided by [`StructOfArray`] has *no* bounds, which means it proves no methods - are available. -*/ -// pub trait SoATypes<'a: 't, 't>: SoAProps<'a> + Sized { -// /// The [`Vec`]-like type -// type Vec: SoAVec<'a, Self> + 'a where Self: 'a; -// /// The immutable `&[Self]`-like type -// type Slice: SoASlice< -// 'a, -// Self, -// Ref<'t> = < -// >::Vec -// as SoASlice<'a, Self> -// >::Ref<'t>, -// Reborrow<'t> = < -// >::Vec -// as SoASlice<'a, Self> -// >::Reborrow<'t> -// > + 'a where Self: 'a; -// /// The mutable `&[Self]`-like type -// type SliceMut: SoAMutSlice< -// 'a, Self, -// Ref<'t> = < -// >::Vec -// as SoASlice<'a, Self> -// >::Ref<'t>, -// Reborrow<'t> = < -// >::Vec -// as SoASlice<'a, Self> -// >::Reborrow<'t>, - -// RefMut<'t> = < -// >::Vec -// as SoAMutSlice<'a, Self> -// >::RefMut<'t>, -// ReborrowMut<'t> = < -// >::Vec -// as SoAMutSlice<'a, Self> -// >::ReborrowMut<'t>, -// > + 'a where Self: 'a; - -// type Ref: 't; -// type RefMut: 't; - -// } /// A collection of supporting traits for [`StructOfArray`] bundled in one place for ease-of-access pub mod prelude { - pub use super::{SoAVec, SoAIter, SoAProps, SoASlice, SoASliceMut, SoAPointers, SoATypes, StructOfArray}; + pub use super::{SoAVec, SoAIter, SoASlice, SoASliceMut, SoAPointers, StructOfArray}; } diff --git a/tests/generic.rs b/tests/generic.rs index cef0a38..b1fada4 100644 --- a/tests/generic.rs +++ b/tests/generic.rs @@ -1,117 +1,117 @@ // use soa_derive::prelude::*; mod particles; -use self::particles::Particle; - -// fn may_iter<'a: 't, 't, T: SoATypes<'a, 't>>(vec: &'a T::Vec) -> T::Iter { -// let x= vec.iter(); -// x -// } - -// fn may_push<'a: 't, 't, T: SoATypes<'a, 't>>(vec: &'a mut T::Vec, val: T) { -// vec.push(val); -// } - -// fn may_sort<'a: 't, 't>(vec: &mut >::Vec) { -// let mut indices: Vec<_> = (0..vec.len()).collect(); - -// indices.sort_by(|j, k| { -// let a = vec.index(*j); -// let b = vec.index(*k); -// a.mass.total_cmp(b.mass).reverse() -// }); - -// vec.apply_index(&indices); -// } - - -// fn may_sort_generic<'a: 't, 't: 'c, 'c, T: SoATypes<'a, 't>>(vec: &'c mut >::Vec) where <>::Vec as SoASlice<'a, T>>::Ref<'t> : PartialOrd { -// let mut indices: Vec<_> = (0..vec.len()).collect(); - -// indices.sort_by(|j, k| { - -// let a: <>::Vec as SoASlice<'a, T>>::Ref<'_> = vec.index(*j); -// let b: <>::Vec as SoASlice<'a, T>>::Ref<'_> = vec.index(*k); -// a.partial_cmp(&b).unwrap() -// }); - -// } - - -// fn may_closure_sort<'a: 't, 't, F>(vec: &mut >::Vec, mut f: F) where F: FnMut(::Ref, ::Ref) -> std::cmp::Ordering { -// let mut indices: Vec<_> = (0..vec.len()).collect(); +use std::marker::PhantomData; -// indices.sort_by(|j, k| { -// let a = vec.index(*j); -// let b = vec.index(*k); -// f(a, b) -// }); +use particles::ParticleVec; +use soa_derive::{SoAVec, StructOfArray}; -// vec.apply_index(&indices); -// } - - -// #[test] -// fn test_generic_type_behavior() { -// let mut x = ::Vec::new(); -// x.push(Particle::new("foo".into(), 100.0)); -// let y: Vec<_> = may_iter::(&x).collect(); -// assert_eq!(x.len(), y.len()); -// assert_eq!(x.get(0).as_ref(), y.get(0)); -// drop(y); - -// let z = Particle::new("bar".into(), 1000.0); -// may_push(&mut x, z); -// assert_eq!(x.len(), 2); -// may_sort(&mut x); -// let a = x.index(0); -// let b = x.index(1); -// assert!(a.mass > b.mass); - -// may_closure_sort(&mut x, |a, b| a.mass.total_cmp(&b.mass)); - -// let a = x.index(0); -// let b = x.index(1); -// assert!(a.mass < b.mass); -// } - - -// #[derive(Debug, Clone)] -// struct Swarm<'a: 't, 't, T: soa_derive::SoATypes<'a, 't> + 'a> { -// entries: T::Vec, -// } - -// impl<'a: 't, 't, T: soa_derive::SoATypes<'a, 't>> Swarm<'a, 't, T> { -// fn new() -> Self { -// Self { -// entries: T::Vec::new() -// } -// } - -// fn push(&mut self, value: T) { -// self.entries.push(value); -// } - -// fn iter(&'a self) -> T::Iter { -// self.entries.iter() -// } - -// fn view(&'a self) -> <>::Vec as SoASlice<'a, T>>::Reborrow<'a> { -// self.entries.as_slice() -// } -// } +use self::particles::Particle; -// #[test] -// fn test_wrapped() { -// let mut this: Swarm<'_, '_, Particle> = Swarm::new(); -// let x= Particle::new("foo".into(), 100.0); -// this.push(x); -// let x = Particle::new("bar".into(), 1000.0); -// this.push(x); -// let x = Particle::new("baz".into(), 10.0); -// this.push(x); +fn may_iter>(vec: &V) -> V::Iter<'_> { + let x= vec.iter(); + x +} -// assert_eq!(this.iter().count(), 3); +fn may_push>(vec: &mut V, val: T) { + vec.push(val); +} + +fn may_sort_generic>(vec: &mut V) where for<'t> V::Ref<'t> : PartialOrd { + let mut indices: Vec<_> = (0..vec.len()).collect(); + + indices.sort_by(|j, k| { + + let a = vec.index(*j); + let b = vec.index(*k); + a.partial_cmp(&b).unwrap() + }); + + vec.apply_index(&indices); +} + + +fn may_closure_sort, F>(vec: &mut V, mut f: F) where F: FnMut(V::Ref<'_>, V::Ref<'_>) -> std::cmp::Ordering { + let mut indices: Vec<_> = (0..vec.len()).collect(); + + indices.sort_by(|j, k| { + let a = vec.index(*j); + let b = vec.index(*k); + f(a, b) + }); + + vec.apply_index(&indices); +} + + +#[test] +fn test_generic_type_behavior() { + let mut x = ParticleVec::new(); + x.push(Particle::new("foo".into(), 100.0)); + let y: Vec<_> = may_iter::(&x).collect(); + assert_eq!(x.len(), y.len()); + assert_eq!(x.get(0).as_ref(), y.get(0)); + drop(y); + + let z = Particle::new("bar".into(), 1000.0); + may_push(&mut x, z); + assert_eq!(x.len(), 2); + + may_sort_generic(&mut x); + assert_eq!(x.first().unwrap().name, "bar"); + + x.sort_by(|a, b| a.mass.total_cmp(&b.mass).reverse()); + // may_sort(&mut x); + let a = x.index(0); + let b = x.index(1); + assert!(a.mass > b.mass); + + may_closure_sort(&mut x, |a, b| a.mass.total_cmp(&b.mass)); + + let a = x.index(0); + let b = x.index(1); + assert!(a.mass < b.mass); +} + + +#[derive(Debug, Clone)] +struct Swarm> { + entries: V, + _t: PhantomData +} + +impl> Swarm { + fn new() -> Self { + Self { + entries: V::new(), + _t: PhantomData + } + } + + fn push(&mut self, value: T) { + self.entries.push(value); + } + + fn iter(&self) -> V::Iter<'_> { + self.entries.iter() + } + + fn view(&self) -> V::Slice<'_> { + self.entries.as_slice() + } +} + +#[test] +fn test_wrapped() { + let mut this: Swarm = Swarm::new(); + let x= Particle::new("foo".into(), 100.0); + this.push(x); + let x = Particle::new("bar".into(), 1000.0); + this.push(x); + let x = Particle::new("baz".into(), 10.0); + this.push(x); + + assert_eq!(this.iter().count(), 3); -// assert_eq!(this.view().len(), 3); -// } + assert_eq!(this.view().len(), 3); +} diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index dda35d2..1e25f1b 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -1,5 +1,8 @@ -use soa_derive::{Permutation, SoATypes, StructOfArray}; -use soa_derive::{SoAIndex, SoAIndexMut, SoASliceMut, SoASlice, SoAVec}; +use std::cmp::Ordering; +use std::fmt::Debug; +use std::marker::PhantomData; + +use soa_derive::prelude::*; #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] @@ -17,68 +20,67 @@ impl Particle { } } - /* -impl<'a> SoASlice<'a, Particle> for ParticleSlice<'a> { +impl<'a> SoASlice for ParticleSlice<'a> { type Ref<'t> = ParticleRef<'t> where Self: 't, 'a: 't; type Slice<'t> = ParticleSlice<'t> where Self: 't, 'a: 't; type Iter<'t> = ParticleIter<'t> where Self: 't, 'a: 't; type Ptr = ParticlePtr; -*/ -// fn len(&self) -> usize { -// self.len() -// } - -// fn is_empty(&self) -> bool { -// self.is_empty() -// } - -// fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c { -// self.reborrow::<'c>() -// } - -// fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c { -// let start = match index.start_bound() { -// std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, -// std::ops::Bound::Unbounded => 0, -// }; -// let n = self.len(); -// let end = match index.end_bound() { -// std::ops::Bound::Included(i) => (*i + 1).min(n), -// std::ops::Bound::Excluded(i) => *i, -// std::ops::Bound::Unbounded => n, -// }; -// self.index(start..end) -// } - -// fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { -// self.get(index) -// } - -// fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { -// self.index(index) -// } - -// fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c { -// self.iter() -// } - -// fn as_ptr(&self) -> Self::Ptr { -// self.as_ptr() -// } -// } + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn as_slice<'c>(&'c self) -> Self::Slice<'c> { + self.reborrow::<'c>() + } + + fn slice<'c, 'b: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'b { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index(start..end) + } + + fn get<'c>(&'c self, index: usize) -> Option> { + self.get(index) + } + + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { + self.index(index) + } + + fn iter<'c>(&'c self) -> Self::Iter<'c> { + self.iter() + } + + fn as_ptr(&self) -> Self::Ptr { + self.as_ptr() + } +} +*/ /* -impl<'a> SoASliceMut<'a, Particle> for ParticleSliceMut<'a> { - type Ref<'t> = ParticleRef<'t> where Self: 't, 'a: 't; - type Slice<'t> = ParticleSlice<'t> where Self: 't, 'a: 't; - type Iter<'t> = ParticleIter<'t> where Self: 't, 'a: 't; +impl<'a> SoASliceMut for ParticleSliceMut<'a> { + type Ref<'t> = ParticleRef<'t> where Self: 't; + type Slice<'t> = ParticleSlice<'t> where Self: 't; + type Iter<'t> = ParticleIter<'t> where Self: 't; type Ptr = ParticlePtr; - type RefMut<'t> = ParticleRefMut<'t> where 'a: 't, Self: 't; - type SliceMut<'t> = ParticleSliceMut<'t> where 'a: 't, Self: 't; - type IterMut<'t> = ParticleIterMut<'t> where 'a: 't, Self: 't; + type RefMut<'t> = ParticleRefMut<'t> where Self: 't; + type SliceMut<'t> = ParticleSliceMut<'t> where Self: 't; + type IterMut<'t> = ParticleIterMut<'t> where Self: 't; type PtrMut = ParticlePtrMut; fn len(&self) -> usize { @@ -89,11 +91,11 @@ impl<'a> SoASliceMut<'a, Particle> for ParticleSliceMut<'a> { self.is_empty() } - fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c { + fn as_slice<'c>(&'c self) -> Self::Slice<'c> { self.as_slice() } - fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c { + fn slice<'c, 'b: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'b { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, @@ -107,23 +109,23 @@ impl<'a> SoASliceMut<'a, Particle> for ParticleSliceMut<'a> { self.index(start..end) } - fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + fn get<'c>(&'c self, index: usize) -> Option> { self.get(index) } - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { self.index(index) } - fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c { + fn iter<'c>(&'c self) -> Self::Iter<'c> { self.as_ref().into_iter() } - fn as_mut_slice<'c>(&'c mut self) -> Self::SliceMut<'c> where 'a: 'c { + fn as_mut_slice<'c: 'b, 'b>(&'c mut self) -> Self::SliceMut<'c> where Self: 'b { self.reborrow() } - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> where 'a: 'c { + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, @@ -137,15 +139,15 @@ impl<'a> SoASliceMut<'a, Particle> for ParticleSliceMut<'a> { self.index_mut(start..end) } - fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { + fn get_mut<'c>(&'c mut self, index: usize) -> Option> { self.get_mut(index) } - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> { self.index_mut(index) } - fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> where 'a: 'c { + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> { self.iter_mut() } @@ -161,21 +163,20 @@ impl<'a> SoASliceMut<'a, Particle> for ParticleSliceMut<'a> { self.as_mut_ptr() } } - */ +*/ -impl<'a> SoAVec<'a, Particle> for ParticleVec { - type Ref<'t> = ParticleRef<'t> where 'a: 't; - type Slice<'t> = ParticleSlice<'t> where Self: 'a, 'a: 't; - type Iter<'t> = ParticleIter<'t> where Self: 'a, 'a: 't; +/* +impl SoAVec for ParticleVec { + type Ref<'t> = ParticleRef<'t>; + type Slice<'t> = ParticleSlice<'t>; + type Iter<'t> = ParticleIter<'t>; type Ptr = ParticlePtr; - type RefMut<'t> = ParticleRefMut<'t> where Self: 'a, 'a: 't; - type SliceMut<'t> = ParticleSliceMut<'t> where Self: 'a, 'a: 't; - type IterMut<'t> = ParticleIterMut<'t> where Self: 'a, 'a: 't; + type RefMut<'t> = ParticleRefMut<'t>; + type SliceMut<'t> = ParticleSliceMut<'t>; + type IterMut<'t> = ParticleIterMut<'t>; type PtrMut = ParticlePtrMut; - - fn len(&self) -> usize { self.len() } @@ -184,11 +185,11 @@ impl<'a> SoAVec<'a, Particle> for ParticleVec { self.is_empty() } - fn as_slice<'c>(&'c self) -> Self::Slice<'c> where 'a: 'c { + fn as_slice<'c, 'a: 'c>(&'c self) -> Self::Slice<'c> where Self: 'a { self.as_slice() } - fn slice<'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where 'a: 'c { + fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, @@ -202,23 +203,23 @@ impl<'a> SoAVec<'a, Particle> for ParticleVec { self.index(start..end) } - fn get<'c>(&'c self, index: usize) -> Option> where 'a: 'c { + fn get<'c>(&'c self, index: usize) -> Option> { self.get(index) } - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> where 'a: 'c { + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { self.index(index) } - fn iter<'c>(&'c self) -> Self::Iter<'c> where 'a: 'c { + fn iter<'c>(&'c self) -> Self::Iter<'c> { self.iter() } - fn as_mut_slice<'c>(&'c mut self) -> Self::SliceMut<'c> where 'a: 'c { + fn as_mut_slice<'c, 'a: 'c>(&'c mut self) -> Self::SliceMut<'c> where Self: 'a { self.as_mut_slice() } - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> where 'a: 'c { + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> { let start = match index.start_bound() { std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, std::ops::Bound::Unbounded => 0, @@ -232,15 +233,15 @@ impl<'a> SoAVec<'a, Particle> for ParticleVec { self.index_mut(start..end) } - fn get_mut<'c>(&'c mut self, index: usize) -> Option> where 'a: 'c { + fn get_mut<'c>(&'c mut self, index: usize) -> Option> { self.get_mut(index) } - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> where 'a: 'c { + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> { self.index_mut(index) } - fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> where 'a: 'c { + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> { self.iter_mut() } @@ -320,48 +321,11 @@ impl<'a> SoAVec<'a, Particle> for ParticleVec { self.as_mut_ptr() } } +*/ - - impl<'a> SoATypes<'a> for Particle { - type Ptr = ParticlePtr; - - type PtrMut = ParticlePtrMut; - - type Vec<'t> = ParticleVec where 'a: 't, Self: 'a; - - type Ref<'t> = ParticleRef<'t> where Self: 'a, 'a: 't; - - type Iter<'t> = ParticleIter<'t> where Self: 'a, 'a: 't; - - type Slice<'t> = ParticleSlice<'t> where Self: 'a, 'a: 't; - - type RefMut<'t> = ParticleRefMut<'t> where Self: 'a, 'a: 't; - - type SliceMut<'t> = ParticleSliceMut<'t> where Self: 'a, 'a: 't; - - type IterMut<'t> = ParticleIterMut<'t> where Self: 'a, 'a: 't; -} - -fn order_concrete<'a>(vec: &mut ParticleVec) { - let mut indices: Vec<_> = (0..vec.len()).collect(); - indices.sort_by(|j, k| { - let a = vec.index(*j); - let b = vec.index(*k); - a.partial_cmp(&b).unwrap() - }); -} - -fn order_generic<'a, T: StructOfArray, V: SoASlice<'a, T> + 'a>(vec: &'a V) where V::Ref<'a>: PartialOrd { - let mut indices: Vec<_> = (0..vec.len()).collect(); - indices.sort_by(|j, k| { - let a = vec.index(*j); - let b = vec.index(*k); - a.partial_cmp(&b).unwrap() - }); -} - -fn iter_max_generic<'a, T: StructOfArray, V: SoASlice<'a, T> + 'a>(vec: &'a V) -> Option> where V::Ref<'a>: PartialOrd { +fn iter_max_generic<'a, T: StructOfArray, V: SoASlice + 'a>(vec: &'a V) -> Option> where V::Ref<'a>: PartialOrd + Debug { let x= vec.iter().reduce(|a, b| { + eprintln!("{a:?}"); if a.partial_cmp(&b).unwrap().is_ge() { a } else { @@ -371,8 +335,8 @@ fn iter_max_generic<'a, T: StructOfArray, V: SoASlice<'a, T> + 'a>(vec: &'a V) - x } -fn iter_max_generic_iter<'a, T: SoATypes<'a>>(it: T::Iter<'a>) -> Option> where T::Ref<'a>: PartialOrd { - it.reduce(|a: T::Ref<'_>, b: T::Ref<'_>| { +fn iter_max_generic_iter<'a, T: StructOfArray, V: SoAVec>(it: V::Iter<'a>) -> Option> where V::Ref<'a>: PartialOrd { + it.reduce(|a: V::Ref<'_>, b: V::Ref<'_>| { if a.partial_cmp(&b).unwrap().is_ge() { a } else { @@ -381,7 +345,7 @@ fn iter_max_generic_iter<'a, T: SoATypes<'a>>(it: T::Iter<'a>) -> Option>(vec: &'a mut T) -> Option> where T::Ref<'a>: PartialOrd { +fn iter_max_generic_slice>(vec: &S) -> Option> where for<'t> S::Ref<'t>: PartialOrd { let mut indices: Vec<_> = (0..vec.len()).collect(); indices.sort_by(|j, k| { let a = vec.index(*j); @@ -392,40 +356,69 @@ fn iter_max_generic_slice<'a, V: StructOfArray, T: SoAVec<'a, V>>(vec: &'a mut T vec.get(i) } -fn iter_max_concrete<'a>(vec: &'a mut ParticleVec) -> Option<>::Ref<'a>> { - let mut indices: Vec<_> = (0..vec.len()).collect(); - indices.sort_by(|j, k| { - let a = >::index(&vec, *j); - let b = >::index(&vec, *k); - a.partial_cmp(&b).unwrap() - }); - let i = indices.iter().position(|x| *x == 0).unwrap(); - vec.get(i) +fn slice_ref_len<'a, T: StructOfArray, V: SoAVec>(vec: &V) -> usize where for<'t> <>::Slice<'t> as SoASlice>::Ref<'t>: PartialOrd { + let view = vec.as_slice(); + // let _ = iter_max_generic_slice(&view); + view.iter().count() } -fn sort_generic<'a: 't, 't: 'c, 'c, T: StructOfArray, V: SoAVec<'t, T>>(vec: &'a mut V) where V::Ref<'t>: PartialOrd { - let mut indices: Vec<_> = (0..vec.len()).collect(); - indices.sort_by(|j, k| { - let a: V::Ref<'c> = vec.index::<'c>(*j); - let b: V::Ref<'_> = vec.index(*k); - let r = a.partial_cmp(&b).unwrap(); - r - }); + +pub struct VWrap> { + data: V, + _t: PhantomData } +impl> VWrap { + pub fn empty() -> Self { + let data = V::new(); + Self { data, _t: PhantomData } + } + + pub fn push(&mut self, value: T) { + self.data.push(value); + } + + pub fn sort_by(&mut self, f: F) where F: FnMut(V::Ref<'_>, V::Ref<'_>) -> Ordering { + self.data.sort_by(f); + } + + pub fn first(&self) -> Option> { + self.data.first() + } +} + + #[test] fn test_ops() { let mut vec = ParticleVec::new(); vec.push(Particle::new("foo".into(), 100.0)); vec.push(Particle::new("bar".into(), 1000.0)); vec.push(Particle::new("baz".into(), 50.0)); - let view = vec.as_slice(); - let x = iter_max_generic(&view); - eprintln!("{x:?}"); - let y = iter_max_generic_iter::(vec.iter()); - eprintln!("{y:?}"); - let y = iter_max_generic_iter::(view.iter()); - eprintln!("{y:?}"); - let y = iter_max_generic_slice::(&view); + // let x = iter_max_generic(&view); + // eprintln!("{x:?}"); + let y = iter_max_generic_iter::(vec.iter()); eprintln!("{y:?}"); + let k = slice_ref_len(&vec); + assert_eq!(k, 3); + + let mut view = vec.as_mut_slice(); + view.iter_mut().for_each(|f| { + *f.mass *= 2.0; + }); + + let view = vec.as_slice(); + let z = iter_max_generic(&view).unwrap(); + assert_eq!(z.name, "foo"); + + let n = view.iter().count(); + assert!(n > 0); + + let mut pv = VWrap::::empty(); + pv.push(Particle::new("foo".into(), 100.0)); + pv.push(Particle::new("bar".into(), 1000.0)); + pv.push(Particle::new("baz".into(), 50.0)); + pv.sort_by(|a, b| a.mass.total_cmp(&b.mass)); + + assert_eq!(pv.first().unwrap().name, "baz"); + } \ No newline at end of file From aab384823f66ef340fb721a16a9155ba0e29ecd9 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Thu, 16 Jan 2025 12:30:02 -0500 Subject: [PATCH 12/37] checkpoint --- Cargo.toml | 5 + example/Cargo.toml | 2 +- soa-derive-internal/Cargo.toml | 3 + soa-derive-internal/src/input.rs | 11 +- soa-derive-internal/src/lib.rs | 18 +- soa-derive-internal/src/slice.rs | 140 ---------- soa-derive-internal/src/vec.rs | 2 + src/lib.rs | 2 +- tests/generic.rs | 1 + tests/nested_soa.rs | 23 +- tests/particles/mod.rs | 455 ++++++------------------------- 11 files changed, 120 insertions(+), 542 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2988869..866439c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,11 @@ members = [ "example", ] +[features] +default_features = ["generic_traits"] + +generic_traits = ["soa_derive_internal/generic_traits"] + [dependencies] soa_derive_internal = {path = "soa-derive-internal", version = "0.13"} permutation = "0.4.0" diff --git a/example/Cargo.toml b/example/Cargo.toml index 9996d8f..3320bd5 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -8,7 +8,7 @@ publish = false edition = "2021" [dependencies] -soa_derive = {path = ".."} +soa_derive = {path = "..", features = ["generic_traits"]} [lib] path = "lib.rs" diff --git a/soa-derive-internal/Cargo.toml b/soa-derive-internal/Cargo.toml index 5a8a299..09432c0 100644 --- a/soa-derive-internal/Cargo.toml +++ b/soa-derive-internal/Cargo.toml @@ -17,6 +17,9 @@ documentation = "https://docs.rs/soa_derive/" [lib] proc-macro = true +[features] +generic_traits = [] + [dependencies] syn = {version = "2", features = ["derive", "extra-traits"]} quote = "1" diff --git a/soa-derive-internal/src/input.rs b/soa-derive-internal/src/input.rs index faa0fac..983fe7f 100644 --- a/soa-derive-internal/src/input.rs +++ b/soa-derive-internal/src/input.rs @@ -18,6 +18,9 @@ pub struct Input { /// Additional attributes requested with `#[soa_attr(...)]` or /// `#[soa_derive()]` pub attrs: ExtraAttributes, + /// Whether or not to generate extra trait implementations that make the SoA types usable + /// in a generic context + pub generate_traits: bool, } pub struct ExtraAttributes { @@ -109,6 +112,7 @@ impl Input { assert!(!fields.is_empty(), "#[derive(StructOfArray)] only supports struct with fields"); let mut extra_attrs = ExtraAttributes::new(); + let mut generate_traits: bool = false; for attr in input.attrs { if attr.path().is_ident("soa_derive") { @@ -163,6 +167,10 @@ impl Input { None => panic!("expected one of the SoA type, got {}", quote!(#soa_type)) } } + + if attr.path().is_ident("generate_traits") { + generate_traits = true; + } } Input { @@ -170,7 +178,8 @@ impl Input { fields: fields, visibility: input.vis, attrs: extra_attrs, - field_is_nested + field_is_nested, + generate_traits: generate_traits, } } diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index 75724a9..e0b8a74 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -6,7 +6,7 @@ extern crate proc_macro; -use proc_macro2::{TokenStream}; +use proc_macro2::TokenStream; use quote::TokenStreamExt; mod index; @@ -17,10 +17,11 @@ mod ptr; mod refs; mod slice; mod vec; +mod generic; pub(crate) mod names; -#[proc_macro_derive(StructOfArray, attributes(soa_derive, soa_attr, nested_soa))] +#[proc_macro_derive(StructOfArray, attributes(soa_derive, soa_attr, nested_soa, generate_traits))] pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); let input = input::Input::new(ast); @@ -34,6 +35,19 @@ pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { generated.append_all(index::derive(&input)); generated.append_all(iter::derive(&input)); generated.append_all(derive_trait(&input)); + + #[cfg(feature = "generic_traits")] + if input.generate_traits { + generated.append_all( + generic::derive_slice(&input) + ); + generated.append_all( + generic::derive_slice_mut(&input) + ); + generated.append_all( + generic::derive_vec(&input) + ); + } generated.into() } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index 6d72569..aea7636 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -238,54 +238,6 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoASlice<#name> for #slice_name<'a> { - type Ref<'t> = #ref_name<'t> where Self: 't, 'a: 't; - type Slice<'t> = #slice_name<'t> where Self: 't, 'a: 't; - type Iter<'t> = #iter_name<'t> where Self: 't, 'a: 't; - type Ptr = #ptr_name; - - fn len(&self) -> usize { - self.len() - } - - fn is_empty(&self) -> bool { - self.is_empty() - } - - fn as_slice<'c>(&'c self) -> Self::Slice<'c> { - self.reborrow::<'c>() - } - - fn slice<'c, 'b: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'b { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index(start..end) - } - - fn get<'c>(&'c self, index: usize) -> Option> { - self.get(index) - } - - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { - self.index(index) - } - - fn iter<'c>(&'c self) -> Self::Iter<'c> { - self.iter() - } - - fn as_ptr(&self) -> Self::Ptr { - self.as_ptr() - } - } }; if input.attrs.derive_clone { @@ -716,98 +668,6 @@ pub fn derive_mut(input: &Input) -> TokenStream { self.apply_permutation(&mut permutation); } } - - impl<'a> ::soa_derive::SoASliceMut<#name> for #slice_mut_name<'a> { - type Ref<'t> = #ref_name<'t> where Self: 't; - type Slice<'t> = #slice_name<'t> where Self: 't; - type Iter<'t> = #iter_name<'t> where Self: 't; - type Ptr = #ptr_name; - - type RefMut<'t> = #ref_mut_name<'t> where Self: 't; - type SliceMut<'t> = #slice_mut_name<'t> where Self: 't; - type IterMut<'t> = #iter_mut_name<'t> where Self: 't; - type PtrMut = #ptr_mut_name; - - fn len(&self) -> usize { - self.len() - } - - fn is_empty(&self) -> bool { - self.is_empty() - } - - fn as_slice<'c>(&'c self) -> Self::Slice<'c> { - self.as_slice() - } - - fn slice<'c, 'b: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'b { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index(start..end) - } - - fn get<'c>(&'c self, index: usize) -> Option> { - self.get(index) - } - - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { - self.index(index) - } - - fn iter<'c>(&'c self) -> Self::Iter<'c> { - self.as_ref().into_iter() - } - - fn as_mut_slice<'c: 'b, 'b>(&'c mut self) -> Self::SliceMut<'c> where Self: 'b { - self.reborrow() - } - - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index_mut(start..end) - } - - fn get_mut<'c>(&'c mut self, index: usize) -> Option> { - self.get_mut(index) - } - - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> { - self.index_mut(index) - } - - fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> { - self.iter_mut() - } - - fn apply_index(&mut self, indices: &[usize]) { - self.apply_permutation(&mut ::soa_derive::Permutation::oneline(indices).inverse()); - } - - fn as_ptr(&self) -> Self::Ptr { - self.as_ptr() - } - - fn as_mut_ptr(&mut self) -> Self::PtrMut { - self.as_mut_ptr() - } -} }; if input.attrs.derive_clone { diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index 0fe727e..502c96c 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -450,6 +450,7 @@ pub fn derive(input: &Input) -> TokenStream { } } + /* impl ::soa_derive::SoAVec<#name> for #vec_name { type Ref<'t> = #ref_name<'t>; type Slice<'t> = #slice_name<'t>; @@ -606,6 +607,7 @@ pub fn derive(input: &Input) -> TokenStream { self.as_mut_ptr() } } + */ #[allow(clippy::drop_non_drop)] impl Drop for #vec_name { diff --git a/src/lib.rs b/src/lib.rs index 4aec469..3aadcbf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -242,7 +242,7 @@ pub use permutation::permutation::*; /// `CheeseVec`; This will helpful in generics programing that generate struct /// can be expressed as `::Type` pub trait StructOfArray { - type Type: SoAVec where Self: Sized; + type Type;//: SoAVec where Self: Sized; } /// Any struct derived by StructOfArray will auto impl this trait. diff --git a/tests/generic.rs b/tests/generic.rs index b1fada4..2d0cd35 100644 --- a/tests/generic.rs +++ b/tests/generic.rs @@ -1,3 +1,4 @@ +#![cfg(feature = "generic_traits")] // use soa_derive::prelude::*; mod particles; diff --git a/tests/nested_soa.rs b/tests/nested_soa.rs index ee976ae..3a91dea 100644 --- a/tests/nested_soa.rs +++ b/tests/nested_soa.rs @@ -1,4 +1,4 @@ -use soa_derive::{StructOfArray, prelude::*}; +use soa_derive::StructOfArray; #[derive(Debug, Clone, PartialEq, StructOfArray)] pub struct Point { @@ -58,24 +58,3 @@ fn nested_soa() { a: vec![255, 23], }); } - -// fn generic_f<'a, T: SoATypes<'a>>(vec: &'a T::Vec<'a>) { -// assert_eq!(vec.len(), 2); -// } - -// #[test] -// fn test_nested_generic() { -// let mut particle_vec = ParticleVec::new(); -// particle_vec.push(Particle { -// point: Point { x: 1.0, y: 2.0 }, -// color: Color { r: 255, g: 0, b: 0, a: 255 }, -// mass: 1.0, -// }); -// particle_vec.push(Particle { -// point: Point { x: 2.0, y: 3.0 }, -// color: Color { r: 128, g: 255, b: 100, a: 23 }, -// mass: 2.0, -// }); - -// generic_f::(&particle_vec); -// } \ No newline at end of file diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index 1e25f1b..b9bb11d 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -1,11 +1,10 @@ -use std::cmp::Ordering; use std::fmt::Debug; -use std::marker::PhantomData; use soa_derive::prelude::*; #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] +#[cfg_attr(feature = "generic_traits", generate_traits)] pub struct Particle { pub name: String, pub mass: f64, @@ -20,405 +19,111 @@ impl Particle { } } -/* -impl<'a> SoASlice for ParticleSlice<'a> { - type Ref<'t> = ParticleRef<'t> where Self: 't, 'a: 't; - type Slice<'t> = ParticleSlice<'t> where Self: 't, 'a: 't; - type Iter<'t> = ParticleIter<'t> where Self: 't, 'a: 't; - type Ptr = ParticlePtr; - fn len(&self) -> usize { - self.len() - } - - fn is_empty(&self) -> bool { - self.is_empty() - } - - fn as_slice<'c>(&'c self) -> Self::Slice<'c> { - self.reborrow::<'c>() - } - - fn slice<'c, 'b: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'b { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index(start..end) - } - - fn get<'c>(&'c self, index: usize) -> Option> { - self.get(index) - } - - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { - self.index(index) - } - - fn iter<'c>(&'c self) -> Self::Iter<'c> { - self.iter() - } - - fn as_ptr(&self) -> Self::Ptr { - self.as_ptr() - } -} -*/ - -/* -impl<'a> SoASliceMut for ParticleSliceMut<'a> { - type Ref<'t> = ParticleRef<'t> where Self: 't; - type Slice<'t> = ParticleSlice<'t> where Self: 't; - type Iter<'t> = ParticleIter<'t> where Self: 't; - type Ptr = ParticlePtr; - - type RefMut<'t> = ParticleRefMut<'t> where Self: 't; - type SliceMut<'t> = ParticleSliceMut<'t> where Self: 't; - type IterMut<'t> = ParticleIterMut<'t> where Self: 't; - type PtrMut = ParticlePtrMut; - - fn len(&self) -> usize { - self.len() - } - - fn is_empty(&self) -> bool { - self.is_empty() - } - - fn as_slice<'c>(&'c self) -> Self::Slice<'c> { - self.as_slice() - } - - fn slice<'c, 'b: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'b { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index(start..end) - } - - fn get<'c>(&'c self, index: usize) -> Option> { - self.get(index) - } - - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { - self.index(index) - } - - fn iter<'c>(&'c self) -> Self::Iter<'c> { - self.as_ref().into_iter() - } - - fn as_mut_slice<'c: 'b, 'b>(&'c mut self) -> Self::SliceMut<'c> where Self: 'b { - self.reborrow() - } - - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index_mut(start..end) - } - - fn get_mut<'c>(&'c mut self, index: usize) -> Option> { - self.get_mut(index) - } - - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> { - self.index_mut(index) - } - - fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> { - self.iter_mut() - } - - fn apply_index(&mut self, indices: &[usize]) { - self.apply_permutation(&mut Permutation::oneline(indices).inverse()); - } - - fn as_ptr(&self) -> Self::Ptr { - self.as_ptr() - } - - fn as_mut_ptr(&mut self) -> Self::PtrMut { - self.as_mut_ptr() - } -} -*/ - -/* -impl SoAVec for ParticleVec { - type Ref<'t> = ParticleRef<'t>; - type Slice<'t> = ParticleSlice<'t>; - type Iter<'t> = ParticleIter<'t>; - type Ptr = ParticlePtr; - - type RefMut<'t> = ParticleRefMut<'t>; - type SliceMut<'t> = ParticleSliceMut<'t>; - type IterMut<'t> = ParticleIterMut<'t>; - type PtrMut = ParticlePtrMut; - - fn len(&self) -> usize { - self.len() - } - - fn is_empty(&self) -> bool { - self.is_empty() - } - - fn as_slice<'c, 'a: 'c>(&'c self) -> Self::Slice<'c> where Self: 'a { - self.as_slice() - } - - fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index(start..end) - } - - fn get<'c>(&'c self, index: usize) -> Option> { - self.get(index) - } - - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { - self.index(index) - } - - fn iter<'c>(&'c self) -> Self::Iter<'c> { - self.iter() - } - - fn as_mut_slice<'c, 'a: 'c>(&'c mut self) -> Self::SliceMut<'c> where Self: 'a { - self.as_mut_slice() - } - - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index_mut(start..end) - } - - fn get_mut<'c>(&'c mut self, index: usize) -> Option> { - self.get_mut(index) - } - - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> { - self.index_mut(index) - } - - fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> { - self.iter_mut() - } - - fn apply_index(&mut self, indices: &[usize]) { - self.as_mut_slice().apply_index(indices); - } - - fn new() -> Self { - Self::new() - } - - fn with_capacity(capacity: usize) -> Self { - Self::with_capacity(capacity) - } - - fn capacity(&self) -> usize { - self.capacity() - } - - fn reserve(&mut self, additional: usize) { - self.reserve(additional); - } - - fn reserve_exact(&mut self, additional: usize) { - self.reserve_exact(additional); - } - - fn shrink_to_fit(&mut self) { - self.shrink_to_fit(); - } - - fn truncate(&mut self, len: usize) { - self.truncate(len); - } - - fn push(&mut self, value: Particle) { - self.push(value); - } - - fn swap_remove(&mut self, index: usize) -> Particle { - self.swap_remove(index) - } - fn insert(&mut self, index: usize, element: Particle) { - self.insert(index, element); - } +#[cfg(feature = "generic_traits")] +mod impls { + use std::cmp::Ordering; + use std::marker::PhantomData; - fn replace(&mut self, index: usize, element: Particle) -> Particle { - self.replace(index, element) - } + use super::*; - fn remove(&mut self, index: usize) -> Particle { - self.remove(index) + fn iter_max_generic<'a, T: StructOfArray, V: SoASlice + 'a>(vec: &'a V) -> Option> where V::Ref<'a>: PartialOrd + Debug { + let x= vec.iter().reduce(|a, b| { + eprintln!("{a:?}"); + if a.partial_cmp(&b).unwrap().is_ge() { + a + } else { + b + } + }); + x } - fn pop(&mut self) -> Option { - self.pop() + fn iter_max_generic_iter<'a, T: StructOfArray, V: SoAVec>(it: V::Iter<'a>) -> Option> where V::Ref<'a>: PartialOrd { + it.reduce(|a: V::Ref<'_>, b: V::Ref<'_>| { + if a.partial_cmp(&b).unwrap().is_ge() { + a + } else { + b + } + }) } - fn append(&mut self, other: &mut Self) { - self.append(other); + fn iter_max_generic_slice>(vec: &S) -> Option> where for<'t> S::Ref<'t>: PartialOrd { + let mut indices: Vec<_> = (0..vec.len()).collect(); + indices.sort_by(|j, k| { + let a = vec.index(*j); + let b = vec.index(*k); + a.partial_cmp(&b).unwrap() + }); + let i = indices.iter().position(|x| *x == 0).unwrap(); + vec.get(i) } - fn clear(&mut self) { - self.clear(); + fn slice_ref_len<'a, T: StructOfArray, V: SoAVec>(vec: &V) -> usize where for<'t> <>::Slice<'t> as SoASlice>::Ref<'t>: PartialOrd { + let view = vec.as_slice(); + // let _ = iter_max_generic_slice(&view); + view.iter().count() } - fn split_off(&mut self, at: usize) -> Self { - self.split_off(at) - } - fn as_ptr(&self) -> Self::Ptr { - self.as_ptr() + pub struct VWrap> { + data: V, + _t: PhantomData } - fn as_mut_ptr(&mut self) -> Self::PtrMut { - self.as_mut_ptr() - } -} -*/ - -fn iter_max_generic<'a, T: StructOfArray, V: SoASlice + 'a>(vec: &'a V) -> Option> where V::Ref<'a>: PartialOrd + Debug { - let x= vec.iter().reduce(|a, b| { - eprintln!("{a:?}"); - if a.partial_cmp(&b).unwrap().is_ge() { - a - } else { - b + impl> VWrap { + pub fn empty() -> Self { + let data = V::new(); + Self { data, _t: PhantomData } } - }); - x -} -fn iter_max_generic_iter<'a, T: StructOfArray, V: SoAVec>(it: V::Iter<'a>) -> Option> where V::Ref<'a>: PartialOrd { - it.reduce(|a: V::Ref<'_>, b: V::Ref<'_>| { - if a.partial_cmp(&b).unwrap().is_ge() { - a - } else { - b + pub fn push(&mut self, value: T) { + self.data.push(value); } - }) -} - -fn iter_max_generic_slice>(vec: &S) -> Option> where for<'t> S::Ref<'t>: PartialOrd { - let mut indices: Vec<_> = (0..vec.len()).collect(); - indices.sort_by(|j, k| { - let a = vec.index(*j); - let b = vec.index(*k); - a.partial_cmp(&b).unwrap() - }); - let i = indices.iter().position(|x| *x == 0).unwrap(); - vec.get(i) -} -fn slice_ref_len<'a, T: StructOfArray, V: SoAVec>(vec: &V) -> usize where for<'t> <>::Slice<'t> as SoASlice>::Ref<'t>: PartialOrd { - let view = vec.as_slice(); - // let _ = iter_max_generic_slice(&view); - view.iter().count() -} - - -pub struct VWrap> { - data: V, - _t: PhantomData -} - -impl> VWrap { - pub fn empty() -> Self { - let data = V::new(); - Self { data, _t: PhantomData } - } - - pub fn push(&mut self, value: T) { - self.data.push(value); - } + pub fn sort_by(&mut self, f: F) where F: FnMut(V::Ref<'_>, V::Ref<'_>) -> Ordering { + self.data.sort_by(f); + } - pub fn sort_by(&mut self, f: F) where F: FnMut(V::Ref<'_>, V::Ref<'_>) -> Ordering { - self.data.sort_by(f); + pub fn first(&self) -> Option> { + self.data.first() + } } - pub fn first(&self) -> Option> { - self.data.first() - } -} + #[test] + fn test_ops() { + let mut vec = ParticleVec::new(); + vec.push(Particle::new("foo".into(), 100.0)); + vec.push(Particle::new("bar".into(), 1000.0)); + vec.push(Particle::new("baz".into(), 50.0)); + // let x = iter_max_generic(&view); + // eprintln!("{x:?}"); + let y = iter_max_generic_iter::(vec.iter()); + eprintln!("{y:?}"); + let k = slice_ref_len(&vec); + assert_eq!(k, 3); + let mut view = vec.as_mut_slice(); + view.iter_mut().for_each(|f| { + *f.mass *= 2.0; + }); -#[test] -fn test_ops() { - let mut vec = ParticleVec::new(); - vec.push(Particle::new("foo".into(), 100.0)); - vec.push(Particle::new("bar".into(), 1000.0)); - vec.push(Particle::new("baz".into(), 50.0)); - // let x = iter_max_generic(&view); - // eprintln!("{x:?}"); - let y = iter_max_generic_iter::(vec.iter()); - eprintln!("{y:?}"); - let k = slice_ref_len(&vec); - assert_eq!(k, 3); + let view = vec.as_slice(); + let z = iter_max_generic(&view).unwrap(); + assert_eq!(z.name, "foo"); - let mut view = vec.as_mut_slice(); - view.iter_mut().for_each(|f| { - *f.mass *= 2.0; - }); + let n = view.iter().count(); + assert!(n > 0); - let view = vec.as_slice(); - let z = iter_max_generic(&view).unwrap(); - assert_eq!(z.name, "foo"); + let mut pv = VWrap::::empty(); + pv.push(Particle::new("foo".into(), 100.0)); + pv.push(Particle::new("bar".into(), 1000.0)); + pv.push(Particle::new("baz".into(), 50.0)); + pv.sort_by(|a, b| a.mass.total_cmp(&b.mass)); - let n = view.iter().count(); - assert!(n > 0); - - let mut pv = VWrap::::empty(); - pv.push(Particle::new("foo".into(), 100.0)); - pv.push(Particle::new("bar".into(), 1000.0)); - pv.push(Particle::new("baz".into(), 50.0)); - pv.sort_by(|a, b| a.mass.total_cmp(&b.mass)); - - assert_eq!(pv.first().unwrap().name, "baz"); + assert_eq!(pv.first().unwrap().name, "baz"); + } } \ No newline at end of file From 0fc43d55b04d6fc7d2f0cb5a68911cc26f140543 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Thu, 16 Jan 2025 12:53:13 -0500 Subject: [PATCH 13/37] restructure crate for features --- .github/workflows/tests.yml | 19 + Cargo.toml | 34 +- example/Cargo.toml | 2 +- soa-derive-internal/src/generic.rs | 351 +++++++++++++++++++ soa-derive/Cargo.toml | 31 ++ {src => soa-derive/src}/lib.rs | 0 {tests => soa-derive/tests}/extreme.rs | 0 {tests => soa-derive/tests}/generic.rs | 0 {tests => soa-derive/tests}/index.rs | 0 {tests => soa-derive/tests}/iter.rs | 0 {tests => soa-derive/tests}/nested_soa.rs | 0 {tests => soa-derive/tests}/particles/mod.rs | 12 - {tests => soa-derive/tests}/ptr.rs | 0 {tests => soa-derive/tests}/replace.rs | 0 {tests => soa-derive/tests}/serde.rs | 0 {tests => soa-derive/tests}/slice.rs | 0 {tests => soa-derive/tests}/slice_mut.rs | 0 {tests => soa-derive/tests}/soa_attr.rs | 0 {tests => soa-derive/tests}/vec.rs | 0 {tests => soa-derive/tests}/zip.rs | 0 20 files changed, 405 insertions(+), 44 deletions(-) create mode 100644 soa-derive-internal/src/generic.rs create mode 100644 soa-derive/Cargo.toml rename {src => soa-derive/src}/lib.rs (100%) rename {tests => soa-derive/tests}/extreme.rs (100%) rename {tests => soa-derive/tests}/generic.rs (100%) rename {tests => soa-derive/tests}/index.rs (100%) rename {tests => soa-derive/tests}/iter.rs (100%) rename {tests => soa-derive/tests}/nested_soa.rs (100%) rename {tests => soa-derive/tests}/particles/mod.rs (88%) rename {tests => soa-derive/tests}/ptr.rs (100%) rename {tests => soa-derive/tests}/replace.rs (100%) rename {tests => soa-derive/tests}/serde.rs (100%) rename {tests => soa-derive/tests}/slice.rs (100%) rename {tests => soa-derive/tests}/slice_mut.rs (100%) rename {tests => soa-derive/tests}/soa_attr.rs (100%) rename {tests => soa-derive/tests}/vec.rs (100%) rename {tests => soa-derive/tests}/zip.rs (100%) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2d9b712..ec58a38 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,3 +26,22 @@ jobs: run: cargo test --release - name: check that benchmarks still compile run: cargo bench --no-run + tests_derive_generics: + runs-on: ubuntu-20.04 + strategy: + matrix: + rust-version: [stable, beta, nightly] + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - name: setup rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust-version }} + - name: run tests in debug mode + run: cargo test -F generic_traits + - name: run tests in release mode + run: cargo test --release -F generic_traits + - name: check that benchmarks still compile + run: cargo bench --no-run -F generic_traits diff --git a/Cargo.toml b/Cargo.toml index 866439c..9121352 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,38 +1,10 @@ -[package] -name = "soa_derive" -version = "0.13.0" -edition = "2018" -rust-version = "1.63" - -authors = ["Guillaume Fraux "] -license = "MIT/Apache-2.0" +[workspace] -readme = "README.md" -description = "Automatic Struct of Array generation" -repository = "https://github.com/lumol-org/soa-derive" -homepage = "https://github.com/lumol-org/soa-derive" -documentation = "https://docs.rs/soa_derive/" +resolver = "2" -[workspace] members = [ "soa-derive-internal", + "soa-derive", "example", ] -[features] -default_features = ["generic_traits"] - -generic_traits = ["soa_derive_internal/generic_traits"] - -[dependencies] -soa_derive_internal = {path = "soa-derive-internal", version = "0.13"} -permutation = "0.4.0" - -[dev-dependencies] -bencher = "0.1" -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[[bench]] -name = "soa" -harness = false diff --git a/example/Cargo.toml b/example/Cargo.toml index 3320bd5..0ab3799 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -8,7 +8,7 @@ publish = false edition = "2021" [dependencies] -soa_derive = {path = "..", features = ["generic_traits"]} +soa_derive = {path = "../soa-derive"} [lib] path = "lib.rs" diff --git a/soa-derive-internal/src/generic.rs b/soa-derive-internal/src/generic.rs new file mode 100644 index 0000000..d316039 --- /dev/null +++ b/soa-derive-internal/src/generic.rs @@ -0,0 +1,351 @@ +use proc_macro2::TokenStream; +use quote::quote; + +use crate::input::Input; +use crate::names; + + +pub fn derive_slice(input: &Input) -> TokenStream { + let name = &input.name; + let slice_name = names::slice_name(name); + let ref_name = names::ref_name(&input.name); + let ptr_name = names::ptr_name(&input.name); + let iter_name = names::iter_name(name); + + let generated = quote! { + impl<'a> ::soa_derive::SoASlice<#name> for #slice_name<'a> { + type Ref<'t> = #ref_name<'t> where Self: 't, 'a: 't; + type Slice<'t> = #slice_name<'t> where Self: 't, 'a: 't; + type Iter<'t> = #iter_name<'t> where Self: 't, 'a: 't; + type Ptr = #ptr_name; + + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn as_slice<'c>(&'c self) -> Self::Slice<'c> { + self.reborrow::<'c>() + } + + fn slice<'c, 'b: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'b { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index(start..end) + } + + fn get<'c>(&'c self, index: usize) -> Option> { + self.get(index) + } + + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { + self.index(index) + } + + fn iter<'c>(&'c self) -> Self::Iter<'c> { + self.iter() + } + + fn as_ptr(&self) -> Self::Ptr { + self.as_ptr() + } + } + }; + + return generated +} + +pub fn derive_slice_mut(input: &Input) -> TokenStream { + let name = &input.name; + let slice_name = names::slice_name(name); + let slice_mut_name = names::slice_mut_name(&input.name); + let ref_name = names::ref_name(&input.name); + let ref_mut_name = names::ref_mut_name(&input.name); + let ptr_name = names::ptr_name(&input.name); + let ptr_mut_name = names::ptr_mut_name(&input.name); + let iter_name = names::iter_name(name); + let iter_mut_name = names::iter_mut_name(name); + + + let generated = quote! { + + impl<'a> ::soa_derive::SoASliceMut<#name> for #slice_mut_name<'a> { + type Ref<'t> = #ref_name<'t> where Self: 't; + type Slice<'t> = #slice_name<'t> where Self: 't; + type Iter<'t> = #iter_name<'t> where Self: 't; + type Ptr = #ptr_name; + + type RefMut<'t> = #ref_mut_name<'t> where Self: 't; + type SliceMut<'t> = #slice_mut_name<'t> where Self: 't; + type IterMut<'t> = #iter_mut_name<'t> where Self: 't; + type PtrMut = #ptr_mut_name; + + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn as_slice<'c>(&'c self) -> Self::Slice<'c> { + self.as_slice() + } + + fn slice<'c, 'b: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'b { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index(start..end) + } + + fn get<'c>(&'c self, index: usize) -> Option> { + self.get(index) + } + + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { + self.index(index) + } + + fn iter<'c>(&'c self) -> Self::Iter<'c> { + self.as_ref().into_iter() + } + + fn as_mut_slice<'c: 'b, 'b>(&'c mut self) -> Self::SliceMut<'c> where Self: 'b { + self.reborrow() + } + + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index_mut(start..end) + } + + fn get_mut<'c>(&'c mut self, index: usize) -> Option> { + self.get_mut(index) + } + + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> { + self.index_mut(index) + } + + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> { + self.iter_mut() + } + + fn apply_index(&mut self, indices: &[usize]) { + self.apply_permutation(&mut ::soa_derive::Permutation::oneline(indices).inverse()); + } + + fn as_ptr(&self) -> Self::Ptr { + self.as_ptr() + } + + fn as_mut_ptr(&mut self) -> Self::PtrMut { + self.as_mut_ptr() + } + } + }; + return generated +} + +pub fn derive_vec(input: &Input) -> TokenStream { + let name = &input.name; + let vec_name = names::vec_name(&input.name); + let slice_name = names::slice_name(name); + let slice_mut_name = names::slice_mut_name(&input.name); + let ref_name = names::ref_name(&input.name); + let ref_mut_name = names::ref_mut_name(&input.name); + let ptr_name = names::ptr_name(&input.name); + let ptr_mut_name = names::ptr_mut_name(&input.name); + let iter_name = names::iter_name(name); + let iter_mut_name = names::iter_mut_name(name); + + let generated = quote! { + + impl ::soa_derive::SoAVec<#name> for #vec_name { + type Ref<'t> = #ref_name<'t>; + type Slice<'t> = #slice_name<'t>; + type Iter<'t> = #iter_name<'t>; + type Ptr = #ptr_name; + + type RefMut<'t> = #ref_mut_name<'t>; + type SliceMut<'t> = #slice_mut_name<'t>; + type IterMut<'t> = #iter_mut_name<'t>; + type PtrMut = #ptr_mut_name; + + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn as_slice<'c, 'a: 'c>(&'c self) -> Self::Slice<'c> where Self: 'a { + self.as_slice() + } + + fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index(start..end) + } + + fn get<'c>(&'c self, index: usize) -> Option> { + self.get(index) + } + + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { + self.index(index) + } + + fn iter<'c>(&'c self) -> Self::Iter<'c> { + self.iter() + } + + fn as_mut_slice<'c, 'a: 'c>(&'c mut self) -> Self::SliceMut<'c> where Self: 'a { + self.as_mut_slice() + } + + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> { + let start = match index.start_bound() { + std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => 0, + }; + let n = self.len(); + let end = match index.end_bound() { + std::ops::Bound::Included(i) => (*i + 1).min(n), + std::ops::Bound::Excluded(i) => *i, + std::ops::Bound::Unbounded => n, + }; + self.index_mut(start..end) + } + + fn get_mut<'c>(&'c mut self, index: usize) -> Option> { + self.get_mut(index) + } + + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> { + self.index_mut(index) + } + + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> { + self.iter_mut() + } + + fn apply_index(&mut self, indices: &[usize]) { + use ::soa_derive::SoASliceMut; + self.as_mut_slice().apply_index(indices); + } + + fn new() -> Self { + Self::new() + } + + fn with_capacity(capacity: usize) -> Self { + Self::with_capacity(capacity) + } + + fn capacity(&self) -> usize { + self.capacity() + } + + fn reserve(&mut self, additional: usize) { + self.reserve(additional); + } + + fn reserve_exact(&mut self, additional: usize) { + self.reserve_exact(additional); + } + + fn shrink_to_fit(&mut self) { + self.shrink_to_fit(); + } + + fn truncate(&mut self, len: usize) { + self.truncate(len); + } + + fn push(&mut self, value: #name) { + self.push(value); + } + + fn swap_remove(&mut self, index: usize) -> #name { + self.swap_remove(index) + } + + fn insert(&mut self, index: usize, element: #name) { + self.insert(index, element); + } + + fn replace(&mut self, index: usize, element: #name) -> #name { + self.replace(index, element) + } + + fn remove(&mut self, index: usize) -> #name { + self.remove(index) + } + + fn pop(&mut self) -> Option<#name> { + self.pop() + } + + fn append(&mut self, other: &mut Self) { + self.append(other); + } + + fn clear(&mut self) { + self.clear(); + } + + fn split_off(&mut self, at: usize) -> Self { + self.split_off(at) + } + + fn as_ptr(&self) -> Self::Ptr { + self.as_ptr() + } + + fn as_mut_ptr(&mut self) -> Self::PtrMut { + self.as_mut_ptr() + } + } + }; + + return generated +} \ No newline at end of file diff --git a/soa-derive/Cargo.toml b/soa-derive/Cargo.toml new file mode 100644 index 0000000..c523d74 --- /dev/null +++ b/soa-derive/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "soa_derive" +version = "0.13.0" +edition = "2018" +rust-version = "1.63" + +authors = ["Guillaume Fraux "] +license = "MIT/Apache-2.0" + +readme = "README.md" +description = "Automatic Struct of Array generation" +repository = "https://github.com/lumol-org/soa-derive" +homepage = "https://github.com/lumol-org/soa-derive" +documentation = "https://docs.rs/soa_derive/" + +[features] +generic_traits = ["soa_derive_internal/generic_traits"] + +[dependencies] +soa_derive_internal = {path = "../soa-derive-internal", version = "0.13"} +permutation = "0.4.0" + +[dev-dependencies] +bencher = "0.1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +[[bench]] +name = "soa" +path = "../benches/soa.rs" +harness = false diff --git a/src/lib.rs b/soa-derive/src/lib.rs similarity index 100% rename from src/lib.rs rename to soa-derive/src/lib.rs diff --git a/tests/extreme.rs b/soa-derive/tests/extreme.rs similarity index 100% rename from tests/extreme.rs rename to soa-derive/tests/extreme.rs diff --git a/tests/generic.rs b/soa-derive/tests/generic.rs similarity index 100% rename from tests/generic.rs rename to soa-derive/tests/generic.rs diff --git a/tests/index.rs b/soa-derive/tests/index.rs similarity index 100% rename from tests/index.rs rename to soa-derive/tests/index.rs diff --git a/tests/iter.rs b/soa-derive/tests/iter.rs similarity index 100% rename from tests/iter.rs rename to soa-derive/tests/iter.rs diff --git a/tests/nested_soa.rs b/soa-derive/tests/nested_soa.rs similarity index 100% rename from tests/nested_soa.rs rename to soa-derive/tests/nested_soa.rs diff --git a/tests/particles/mod.rs b/soa-derive/tests/particles/mod.rs similarity index 88% rename from tests/particles/mod.rs rename to soa-derive/tests/particles/mod.rs index b9bb11d..66e12f5 100644 --- a/tests/particles/mod.rs +++ b/soa-derive/tests/particles/mod.rs @@ -50,24 +50,12 @@ mod impls { }) } - fn iter_max_generic_slice>(vec: &S) -> Option> where for<'t> S::Ref<'t>: PartialOrd { - let mut indices: Vec<_> = (0..vec.len()).collect(); - indices.sort_by(|j, k| { - let a = vec.index(*j); - let b = vec.index(*k); - a.partial_cmp(&b).unwrap() - }); - let i = indices.iter().position(|x| *x == 0).unwrap(); - vec.get(i) - } - fn slice_ref_len<'a, T: StructOfArray, V: SoAVec>(vec: &V) -> usize where for<'t> <>::Slice<'t> as SoASlice>::Ref<'t>: PartialOrd { let view = vec.as_slice(); // let _ = iter_max_generic_slice(&view); view.iter().count() } - pub struct VWrap> { data: V, _t: PhantomData diff --git a/tests/ptr.rs b/soa-derive/tests/ptr.rs similarity index 100% rename from tests/ptr.rs rename to soa-derive/tests/ptr.rs diff --git a/tests/replace.rs b/soa-derive/tests/replace.rs similarity index 100% rename from tests/replace.rs rename to soa-derive/tests/replace.rs diff --git a/tests/serde.rs b/soa-derive/tests/serde.rs similarity index 100% rename from tests/serde.rs rename to soa-derive/tests/serde.rs diff --git a/tests/slice.rs b/soa-derive/tests/slice.rs similarity index 100% rename from tests/slice.rs rename to soa-derive/tests/slice.rs diff --git a/tests/slice_mut.rs b/soa-derive/tests/slice_mut.rs similarity index 100% rename from tests/slice_mut.rs rename to soa-derive/tests/slice_mut.rs diff --git a/tests/soa_attr.rs b/soa-derive/tests/soa_attr.rs similarity index 100% rename from tests/soa_attr.rs rename to soa-derive/tests/soa_attr.rs diff --git a/tests/vec.rs b/soa-derive/tests/vec.rs similarity index 100% rename from tests/vec.rs rename to soa-derive/tests/vec.rs diff --git a/tests/zip.rs b/soa-derive/tests/zip.rs similarity index 100% rename from tests/zip.rs rename to soa-derive/tests/zip.rs From 5f3e7660c9bc518857cd953d5a2496cf915e352a Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Thu, 16 Jan 2025 13:04:01 -0500 Subject: [PATCH 14/37] guard traits --- soa-derive/src/lib.rs | 479 ++++++++++++++++++++++-------------------- 1 file changed, 255 insertions(+), 224 deletions(-) diff --git a/soa-derive/src/lib.rs b/soa-derive/src/lib.rs index 3aadcbf..e7fa0b4 100644 --- a/soa-derive/src/lib.rs +++ b/soa-derive/src/lib.rs @@ -391,290 +391,321 @@ pub trait SoAPointers { type MutPtr; } -/** -The interface for the `Slice` immutable slice struct-of-arrays type. - */ -pub trait SoASlice { - type Ref<'t> where Self: 't; - type Slice<'t>: SoASlice where Self: 't; - type Iter<'t>: Iterator> where Self: 't; - type Ptr; - - fn len(&self) -> usize; - fn is_empty(&self) -> bool; - fn as_slice<'c>(&'c self) -> Self::Slice<'c>; - /// Create a slice of this vector matching the given `range`. This - /// is analogous to `Index>`. - fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a; +#[cfg(feature = "generic_traits")] +mod generics { + use super::*; - /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) - fn get<'c>(&'c self, index: usize) -> Option>; + /** + The interface for the `Slice` immutable slice struct-of-arrays type. + */ + pub trait SoASlice { + type Ref<'t> where Self: 't; + type Slice<'t>: SoASlice where Self: 't; + type Iter<'t>: Iterator> where Self: 't; + type Ptr; - /// Analogous to [`std::ops::Index::index()`] for `usize` - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c>; + fn len(&self) -> usize; + fn is_empty(&self) -> bool; + fn as_slice<'c>(&'c self) -> Self::Slice<'c>; - /// Create an immutable iterator - fn iter<'c>(&'c self) -> Self::Iter<'c>; + /// Create a slice of this vector matching the given `range`. This + /// is analogous to `Index>`. + fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a; - /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) - fn first<'c>(&'c self) -> Option> { - self.get(0) - } - - /// Analogous to [`slice::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last) - fn last<'c>(&'c self) -> Option> { - self.get(self.len().saturating_sub(1)) - } - - /// Obtain a `const` pointer type for this data - fn as_ptr(&self) -> Self::Ptr; -} - -/** -The interface for the `SliceMut` mutable slice struct-of-arrays type. A generalization of [`SoASlice`] -whose methods can modify elements of the arrays - */ -pub trait SoASliceMut { - type Ref<'t> where Self: 't; - type Slice<'t>: SoASlice where Self: 't; - type Iter<'t>: Iterator> where Self: 't; - type Ptr; + /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) + fn get<'c>(&'c self, index: usize) -> Option>; - type RefMut<'t> where Self: 't; - type SliceMut<'t>: SoASliceMut where Self: 't; - type IterMut<'t>: Iterator> where Self: 't; - type PtrMut; + /// Analogous to [`std::ops::Index::index()`] for `usize` + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c>; - fn len(&self) -> usize; - fn is_empty(&self) -> bool; - fn as_slice<'c>(&'c self) -> Self::Slice<'c>; + /// Create an immutable iterator + fn iter<'c>(&'c self) -> Self::Iter<'c>; - /// Create a slice of this vector matching the given `range`. This - /// is analogous to `Index>`. - fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a; + /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) + fn first<'c>(&'c self) -> Option> { + self.get(0) + } - /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) - fn get<'c>(&'c self, index: usize) -> Option>; + /// Analogous to [`slice::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last) + fn last<'c>(&'c self) -> Option> { + self.get(self.len().saturating_sub(1)) + } - /// Analogous to [`std::ops::Index::index()`] for `usize` - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c>; - - /// Create an immutable iterator - fn iter<'c>(&'c self) -> Self::Iter<'c>; - - /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) - fn first<'c>(&'c self) -> Option> { - self.get(0) + /// Obtain a `const` pointer type for this data + fn as_ptr(&self) -> Self::Ptr; } - /// Analogous to [`slice::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last) - fn last<'c>(&'c self) -> Option> { - self.get(self.len().saturating_sub(1)) + /** + The interface for the `SliceMut` mutable slice struct-of-arrays type. A generalization of [`SoASlice`] + whose methods can modify elements of the arrays + */ + pub trait SoASliceMut { + type Ref<'t> where Self: 't; + type Slice<'t>: SoASlice where Self: 't; + type Iter<'t>: Iterator> where Self: 't; + type Ptr; + + type RefMut<'t> where Self: 't; + type SliceMut<'t>: SoASliceMut where Self: 't; + type IterMut<'t>: Iterator> where Self: 't; + type PtrMut; + + fn len(&self) -> usize; + fn is_empty(&self) -> bool; + fn as_slice<'c>(&'c self) -> Self::Slice<'c>; + + /// Create a slice of this vector matching the given `range`. This + /// is analogous to `Index>`. + fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a; + + /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) + fn get<'c>(&'c self, index: usize) -> Option>; + + /// Analogous to [`std::ops::Index::index()`] for `usize` + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c>; + + /// Create an immutable iterator + fn iter<'c>(&'c self) -> Self::Iter<'c>; + + /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) + fn first<'c>(&'c self) -> Option> { + self.get(0) + } + + /// Analogous to [`slice::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last) + fn last<'c>(&'c self) -> Option> { + self.get(self.len().saturating_sub(1)) + } + + /// Obtain a `const` pointer type for this data + fn as_ptr(&self) -> Self::Ptr; + + /// Analogous to [`Vec::as_mut_slice()`] + fn as_mut_slice<'c: 'b, 'b>(&'c mut self) -> Self::SliceMut<'c> where Self: 'b; + + /// Create a mutable slice of this vector matching the given + /// `range`. This is analogous to `IndexMut>`. + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c>; + + /// Analogous to [`slice::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut) + fn get_mut<'c>(&'c mut self, index: usize) -> Option>; + + /// Analogous to [`std::ops::IndexMut::index_mut()`] for `usize` + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c>; + + /// Creates a mutable iterator + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c>; + + /** Re-order the arrays using the provided indices. This is provided so that generic sorting methods + can be implemented because closure-passing trait methods encounter difficulties with lifetimes. + */ + fn apply_index(&mut self, indices: &[usize]); + + fn sort_by(&mut self, mut f: F) where F: FnMut(Self::Ref<'_>, Self::Ref<'_>) -> std::cmp::Ordering { + let mut permutation: Vec = (0..self.len()).collect(); + permutation.sort_by(|j, k| f(self.index(*j), self.index(*k))); + + self.apply_index(&permutation); + } + + fn sort_by_key(&mut self, mut f: F) where + F: FnMut(Self::Ref<'_>) -> K, + K: Ord, + { + let mut permutation: Vec = (0..self.len()).collect(); + permutation.sort_by_key(|j| f(self.index(*j))); + + self.apply_index(&permutation); + } + + /// Analogous to [`slice::first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut) + fn first_mut<'c>(&'c mut self) -> Option> { + self.get_mut(0) + } + + /// Analogous to [`slice::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut) + fn last_mut<'c>(&'c mut self) -> Option> { + self.get_mut(self.len().saturating_sub(1)) + } + + /// Obtain a `mut` pointer type for this data + fn as_mut_ptr(&mut self) -> Self::PtrMut; } - /// Obtain a `const` pointer type for this data - fn as_ptr(&self) -> Self::Ptr; + /** + The interface for the `Vec`-like struct-of-arrays type. A generalization of [`SoAMutSlice`] whose methods can + also re-size the underlying arrays. - /// Analogous to [`Vec::as_mut_slice()`] - fn as_mut_slice<'c: 'b, 'b>(&'c mut self) -> Self::SliceMut<'c> where Self: 'b; + **NOTE**: This interface is incomplete and additional methods may be added as needed. + */ + pub trait SoAVec { + type Ref<'t> where Self: 't; + type Slice<'t>: SoASlice where Self:'t; + type Iter<'t>: Iterator> where Self: 't; + type Ptr; - /// Create a mutable slice of this vector matching the given - /// `range`. This is analogous to `IndexMut>`. - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c>; + type RefMut<'t> where Self: 't; + type SliceMut<'t>: SoASliceMut where Self: 't; + type IterMut<'t>: Iterator> where Self: 't; + type PtrMut; - /// Analogous to [`slice::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut) - fn get_mut<'c>(&'c mut self, index: usize) -> Option>; + fn len(&self) -> usize; + fn is_empty(&self) -> bool; + fn as_slice<'c, 'a: 'c>(&'c self) -> Self::Slice<'c> where Self: 'a; - /// Analogous to [`std::ops::IndexMut::index_mut()`] for `usize` - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c>; + /// Create a slice of this vector matching the given `range`. This + /// is analogous to `Index>`. + fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a; - /// Creates a mutable iterator - fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c>; + /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) + fn get<'c>(&'c self, index: usize) -> Option>; - /** Re-order the arrays using the provided indices. This is provided so that generic sorting methods - can be implemented because closure-passing trait methods encounter difficulties with lifetimes. - */ - fn apply_index(&mut self, indices: &[usize]); + /// Analogous to [`std::ops::Index::index()`] for `usize` + fn index<'c>(&'c self, index: usize) -> Self::Ref<'c>; - fn sort_by(&mut self, mut f: F) where F: FnMut(Self::Ref<'_>, Self::Ref<'_>) -> std::cmp::Ordering { - let mut permutation: Vec = (0..self.len()).collect(); - permutation.sort_by(|j, k| f(self.index(*j), self.index(*k))); + /// Create an immutable iterator + fn iter<'c>(&'c self) -> Self::Iter<'c>; - self.apply_index(&permutation); - } + /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) + fn first<'c>(&'c self) -> Option> { + self.get(0) + } - fn sort_by_key(&mut self, mut f: F) where - F: FnMut(Self::Ref<'_>) -> K, - K: Ord, - { - let mut permutation: Vec = (0..self.len()).collect(); - permutation.sort_by_key(|j| f(self.index(*j))); + /// Analogous to [`slice::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last) + fn last<'c>(&'c self) -> Option> { + self.get(self.len().saturating_sub(1)) + } - self.apply_index(&permutation); - } + /// Obtain a `const` pointer type for this data + fn as_ptr(&self) -> Self::Ptr; - /// Analogous to [`slice::first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut) - fn first_mut<'c>(&'c mut self) -> Option> { - self.get_mut(0) - } + /// Analogous to [`Vec::as_mut_slice()`] + fn as_mut_slice<'c, 'a: 'c>(&'c mut self) -> Self::SliceMut<'c> where Self: 'a; - /// Analogous to [`slice::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut) - fn last_mut<'c>(&'c mut self) -> Option> { - self.get_mut(self.len().saturating_sub(1)) - } + /// Create a mutable slice of this vector matching the given + /// `range`. This is analogous to `IndexMut>`. + fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c>; - /// Obtain a `mut` pointer type for this data - fn as_mut_ptr(&mut self) -> Self::PtrMut; -} + /// Analogous to [`slice::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut) + fn get_mut<'c>(&'c mut self, index: usize) -> Option>; -/** - * The interface for the `Vec`-like struct-of-arrays type. A generalization of [`SoAMutSlice`] whose methods can - * also re-size the underlying arrays. - * - * **NOTE**: This interface is incomplete and additional methods may be added as needed. - */ -pub trait SoAVec { - type Ref<'t> where Self: 't; - type Slice<'t>: SoASlice where Self:'t; - type Iter<'t>: Iterator> where Self: 't; - type Ptr; + /// Analogous to [`std::ops::IndexMut::index_mut()`] for `usize` + fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c>; - type RefMut<'t> where Self: 't; - type SliceMut<'t>: SoASliceMut where Self: 't; - type IterMut<'t>: Iterator> where Self: 't; - type PtrMut; + /// Creates a mutable iterator + fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c>; - fn len(&self) -> usize; - fn is_empty(&self) -> bool; - fn as_slice<'c, 'a: 'c>(&'c self) -> Self::Slice<'c> where Self: 'a; + /** Re-order the arrays using the provided indices. This is provided so that generic sorting methods + can be implemented because closure-passing trait methods encounter difficulties with lifetimes. + */ + fn apply_index(&mut self, indices: &[usize]); - /// Create a slice of this vector matching the given `range`. This - /// is analogous to `Index>`. - fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a; + fn sort_by(&mut self, mut f: F) where F: FnMut(Self::Ref<'_>, Self::Ref<'_>) -> std::cmp::Ordering { + let mut permutation: Vec = (0..self.len()).collect(); + permutation.sort_by(|j, k| f(self.index(*j), self.index(*k))); - /// Analogous to [`slice::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get) - fn get<'c>(&'c self, index: usize) -> Option>; + self.apply_index(&permutation); + } - /// Analogous to [`std::ops::Index::index()`] for `usize` - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c>; + fn sort_by_key(&mut self, mut f: F) where + F: FnMut(Self::Ref<'_>) -> K, + K: Ord, + { + let mut permutation: Vec = (0..self.len()).collect(); + permutation.sort_by_key(|j| f(self.index(*j))); - /// Create an immutable iterator - fn iter<'c>(&'c self) -> Self::Iter<'c>; + self.apply_index(&permutation); + } - /// Analogous to [`slice::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first) - fn first<'c>(&'c self) -> Option> { - self.get(0) - } - - /// Analogous to [`slice::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last) - fn last<'c>(&'c self) -> Option> { - self.get(self.len().saturating_sub(1)) - } - - /// Obtain a `const` pointer type for this data - fn as_ptr(&self) -> Self::Ptr; - - /// Analogous to [`Vec::as_mut_slice()`] - fn as_mut_slice<'c, 'a: 'c>(&'c mut self) -> Self::SliceMut<'c> where Self: 'a; - - /// Create a mutable slice of this vector matching the given - /// `range`. This is analogous to `IndexMut>`. - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c>; - - /// Analogous to [`slice::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut) - fn get_mut<'c>(&'c mut self, index: usize) -> Option>; - - /// Analogous to [`std::ops::IndexMut::index_mut()`] for `usize` - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c>; + /// Analogous to [`slice::first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut) + fn first_mut<'c>(&'c mut self) -> Option> { + self.get_mut(0) + } - /// Creates a mutable iterator - fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c>; + /// Analogous to [`slice::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut) + fn last_mut<'c>(&'c mut self) -> Option> { + self.get_mut(self.len().saturating_sub(1)) + } - /** Re-order the arrays using the provided indices. This is provided so that generic sorting methods - can be implemented because closure-passing trait methods encounter difficulties with lifetimes. - */ - fn apply_index(&mut self, indices: &[usize]); + /// Obtain a `mut` pointer type for this data + fn as_mut_ptr(&mut self) -> Self::PtrMut; - fn sort_by(&mut self, mut f: F) where F: FnMut(Self::Ref<'_>, Self::Ref<'_>) -> std::cmp::Ordering { - let mut permutation: Vec = (0..self.len()).collect(); - permutation.sort_by(|j, k| f(self.index(*j), self.index(*k))); + /// Create a new, empty struct of arrays + fn new() -> Self; - self.apply_index(&permutation); - } - - fn sort_by_key(&mut self, mut f: F) where - F: FnMut(Self::Ref<'_>) -> K, - K: Ord, - { - let mut permutation: Vec = (0..self.len()).collect(); - permutation.sort_by_key(|j| f(self.index(*j))); - - self.apply_index(&permutation); - } + /// Create a new, empty struct of arrays with the specified capacity + fn with_capacity(capacity: usize) -> Self; - /// Analogous to [`slice::first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut) - fn first_mut<'c>(&'c mut self) -> Option> { - self.get_mut(0) - } + /// Analogous to [`Vec::capacity`] + fn capacity(&self) -> usize; - /// Analogous to [`slice::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut) - fn last_mut<'c>(&'c mut self) -> Option> { - self.get_mut(self.len().saturating_sub(1)) - } + /// Analogous to [`Vec::reserve`] + fn reserve(&mut self, additional: usize); - /// Obtain a `mut` pointer type for this data - fn as_mut_ptr(&mut self) -> Self::PtrMut; + /// Analogous to [`Vec::reserve_exact`] + fn reserve_exact(&mut self, additional: usize); - /// Create a new, empty struct of arrays - fn new() -> Self; + /// Analogous to [`Vec::shrink_to_fit`] + fn shrink_to_fit(&mut self); - /// Create a new, empty struct of arrays with the specified capacity - fn with_capacity(capacity: usize) -> Self; + /// Analogous to [`Vec::truncate`] + fn truncate(&mut self, len: usize); - /// Analogous to [`Vec::capacity`] - fn capacity(&self) -> usize; + /// Add a singular value of `T` to the arrays. Analogous to [`Vec::push`] + fn push(&mut self, value: T); - /// Analogous to [`Vec::reserve`] - fn reserve(&mut self, additional: usize); + /// Analogous to [`Vec::swap_remove`] + fn swap_remove(&mut self, index: usize) -> T; - /// Analogous to [`Vec::reserve_exact`] - fn reserve_exact(&mut self, additional: usize); + /// Analogous to [`Vec::insert`] + fn insert(&mut self, index: usize, element: T); - /// Analogous to [`Vec::shrink_to_fit`] - fn shrink_to_fit(&mut self); + /// Analogous to [`Vec::replace`] + fn replace(&mut self, index: usize, element: T) -> T; - /// Analogous to [`Vec::truncate`] - fn truncate(&mut self, len: usize); + /// Analogous to [`Vec::remove`] + fn remove(&mut self, index: usize) -> T; - /// Add a singular value of `T` to the arrays. Analogous to [`Vec::push`] - fn push(&mut self, value: T); + /// Analogous to [`Vec::pop`] + fn pop(&mut self) -> Option; - /// Analogous to [`Vec::swap_remove`] - fn swap_remove(&mut self, index: usize) -> T; + /// Analogous to [`Vec::append`] + fn append(&mut self, other: &mut Self); - /// Analogous to [`Vec::insert`] - fn insert(&mut self, index: usize, element: T); + /// Analogous to [`Vec::clear`] + fn clear(&mut self); - /// Analogous to [`Vec::replace`] - fn replace(&mut self, index: usize, element: T) -> T; + /// Analogous to [`Vec::split_off`] + fn split_off(&mut self, at: usize) -> Self; + } +} - /// Analogous to [`Vec::remove`] - fn remove(&mut self, index: usize) -> T; +#[cfg(not(feature = "generic_traits"))] +mod generics { + use super::*; - /// Analogous to [`Vec::pop`] - fn pop(&mut self) -> Option; + /** + The interface for the `Slice` immutable slice struct-of-arrays type. + */ + pub trait SoASlice {} - /// Analogous to [`Vec::append`] - fn append(&mut self, other: &mut Self); + /** + The interface for the `SliceMut` mutable slice struct-of-arrays type. A generalization of [`SoASlice`] + whose methods can modify elements of the arrays + */ + pub trait SoASliceMut {} - /// Analogous to [`Vec::clear`] - fn clear(&mut self); + /** + The interface for the `Vec`-like struct-of-arrays type. A generalization of [`SoAMutSlice`] whose methods can + also re-size the underlying arrays. - /// Analogous to [`Vec::split_off`] - fn split_off(&mut self, at: usize) -> Self; + **NOTE**: This interface is incomplete and additional methods may be added as needed. + */ + pub trait SoAVec {} } +pub use generics::*; /// A collection of supporting traits for [`StructOfArray`] bundled in one place for ease-of-access pub mod prelude { From 498d5de7e4d119edd53eceada796e1f96bc694a2 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Thu, 16 Jan 2025 14:15:02 -0500 Subject: [PATCH 15/37] manage dead code warnings --- .gitignore | 1 + soa-derive-internal/src/generic.rs | 2 +- soa-derive-internal/src/input.rs | 3 ++- soa-derive-internal/src/lib.rs | 1 + soa-derive/Cargo.toml | 2 +- soa-derive/src/lib.rs | 2 +- 6 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index fa8d85a..867b25e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ Cargo.lock target +rust-toolchain.toml \ No newline at end of file diff --git a/soa-derive-internal/src/generic.rs b/soa-derive-internal/src/generic.rs index d316039..9406440 100644 --- a/soa-derive-internal/src/generic.rs +++ b/soa-derive-internal/src/generic.rs @@ -77,7 +77,6 @@ pub fn derive_slice_mut(input: &Input) -> TokenStream { let iter_name = names::iter_name(name); let iter_mut_name = names::iter_mut_name(name); - let generated = quote! { impl<'a> ::soa_derive::SoASliceMut<#name> for #slice_mut_name<'a> { @@ -172,6 +171,7 @@ pub fn derive_slice_mut(input: &Input) -> TokenStream { } } }; + return generated } diff --git a/soa-derive-internal/src/input.rs b/soa-derive-internal/src/input.rs index 983fe7f..0e0cdf6 100644 --- a/soa-derive-internal/src/input.rs +++ b/soa-derive-internal/src/input.rs @@ -18,8 +18,9 @@ pub struct Input { /// Additional attributes requested with `#[soa_attr(...)]` or /// `#[soa_derive()]` pub attrs: ExtraAttributes, + #[allow(unused)] /// Whether or not to generate extra trait implementations that make the SoA types usable - /// in a generic context + /// in a generic context enabled by the `generic_traits` feature. pub generate_traits: bool, } diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index e0b8a74..0c3602a 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -17,6 +17,7 @@ mod ptr; mod refs; mod slice; mod vec; +#[cfg(feature = "generic_traits")] mod generic; pub(crate) mod names; diff --git a/soa-derive/Cargo.toml b/soa-derive/Cargo.toml index c523d74..5960f98 100644 --- a/soa-derive/Cargo.toml +++ b/soa-derive/Cargo.toml @@ -7,7 +7,7 @@ rust-version = "1.63" authors = ["Guillaume Fraux "] license = "MIT/Apache-2.0" -readme = "README.md" +readme = "../README.md" description = "Automatic Struct of Array generation" repository = "https://github.com/lumol-org/soa-derive" homepage = "https://github.com/lumol-org/soa-derive" diff --git a/soa-derive/src/lib.rs b/soa-derive/src/lib.rs index e7fa0b4..c4ec037 100644 --- a/soa-derive/src/lib.rs +++ b/soa-derive/src/lib.rs @@ -242,7 +242,7 @@ pub use permutation::permutation::*; /// `CheeseVec`; This will helpful in generics programing that generate struct /// can be expressed as `::Type` pub trait StructOfArray { - type Type;//: SoAVec where Self: Sized; + type Type; } /// Any struct derived by StructOfArray will auto impl this trait. From f7525255b50bce95f725b7dc1674320ec100f030 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Thu, 16 Jan 2025 15:19:34 -0500 Subject: [PATCH 16/37] docs --- example/Cargo.toml | 2 +- example/lib.rs | 1 + soa-derive/src/lib.rs | 97 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 92 insertions(+), 8 deletions(-) diff --git a/example/Cargo.toml b/example/Cargo.toml index 0ab3799..d93c268 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -8,7 +8,7 @@ publish = false edition = "2021" [dependencies] -soa_derive = {path = "../soa-derive"} +soa_derive = { path = "../soa-derive", features = ["generic_traits"]} [lib] path = "lib.rs" diff --git a/example/lib.rs b/example/lib.rs index 8921758..566fca9 100644 --- a/example/lib.rs +++ b/example/lib.rs @@ -44,6 +44,7 @@ extern crate soa_derive; /// A basic Particle type #[derive(Debug, PartialEq, StructOfArray)] #[soa_derive(Debug, PartialEq)] +#[generate_traits] pub struct Particle { /// Mass of the particle pub mass: f64, diff --git a/soa-derive/src/lib.rs b/soa-derive/src/lib.rs index c4ec037..4e4b3c7 100644 --- a/soa-derive/src/lib.rs +++ b/soa-derive/src/lib.rs @@ -226,6 +226,35 @@ //! ``` //! //! All helper structs will be also nested, for example `PointSlice` will be nested in `ParticleSlice`. +//! +//! # Use in a generic context +//! +//! `StructOfArray` does not provide a set of common operations by default. Thus if you wanted to use a `StructOfArray` +//! type in a generic context, there is no way to guarantee to the type system that any methods are available. +//! +//! If the `generic_traits` feature is enabled, the attribute macro `#[generate_traits]` will generate +//! implementations of [`SoAVec`], [`SoASlice`], and [`SoASliceMut`] for the respective `Vec`, `Slice` +//! and `SliceMut` types. +//! +//! These rely on GATs, and so require Rust 1.65 or newer, and so this feature is disabled by default. +//! Even when enabled, trait implementations are only generated by opting in with the `#[generate_traits]` +//! attribute. +//! +//! ```no_run +//! # mod cheese { +//! # use soa_derive::{StructOfArray, prelude::*}; +//! #[derive(StructOfArray)] +//! #[generate_traits] +//! pub struct Point { +//! x: f32, +//! y: f32, +//! } +//! +//! fn get_num_items>(values: &V) -> usize { +//! values.len() +//! } +//! # } +//! ``` // The proc macro is implemented in soa_derive_internal, and re-exported by this // crate. This is because a single crate can not define both a proc macro and a @@ -400,13 +429,25 @@ mod generics { The interface for the `Slice` immutable slice struct-of-arrays type. */ pub trait SoASlice { + /// The type that elements will be proxied with as type Ref<'t> where Self: 't; + + /// The type representing immutable slices of elements type Slice<'t>: SoASlice where Self: 't; + + /// The type used for iteration over [`Self::Ref`] type Iter<'t>: Iterator> where Self: 't; + + /// The raw pointer type interface type Ptr; + /// Returns the number of elements in the arrays fn len(&self) -> usize; + + /// Returns true if the arrays has a length of 0. fn is_empty(&self) -> bool; + + /// Create an immutable slice of the arrays fn as_slice<'c>(&'c self) -> Self::Slice<'c>; /// Create a slice of this vector matching the given `range`. This @@ -441,18 +482,37 @@ mod generics { whose methods can modify elements of the arrays */ pub trait SoASliceMut { + /// The type that elements will be proxied with as type Ref<'t> where Self: 't; + + /// The type representing immutable slices of elements type Slice<'t>: SoASlice where Self: 't; + + /// The type used for iteration over [`Self::Ref`] type Iter<'t>: Iterator> where Self: 't; + + /// The const pointer type interface type Ptr; + /// The type that elements will be proxied with as when mutable type RefMut<'t> where Self: 't; + + /// The type representing mutable slices of elements type SliceMut<'t>: SoASliceMut where Self: 't; + + /// The type used for iteration over [`Self::RefMut`] type IterMut<'t>: Iterator> where Self: 't; + + /// The mut pointer type interface type PtrMut; + /// Returns the number of elements in the arrays fn len(&self) -> usize; + + /// Returns true if the arrays has a length of 0. fn is_empty(&self) -> bool; + + /// Create an immutable slice of the arrays fn as_slice<'c>(&'c self) -> Self::Slice<'c>; /// Create a slice of this vector matching the given `range`. This @@ -502,6 +562,7 @@ mod generics { */ fn apply_index(&mut self, indices: &[usize]); + /// `[slice::sort_by()`](). fn sort_by(&mut self, mut f: F) where F: FnMut(Self::Ref<'_>, Self::Ref<'_>) -> std::cmp::Ordering { let mut permutation: Vec = (0..self.len()).collect(); permutation.sort_by(|j, k| f(self.index(*j), self.index(*k))); @@ -509,6 +570,7 @@ mod generics { self.apply_index(&permutation); } + /// `[slice::sort_by()`](). fn sort_by_key(&mut self, mut f: F) where F: FnMut(Self::Ref<'_>) -> K, K: Ord, @@ -519,12 +581,12 @@ mod generics { self.apply_index(&permutation); } - /// Analogous to [`slice::first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut) + /// Analogous to [`slice::first_mut()`](). fn first_mut<'c>(&'c mut self) -> Option> { self.get_mut(0) } - /// Analogous to [`slice::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut) + /// Analogous to [`slice::last_mut()`](). fn last_mut<'c>(&'c mut self) -> Option> { self.get_mut(self.len().saturating_sub(1)) } @@ -534,24 +596,43 @@ mod generics { } /** - The interface for the `Vec`-like struct-of-arrays type. A generalization of [`SoAMutSlice`] whose methods can + The interface for the `Vec`-like struct-of-arrays type. A generalization of [`SoASliceMut`] whose methods can also re-size the underlying arrays. **NOTE**: This interface is incomplete and additional methods may be added as needed. */ pub trait SoAVec { + /// The type that elements will be proxied with as type Ref<'t> where Self: 't; - type Slice<'t>: SoASlice where Self:'t; + + /// The type representing immutable slices of elements + type Slice<'t>: SoASlice where Self: 't; + + /// The type used for iteration over [`Self::Ref`] type Iter<'t>: Iterator> where Self: 't; + + /// The const pointer type interface type Ptr; + /// The type that elements will be proxied with as when mutable type RefMut<'t> where Self: 't; + + /// The type representing mutable slices of elements type SliceMut<'t>: SoASliceMut where Self: 't; + + /// The type used for iteration over [`Self::RefMut`] type IterMut<'t>: Iterator> where Self: 't; + + /// The mut pointer type interface type PtrMut; + /// Returns the number of elements in the arrays fn len(&self) -> usize; + + /// Returns true if the arrays has a length of 0. fn is_empty(&self) -> bool; + + /// Create an immutable slice of the arrays fn as_slice<'c, 'a: 'c>(&'c self) -> Self::Slice<'c> where Self: 'a; /// Create a slice of this vector matching the given `range`. This @@ -601,6 +682,7 @@ mod generics { */ fn apply_index(&mut self, indices: &[usize]); + /// `[slice::sort_by()`](). fn sort_by(&mut self, mut f: F) where F: FnMut(Self::Ref<'_>, Self::Ref<'_>) -> std::cmp::Ordering { let mut permutation: Vec = (0..self.len()).collect(); permutation.sort_by(|j, k| f(self.index(*j), self.index(*k))); @@ -608,6 +690,7 @@ mod generics { self.apply_index(&permutation); } + /// `[slice::sort_by()`](). fn sort_by_key(&mut self, mut f: F) where F: FnMut(Self::Ref<'_>) -> K, K: Ord, @@ -618,12 +701,12 @@ mod generics { self.apply_index(&permutation); } - /// Analogous to [`slice::first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut) + /// Analogous to [`slice::first_mut()`]() fn first_mut<'c>(&'c mut self) -> Option> { self.get_mut(0) } - /// Analogous to [`slice::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut) + /// Analogous to [`slice::last_mut()`]() fn last_mut<'c>(&'c mut self) -> Option> { self.get_mut(self.len().saturating_sub(1)) } @@ -661,7 +744,7 @@ mod generics { /// Analogous to [`Vec::insert`] fn insert(&mut self, index: usize, element: T); - /// Analogous to [`Vec::replace`] + /// Similar to [`std::mem::replace()`](https://doc.rust-lang.org/std/mem/fn.replace.html). fn replace(&mut self, index: usize, element: T) -> T; /// Analogous to [`Vec::remove`] From ad073f797600642aaf70b562ff80f10dd9cb4ca5 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Thu, 16 Jan 2025 15:40:07 -0500 Subject: [PATCH 17/37] Remove commented out impl --- soa-derive-internal/src/vec.rs | 159 --------------------------------- 1 file changed, 159 deletions(-) diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index 502c96c..62b5b30 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -450,165 +450,6 @@ pub fn derive(input: &Input) -> TokenStream { } } - /* - impl ::soa_derive::SoAVec<#name> for #vec_name { - type Ref<'t> = #ref_name<'t>; - type Slice<'t> = #slice_name<'t>; - type Iter<'t> = #iter_name<'t>; - type Ptr = #ptr_name; - - type RefMut<'t> = #ref_mut_name<'t>; - type SliceMut<'t> = #slice_mut_name<'t>; - type IterMut<'t> = #iter_mut_name<'t>; - type PtrMut = #ptr_mut_name; - - fn len(&self) -> usize { - self.len() - } - - fn is_empty(&self) -> bool { - self.is_empty() - } - - fn as_slice<'c, 'a: 'c>(&'c self) -> Self::Slice<'c> where Self: 'a { - self.as_slice() - } - - fn slice<'c, 'a: 'c>(&'c self, index: impl core::ops::RangeBounds) -> Self::Slice<'c> where Self: 'a { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index(start..end) - } - - fn get<'c>(&'c self, index: usize) -> Option> { - self.get(index) - } - - fn index<'c>(&'c self, index: usize) -> Self::Ref<'c> { - self.index(index) - } - - fn iter<'c>(&'c self) -> Self::Iter<'c> { - self.iter() - } - - fn as_mut_slice<'c, 'a: 'c>(&'c mut self) -> Self::SliceMut<'c> where Self: 'a { - self.as_mut_slice() - } - - fn slice_mut<'c>(&'c mut self, index: impl core::ops::RangeBounds) -> Self::SliceMut<'c> { - let start = match index.start_bound() { - std::ops::Bound::Included(i) | std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => 0, - }; - let n = self.len(); - let end = match index.end_bound() { - std::ops::Bound::Included(i) => (*i + 1).min(n), - std::ops::Bound::Excluded(i) => *i, - std::ops::Bound::Unbounded => n, - }; - self.index_mut(start..end) - } - - fn get_mut<'c>(&'c mut self, index: usize) -> Option> { - self.get_mut(index) - } - - fn index_mut<'c>(&'c mut self, index: usize) -> Self::RefMut<'c> { - self.index_mut(index) - } - - fn iter_mut<'c>(&'c mut self) -> Self::IterMut<'c> { - self.iter_mut() - } - - fn apply_index(&mut self, indices: &[usize]) { - use ::soa_derive::SoASliceMut; - self.as_mut_slice().apply_index(indices); - } - - fn new() -> Self { - Self::new() - } - - fn with_capacity(capacity: usize) -> Self { - Self::with_capacity(capacity) - } - - fn capacity(&self) -> usize { - self.capacity() - } - - fn reserve(&mut self, additional: usize) { - self.reserve(additional); - } - - fn reserve_exact(&mut self, additional: usize) { - self.reserve_exact(additional); - } - - fn shrink_to_fit(&mut self) { - self.shrink_to_fit(); - } - - fn truncate(&mut self, len: usize) { - self.truncate(len); - } - - fn push(&mut self, value: #name) { - self.push(value); - } - - fn swap_remove(&mut self, index: usize) -> #name { - self.swap_remove(index) - } - - fn insert(&mut self, index: usize, element: #name) { - self.insert(index, element); - } - - fn replace(&mut self, index: usize, element: #name) -> #name { - self.replace(index, element) - } - - fn remove(&mut self, index: usize) -> #name { - self.remove(index) - } - - fn pop(&mut self) -> Option<#name> { - self.pop() - } - - fn append(&mut self, other: &mut Self) { - self.append(other); - } - - fn clear(&mut self) { - self.clear(); - } - - fn split_off(&mut self, at: usize) -> Self { - self.split_off(at) - } - - fn as_ptr(&self) -> Self::Ptr { - self.as_ptr() - } - - fn as_mut_ptr(&mut self) -> Self::PtrMut { - self.as_mut_ptr() - } - } - */ - #[allow(clippy::drop_non_drop)] impl Drop for #vec_name { fn drop(&mut self) { From 3cc69fd89d0bfa36217295a066207988fa6bb44a Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Thu, 16 Jan 2025 16:30:01 -0500 Subject: [PATCH 18/37] remove traits from example --- example/Cargo.toml | 2 +- example/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/example/Cargo.toml b/example/Cargo.toml index d93c268..9ffccad 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -8,7 +8,7 @@ publish = false edition = "2021" [dependencies] -soa_derive = { path = "../soa-derive", features = ["generic_traits"]} +soa_derive = { path = "../soa-derive", features = []} [lib] path = "lib.rs" diff --git a/example/lib.rs b/example/lib.rs index 566fca9..8921758 100644 --- a/example/lib.rs +++ b/example/lib.rs @@ -44,7 +44,6 @@ extern crate soa_derive; /// A basic Particle type #[derive(Debug, PartialEq, StructOfArray)] #[soa_derive(Debug, PartialEq)] -#[generate_traits] pub struct Particle { /// Mass of the particle pub mass: f64, From 8db660b9ebef1d89b8de08ea3a1823aed814ad4c Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Thu, 16 Jan 2025 16:54:46 -0500 Subject: [PATCH 19/37] exclude doctest --- soa-derive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soa-derive/src/lib.rs b/soa-derive/src/lib.rs index 4e4b3c7..a15df10 100644 --- a/soa-derive/src/lib.rs +++ b/soa-derive/src/lib.rs @@ -240,7 +240,7 @@ //! Even when enabled, trait implementations are only generated by opting in with the `#[generate_traits]` //! attribute. //! -//! ```no_run +//! ```ignore //! # mod cheese { //! # use soa_derive::{StructOfArray, prelude::*}; //! #[derive(StructOfArray)] From 3aecfd05533396cce3abd1a6a1c4f576bda7cb0d Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Fri, 17 Jan 2025 23:16:45 -0500 Subject: [PATCH 20/37] add supporting traits for `to_vec` and `into_iter` --- soa-derive-internal/src/iter.rs | 13 ++++++++- soa-derive-internal/src/slice.rs | 24 +++++++++++++++++ soa-derive-internal/src/vec.rs | 12 +++++++++ soa-derive/src/lib.rs | 45 ++++++++++++++++++++++++++----- soa-derive/tests/particles/mod.rs | 7 ++--- 5 files changed, 90 insertions(+), 11 deletions(-) diff --git a/soa-derive-internal/src/iter.rs b/soa-derive-internal/src/iter.rs index 00ea08a..919e667 100644 --- a/soa-derive-internal/src/iter.rs +++ b/soa-derive-internal/src/iter.rs @@ -1,5 +1,6 @@ use proc_macro2::TokenStream; use quote::quote; +use quote::TokenStreamExt; use crate::input::{Input, TokenStreamIterator}; use crate::names; @@ -79,7 +80,7 @@ pub fn derive(input: &Input) -> TokenStream { } }).expect("should be Some"); - return quote! { + let mut generated = quote! { /// Iterator over #[doc = #doc_url] #[allow(missing_debug_implementations)] @@ -297,4 +298,14 @@ pub fn derive(input: &Input) -> TokenStream { } } }; + + if input.generate_traits { + generated.append_all(quote! { + + impl<'a> ::soa_derive::IntoSoAIter<'a, #name> for #slice_name<'a> {} + + }) + } + + return generated; } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index aea7636..48ad75d 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -254,6 +254,18 @@ pub fn derive(input: &Input) -> TokenStream { } } }); + + if input.generate_traits { + generated.append_all(quote! { + impl<'a> ::soa_derive::ToSoAVec<#name> for #slice_name<'a> { + type SoAVecType = #vec_name; + + fn to_vec(&self) -> Self::SoAVecType { + self.to_vec() + } + } + }); + } } return generated; @@ -684,6 +696,18 @@ pub fn derive_mut(input: &Input) -> TokenStream { } } }); + + if input.generate_traits { + generated.append_all(quote! { + impl<'a> ::soa_derive::ToSoAVec<#name> for #slice_mut_name<'a> { + type SoAVecType = #vec_name; + + fn to_vec(&self) -> Self::SoAVecType { + self.to_vec() + } + } + }); + } } return generated; diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index 62b5b30..1e7aafb 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -474,6 +474,18 @@ pub fn derive(input: &Input) -> TokenStream { } } }); + + if input.generate_traits { + generated.append_all(quote! { + impl ::soa_derive::SoAAppendVec<#name> for #vec_name { + fn extend_from_slice(&mut self, other: Self::Slice<'_>) { + #( + self.#fields_names.extend_from_slice(other.#fields_names); + )* + } + } + }) + } } return generated; diff --git a/soa-derive/src/lib.rs b/soa-derive/src/lib.rs index a15df10..0d5e37e 100644 --- a/soa-derive/src/lib.rs +++ b/soa-derive/src/lib.rs @@ -428,12 +428,12 @@ mod generics { /** The interface for the `Slice` immutable slice struct-of-arrays type. */ - pub trait SoASlice { + pub trait SoASlice { /// The type that elements will be proxied with as type Ref<'t> where Self: 't; /// The type representing immutable slices of elements - type Slice<'t>: SoASlice where Self: 't; + type Slice<'t>: SoASlice = Self::Ref<'t>> + IntoSoAIter<'t, T, Ref<'t> = Self::Ref<'t>> where Self: 't; /// The type used for iteration over [`Self::Ref`] type Iter<'t>: Iterator> where Self: 't; @@ -486,7 +486,7 @@ mod generics { type Ref<'t> where Self: 't; /// The type representing immutable slices of elements - type Slice<'t>: SoASlice where Self: 't; + type Slice<'t>: SoASlice = Self::Ref<'t>> + IntoSoAIter<'t, T, Ref<'t> = Self::Ref<'t>> where Self: 't; /// The type used for iteration over [`Self::Ref`] type Iter<'t>: Iterator> where Self: 't; @@ -596,7 +596,7 @@ mod generics { } /** - The interface for the `Vec`-like struct-of-arrays type. A generalization of [`SoASliceMut`] whose methods can + The interface for the `Vec`-like struct-of-arrays type. A generalization of [`SoASliceMut`] whose methods can also re-size the underlying arrays. **NOTE**: This interface is incomplete and additional methods may be added as needed. @@ -606,7 +606,7 @@ mod generics { type Ref<'t> where Self: 't; /// The type representing immutable slices of elements - type Slice<'t>: SoASlice where Self: 't; + type Slice<'t>: SoASlice = Self::Ref<'t>> + IntoSoAIter<'t, T> where Self: 't; /// The type used for iteration over [`Self::Ref`] type Iter<'t>: Iterator> where Self: 't; @@ -762,6 +762,26 @@ mod generics { /// Analogous to [`Vec::split_off`] fn split_off(&mut self, at: usize) -> Self; } + + /// A trait to implement `Clone`-dependent behavior to convert a non-owning SoA type into an + /// owning [`SoAVec`]. + pub trait ToSoAVec { + type SoAVecType: SoAVec; + + /// Similar to [`slice::to_vec()`](https://doc.rust-lang.org/std/primitive.slice.html#method.to_vec) + fn to_vec(&self) -> Self::SoAVecType; + } + + /// A trait to implement `Clone`-dependent behavior to extend an [`SoAVec`] with data copied + /// from its associated `Slice` type. + pub trait SoAAppendVec: SoAVec { + + /// Analogous to [`Vec::extend_from_slice`] + fn extend_from_slice(&mut self, other: Self::Slice<'_>); + } + + /// A trait to express the [`IntoIterator`] guarantee of [`SoASlice`] types in the type system. + pub trait IntoSoAIter<'a, T: StructOfArray>: SoASlice + IntoIterator> + 'a {} } #[cfg(not(feature = "generic_traits"))] @@ -780,19 +800,30 @@ mod generics { pub trait SoASliceMut {} /** - The interface for the `Vec`-like struct-of-arrays type. A generalization of [`SoAMutSlice`] whose methods can + The interface for the `Vec`-like struct-of-arrays type. A generalization of [`SoAMutSlice`] whose methods can also re-size the underlying arrays. **NOTE**: This interface is incomplete and additional methods may be added as needed. */ pub trait SoAVec {} + + /// A trait to implement `Clone`-dependent behavior to convert a non-owning SoA type into an + /// owning [`SoAVec`]. + pub trait ToSoAVec {} + + /// A trait to implement `Clone`-dependent behavior to extend an [`SoAVec`] with data copied + /// from its associated `Slice` type. + pub trait SoAAppendVec: SoAVec {} + + /// A trait to express the [`IntoIterator`] guarantee of [`SoASlice`] types in the type system. + pub trait IntoSoAIter<'a, T: StructOfArray> {} } pub use generics::*; /// A collection of supporting traits for [`StructOfArray`] bundled in one place for ease-of-access pub mod prelude { - pub use super::{SoAVec, SoAIter, SoASlice, SoASliceMut, SoAPointers, StructOfArray}; + pub use super::{SoAVec, SoAIter, SoASlice, SoASliceMut, SoAPointers, StructOfArray, ToSoAVec, IntoSoAIter}; } diff --git a/soa-derive/tests/particles/mod.rs b/soa-derive/tests/particles/mod.rs index 66e12f5..5c65864 100644 --- a/soa-derive/tests/particles/mod.rs +++ b/soa-derive/tests/particles/mod.rs @@ -50,10 +50,11 @@ mod impls { }) } - fn slice_ref_len<'a, T: StructOfArray, V: SoAVec>(vec: &V) -> usize where for<'t> <>::Slice<'t> as SoASlice>::Ref<'t>: PartialOrd { + fn slice_ref_len<'a, T: StructOfArray, V: SoAVec>(vec: &V) -> usize { let view = vec.as_slice(); - // let _ = iter_max_generic_slice(&view); - view.iter().count() + let n = view.iter().count(); + assert_eq!(view.into_iter().count(), n); + n } pub struct VWrap> { From f200fa0c8b72ce19c559dcad94cb6171e6b6212f Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sat, 18 Jan 2025 11:52:28 -0500 Subject: [PATCH 21/37] undo bundling, introduces problematic lifetime net --- soa-derive/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/soa-derive/src/lib.rs b/soa-derive/src/lib.rs index 0d5e37e..3a1fe2d 100644 --- a/soa-derive/src/lib.rs +++ b/soa-derive/src/lib.rs @@ -433,7 +433,7 @@ mod generics { type Ref<'t> where Self: 't; /// The type representing immutable slices of elements - type Slice<'t>: SoASlice = Self::Ref<'t>> + IntoSoAIter<'t, T, Ref<'t> = Self::Ref<'t>> where Self: 't; + type Slice<'t>: SoASlice + IntoSoAIter<'t, T, Ref<'t> = Self::Ref<'t>> where Self: 't; /// The type used for iteration over [`Self::Ref`] type Iter<'t>: Iterator> where Self: 't; @@ -486,7 +486,7 @@ mod generics { type Ref<'t> where Self: 't; /// The type representing immutable slices of elements - type Slice<'t>: SoASlice = Self::Ref<'t>> + IntoSoAIter<'t, T, Ref<'t> = Self::Ref<'t>> where Self: 't; + type Slice<'t>: SoASlice + IntoSoAIter<'t, T, Ref<'t> = Self::Ref<'t>> where Self: 't; /// The type used for iteration over [`Self::Ref`] type Iter<'t>: Iterator> where Self: 't; @@ -606,7 +606,7 @@ mod generics { type Ref<'t> where Self: 't; /// The type representing immutable slices of elements - type Slice<'t>: SoASlice = Self::Ref<'t>> + IntoSoAIter<'t, T> where Self: 't; + type Slice<'t>: SoASlice + IntoSoAIter<'t, T> where Self: 't; /// The type used for iteration over [`Self::Ref`] type Iter<'t>: Iterator> where Self: 't; @@ -823,7 +823,7 @@ pub use generics::*; /// A collection of supporting traits for [`StructOfArray`] bundled in one place for ease-of-access pub mod prelude { - pub use super::{SoAVec, SoAIter, SoASlice, SoASliceMut, SoAPointers, StructOfArray, ToSoAVec, IntoSoAIter}; + pub use super::{SoAVec, SoAIter, SoASlice, SoASliceMut, SoAPointers, StructOfArray, ToSoAVec, IntoSoAIter, SoAAppendVec}; } From 8fdcb3a150d86077a6dda36c782ba8ea91eefdd2 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sun, 26 Jan 2025 22:06:45 -0500 Subject: [PATCH 22/37] feature: add `soa_crate` type-level attribute for vendoring --- soa-derive-internal/src/generic.rs | 13 ++++--- soa-derive-internal/src/index.rs | 57 +++++++++++++++--------------- soa-derive-internal/src/input.rs | 15 ++++++-- soa-derive-internal/src/iter.rs | 17 ++++----- soa-derive-internal/src/lib.rs | 4 +-- soa-derive-internal/src/ptr.rs | 3 +- soa-derive-internal/src/slice.rs | 24 +++++++------ soa-derive-internal/src/vec.rs | 15 ++++---- soa-derive/tests/particles/mod.rs | 1 + 9 files changed, 85 insertions(+), 64 deletions(-) diff --git a/soa-derive-internal/src/generic.rs b/soa-derive-internal/src/generic.rs index 9406440..924e28e 100644 --- a/soa-derive-internal/src/generic.rs +++ b/soa-derive-internal/src/generic.rs @@ -11,9 +11,10 @@ pub fn derive_slice(input: &Input) -> TokenStream { let ref_name = names::ref_name(&input.name); let ptr_name = names::ptr_name(&input.name); let iter_name = names::iter_name(name); + let crate_name = &input.soa_crate; let generated = quote! { - impl<'a> ::soa_derive::SoASlice<#name> for #slice_name<'a> { + impl<'a> #crate_name::SoASlice<#name> for #slice_name<'a> { type Ref<'t> = #ref_name<'t> where Self: 't, 'a: 't; type Slice<'t> = #slice_name<'t> where Self: 't, 'a: 't; type Iter<'t> = #iter_name<'t> where Self: 't, 'a: 't; @@ -76,10 +77,11 @@ pub fn derive_slice_mut(input: &Input) -> TokenStream { let ptr_mut_name = names::ptr_mut_name(&input.name); let iter_name = names::iter_name(name); let iter_mut_name = names::iter_mut_name(name); + let crate_name = &input.soa_crate; let generated = quote! { - impl<'a> ::soa_derive::SoASliceMut<#name> for #slice_mut_name<'a> { + impl<'a> #crate_name::SoASliceMut<#name> for #slice_mut_name<'a> { type Ref<'t> = #ref_name<'t> where Self: 't; type Slice<'t> = #slice_name<'t> where Self: 't; type Iter<'t> = #iter_name<'t> where Self: 't; @@ -159,7 +161,7 @@ pub fn derive_slice_mut(input: &Input) -> TokenStream { } fn apply_index(&mut self, indices: &[usize]) { - self.apply_permutation(&mut ::soa_derive::Permutation::oneline(indices).inverse()); + self.apply_permutation(&mut #crate_name::Permutation::oneline(indices).inverse()); } fn as_ptr(&self) -> Self::Ptr { @@ -186,10 +188,11 @@ pub fn derive_vec(input: &Input) -> TokenStream { let ptr_mut_name = names::ptr_mut_name(&input.name); let iter_name = names::iter_name(name); let iter_mut_name = names::iter_mut_name(name); + let crate_name = &input.soa_crate; let generated = quote! { - impl ::soa_derive::SoAVec<#name> for #vec_name { + impl #crate_name::SoAVec<#name> for #vec_name { type Ref<'t> = #ref_name<'t>; type Slice<'t> = #slice_name<'t>; type Iter<'t> = #iter_name<'t>; @@ -269,7 +272,7 @@ pub fn derive_vec(input: &Input) -> TokenStream { } fn apply_index(&mut self, indices: &[usize]) { - use ::soa_derive::SoASliceMut; + use #crate_name::SoASliceMut; self.as_mut_slice().apply_index(indices); } diff --git a/soa-derive-internal/src/index.rs b/soa-derive-internal/src/index.rs index 0a685b1..ab76416 100644 --- a/soa-derive-internal/src/index.rs +++ b/soa-derive-internal/src/index.rs @@ -11,6 +11,7 @@ pub fn derive(input: &Input) -> TokenStream { let slice_mut_name = names::slice_mut_name(&input.name); let ref_name = names::ref_name(&input.name); let ref_mut_name = names::ref_mut_name(&input.name); + let crate_name = &input.soa_crate; let fields_names = &input.fields.iter() .map(|field| field.ident.clone().unwrap()) @@ -40,7 +41,7 @@ pub fn derive(input: &Input) -> TokenStream { quote!{ // usize - impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for usize { + impl<'a> #crate_name::SoAIndex<&'a #vec_name> for usize { type RefOutput = #ref_name<'a>; #[inline] @@ -63,7 +64,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for usize { + impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for usize { type MutOutput = #ref_mut_name<'a>; #[inline] @@ -89,7 +90,7 @@ pub fn derive(input: &Input) -> TokenStream { // Range - impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for ::std::ops::Range { + impl<'a> #crate_name::SoAIndex<&'a #vec_name> for ::std::ops::Range { type RefOutput = #slice_name<'a>; #[inline] @@ -112,7 +113,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for ::std::ops::Range { + impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for ::std::ops::Range { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -136,7 +137,7 @@ pub fn derive(input: &Input) -> TokenStream { } // RangeTo - impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for ::std::ops::RangeTo { + impl<'a> #crate_name::SoAIndex<&'a #vec_name> for ::std::ops::RangeTo { type RefOutput = #slice_name<'a>; #[inline] @@ -155,7 +156,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeTo { + impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeTo { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -175,7 +176,7 @@ pub fn derive(input: &Input) -> TokenStream { } // RangeFrom - impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for ::std::ops::RangeFrom { + impl<'a> #crate_name::SoAIndex<&'a #vec_name> for ::std::ops::RangeFrom { type RefOutput = #slice_name<'a>; #[inline] @@ -194,7 +195,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeFrom { + impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeFrom { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -214,7 +215,7 @@ pub fn derive(input: &Input) -> TokenStream { } // RangeFull - impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for ::std::ops::RangeFull { + impl<'a> #crate_name::SoAIndex<&'a #vec_name> for ::std::ops::RangeFull { type RefOutput = #slice_name<'a>; #[inline] @@ -233,7 +234,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeFull { + impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeFull { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -253,7 +254,7 @@ pub fn derive(input: &Input) -> TokenStream { } // RangeInclusive - impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for ::std::ops::RangeInclusive { + impl<'a> #crate_name::SoAIndex<&'a #vec_name> for ::std::ops::RangeInclusive { type RefOutput = #slice_name<'a>; #[inline] @@ -276,7 +277,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeInclusive { + impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeInclusive { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -300,7 +301,7 @@ pub fn derive(input: &Input) -> TokenStream { } // RangeToInclusive - impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for ::std::ops::RangeToInclusive { + impl<'a> #crate_name::SoAIndex<&'a #vec_name> for ::std::ops::RangeToInclusive { type RefOutput = #slice_name<'a>; #[inline] @@ -319,7 +320,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeToInclusive { + impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeToInclusive { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -339,7 +340,7 @@ pub fn derive(input: &Input) -> TokenStream { } // usize - impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for usize { + impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for usize { type RefOutput = #ref_name<'a>; #[inline] @@ -366,7 +367,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for usize { + impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for usize { type MutOutput = #ref_mut_name<'a>; #[inline] @@ -396,7 +397,7 @@ pub fn derive(input: &Input) -> TokenStream { // Range - impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for ::std::ops::Range { + impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for ::std::ops::Range { type RefOutput = #slice_name<'a>; #[inline] @@ -423,7 +424,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::Range { + impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::Range { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -453,7 +454,7 @@ pub fn derive(input: &Input) -> TokenStream { // RangeTo - impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for ::std::ops::RangeTo { + impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for ::std::ops::RangeTo { type RefOutput = #slice_name<'a>; #[inline] @@ -472,7 +473,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeTo { + impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeTo { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -493,7 +494,7 @@ pub fn derive(input: &Input) -> TokenStream { // RangeFrom - impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for ::std::ops::RangeFrom { + impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for ::std::ops::RangeFrom { type RefOutput = #slice_name<'a>; #[inline] @@ -512,7 +513,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeFrom { + impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeFrom { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -533,7 +534,7 @@ pub fn derive(input: &Input) -> TokenStream { // RangeFull - impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for ::std::ops::RangeFull { + impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for ::std::ops::RangeFull { type RefOutput = #slice_name<'a>; #[inline] @@ -552,7 +553,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeFull { + impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeFull { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -573,7 +574,7 @@ pub fn derive(input: &Input) -> TokenStream { // RangeInclusive - impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for ::std::ops::RangeInclusive { + impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for ::std::ops::RangeInclusive { type RefOutput = #slice_name<'a>; #[inline] @@ -596,7 +597,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeInclusive { + impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeInclusive { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -621,7 +622,7 @@ pub fn derive(input: &Input) -> TokenStream { // RangeToInclusive - impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for ::std::ops::RangeToInclusive { + impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for ::std::ops::RangeToInclusive { type RefOutput = #slice_name<'a>; #[inline] @@ -640,7 +641,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeToInclusive { + impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeToInclusive { type MutOutput = #slice_mut_name<'a>; #[inline] diff --git a/soa-derive-internal/src/input.rs b/soa-derive-internal/src/input.rs index 0e0cdf6..70d561e 100644 --- a/soa-derive-internal/src/input.rs +++ b/soa-derive-internal/src/input.rs @@ -2,7 +2,7 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::punctuated::Punctuated; -use syn::{Attribute, Data, DeriveInput, Field, Path, Visibility, Token}; +use syn::{Attribute, Data, DeriveInput, Field, Path, Token, Visibility}; use syn::{Meta, MetaList}; /// Representing the struct we are deriving @@ -18,10 +18,14 @@ pub struct Input { /// Additional attributes requested with `#[soa_attr(...)]` or /// `#[soa_derive()]` pub attrs: ExtraAttributes, - #[allow(unused)] + /// Whether or not to generate extra trait implementations that make the SoA types usable /// in a generic context enabled by the `generic_traits` feature. pub generate_traits: bool, + + /// The path to import the `soa_derive` crate from, in case the library is vendored or + /// internalized. + pub soa_crate: syn::Path, } pub struct ExtraAttributes { @@ -114,6 +118,7 @@ impl Input { let mut extra_attrs = ExtraAttributes::new(); let mut generate_traits: bool = false; + let mut soa_derive_crate: Option = Some(syn::parse_str("::soa_derive").unwrap()); for attr in input.attrs { if attr.path().is_ident("soa_derive") { @@ -172,6 +177,11 @@ impl Input { if attr.path().is_ident("generate_traits") { generate_traits = true; } + + if attr.path().is_ident("soa_crate") { + let args = attr.parse_args::().expect("expected an attribute like a path"); + soa_derive_crate = Some(args); + } } Input { @@ -181,6 +191,7 @@ impl Input { attrs: extra_attrs, field_is_nested, generate_traits: generate_traits, + soa_crate: soa_derive_crate.unwrap(), } } diff --git a/soa-derive-internal/src/iter.rs b/soa-derive-internal/src/iter.rs index 919e667..faebce2 100644 --- a/soa-derive-internal/src/iter.rs +++ b/soa-derive-internal/src/iter.rs @@ -15,6 +15,7 @@ pub fn derive(input: &Input) -> TokenStream { let ref_mut_name = names::ref_mut_name(&input.name); let iter_name = names::iter_name(&input.name); let iter_mut_name = names::iter_mut_name(&input.name); + let crate_name = &input.soa_crate; let doc_url = format!("[`{0}`](struct.{0}.html)", name); let ref_doc_url = format!("[`{0}`](struct.{0}.html)", ref_name); @@ -125,7 +126,7 @@ pub fn derive(input: &Input) -> TokenStream { /// Get an iterator over the #[doc = #ref_doc_url] /// in this vector - pub fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { + pub fn iter(&self) -> <#name as #crate_name::SoAIter>::Iter { self.as_slice().into_iter() } } @@ -134,14 +135,14 @@ pub fn derive(input: &Input) -> TokenStream { /// Get an iterator over the #[doc = #ref_doc_url] /// in this slice. - pub fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { + pub fn iter(&self) -> <#name as #crate_name::SoAIter>::Iter { #iter_name(#create_iter) } /// Get an iterator over the #[doc = #ref_doc_url] /// in this slice. - pub fn into_iter(self) -> <#name as ::soa_derive::SoAIter<'a>>::Iter { + pub fn into_iter(self) -> <#name as #crate_name::SoAIter<'a>>::Iter { #iter_name(#create_into_iter) } } @@ -189,7 +190,7 @@ pub fn derive(input: &Input) -> TokenStream { /// Get a mutable iterator over the #[doc = #ref_mut_doc_url] /// in this vector - pub fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { + pub fn iter_mut(&mut self) -> <#name as #crate_name::SoAIter>::IterMut { self.as_mut_slice().into_iter() } } @@ -198,21 +199,21 @@ pub fn derive(input: &Input) -> TokenStream { /// Get an iterator over the #[doc = #ref_doc_url] /// in this vector - pub fn iter(&mut self) -> <#name as ::soa_derive::SoAIter>::Iter { + pub fn iter(&mut self) -> <#name as #crate_name::SoAIter>::Iter { self.as_ref().into_iter() } /// Get a mutable iterator over the #[doc = #ref_mut_doc_url] /// in this vector - pub fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { + pub fn iter_mut(&mut self) -> <#name as #crate_name::SoAIter>::IterMut { #iter_mut_name(#create_iter_mut) } /// Get a mutable iterator over the #[doc = #ref_mut_doc_url] /// in this vector - pub fn into_iter(self) -> <#name as ::soa_derive::SoAIter<'a>>::IterMut { + pub fn into_iter(self) -> <#name as #crate_name::SoAIter<'a>>::IterMut { #iter_mut_name(#create_mut_into_iter) } } @@ -302,7 +303,7 @@ pub fn derive(input: &Input) -> TokenStream { if input.generate_traits { generated.append_all(quote! { - impl<'a> ::soa_derive::IntoSoAIter<'a, #name> for #slice_name<'a> {} + impl<'a> #crate_name::IntoSoAIter<'a, #name> for #slice_name<'a> {} }) } diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index 0c3602a..b6e0925 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -22,9 +22,9 @@ mod generic; pub(crate) mod names; -#[proc_macro_derive(StructOfArray, attributes(soa_derive, soa_attr, nested_soa, generate_traits))] +#[proc_macro_derive(StructOfArray, attributes(soa_derive, soa_attr, nested_soa, generate_traits, soa_crate))] pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let ast = syn::parse(input).unwrap(); + let ast = syn::parse(input).expect("Failed to parse derive macro for StructOfArray"); let input = input::Input::new(ast); let mut generated = TokenStream::new(); diff --git a/soa-derive-internal/src/ptr.rs b/soa-derive-internal/src/ptr.rs index 65d2f81..e315a3f 100644 --- a/soa-derive-internal/src/ptr.rs +++ b/soa-derive-internal/src/ptr.rs @@ -14,6 +14,7 @@ pub fn derive(input: &Input) -> TokenStream { let ptr_mut_name = names::ptr_mut_name(&input.name); let ref_name = names::ref_name(&input.name); let ref_mut_name = names::ref_mut_name(&input.name); + let crate_name = &input.soa_crate; let doc_url = format!("[`{0}`](struct.{0}.html)", name); let vec_doc_url = format!("[`{0}`](struct.{0}.html)", vec_name); @@ -187,7 +188,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl ::soa_derive::SoAPointers for #name { + impl #crate_name::SoAPointers for #name { type Ptr = #ptr_name; type MutPtr = #ptr_mut_name; } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index 48ad75d..6ba0c93 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -14,6 +14,7 @@ pub fn derive(input: &Input) -> TokenStream { let vec_name = names::vec_name(&input.name); let ref_name = names::ref_name(&input.name); let ptr_name = names::ptr_name(&input.name); + let crate_name = &input.soa_crate; let slice_name_str = format!("[{}]", input.name); let doc_url = format!("[`{0}`](struct.{0}.html)", input.name); @@ -177,7 +178,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get). pub fn get<'b, I>(&'b self, index: I) -> Option where - I: ::soa_derive::SoAIndex<#slice_name<'b>>, + I: #crate_name::SoAIndex<#slice_name<'b>>, 'a: 'b { let slice: #slice_name<'b> = self.reborrow(); @@ -189,7 +190,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::get_unchecked()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked). pub unsafe fn get_unchecked<'b, I>(&'b self, index: I) -> I::RefOutput where - I: ::soa_derive::SoAIndex<#slice_name<'b>>, + I: #crate_name::SoAIndex<#slice_name<'b>>, 'a: 'b { let slice: #slice_name<'b> = self.reborrow(); @@ -204,7 +205,7 @@ pub fn derive(input: &Input) -> TokenStream { /// This is required because we cannot implement `std::ops::Index` directly since it requires returning a reference. pub fn index<'b, I>(&'b self, index: I) -> I::RefOutput where - I: ::soa_derive::SoAIndex<#slice_name<'b>>, + I: #crate_name::SoAIndex<#slice_name<'b>>, 'a: 'b { let slice: #slice_name<'b> = self.reborrow(); @@ -257,7 +258,7 @@ pub fn derive(input: &Input) -> TokenStream { if input.generate_traits { generated.append_all(quote! { - impl<'a> ::soa_derive::ToSoAVec<#name> for #slice_name<'a> { + impl<'a> #crate_name::ToSoAVec<#name> for #slice_name<'a> { type SoAVecType = #vec_name; fn to_vec(&self) -> Self::SoAVecType { @@ -282,6 +283,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { let ref_mut_name = names::ref_mut_name(&input.name); let ptr_name = names::ptr_name(&input.name); let ptr_mut_name = names::ptr_mut_name(&input.name); + let crate_name = &input.soa_crate; let slice_name_str = format!("[{}]", input.name); let doc_url = format!("[`{0}`](struct.{0}.html)", input.name); @@ -504,7 +506,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { /// ::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get). pub fn get<'b, I>(&'b self, index: I) -> Option where - I: ::soa_derive::SoAIndex<#slice_name<'b>>, + I: #crate_name::SoAIndex<#slice_name<'b>>, 'a: 'b { let slice: #slice_name<'b> = self.as_slice(); @@ -516,7 +518,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { /// ::get_unchecked()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked). pub unsafe fn get_unchecked<'b, I>(&'b self, index: I) -> I::RefOutput where - I: ::soa_derive::SoAIndex<#slice_name<'b>>, + I: #crate_name::SoAIndex<#slice_name<'b>>, 'a: 'b { let slice: #slice_name<'b> = self.as_slice(); @@ -532,7 +534,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { /// This is required because we cannot implement that trait. pub fn index<'b, I>(&'b self, index: I) -> I::RefOutput where - I: ::soa_derive::SoAIndex<#slice_name<'b>>, + I: #crate_name::SoAIndex<#slice_name<'b>>, 'a: 'b { let slice: #slice_name<'b> = self.as_slice(); @@ -544,7 +546,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { /// ::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut). pub fn get_mut<'b, I>(&'b mut self, index: I) -> Option where - I: ::soa_derive::SoAIndexMut<#slice_mut_name<'b>>, + I: #crate_name::SoAIndexMut<#slice_mut_name<'b>>, 'a: 'b { let slice: #slice_mut_name<'b> = self.reborrow(); @@ -556,7 +558,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { /// ::get_unchecked_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked_mut). pub unsafe fn get_unchecked_mut<'b, I>(&'b mut self, index: I) -> I::MutOutput where - I: ::soa_derive::SoAIndexMut<#slice_mut_name<'b>>, + I: #crate_name::SoAIndexMut<#slice_mut_name<'b>>, 'a: 'b { let slice: #slice_mut_name<'b> = self.reborrow(); @@ -571,7 +573,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { /// This is required because we cannot implement `std::ops::IndexMut` directly since it requires returning a mutable reference. pub fn index_mut<'b, I>(&'b mut self, index: I) -> I::MutOutput where - I: ::soa_derive::SoAIndexMut<#slice_mut_name<'b>>, + I: #crate_name::SoAIndexMut<#slice_mut_name<'b>>, 'a: 'b { let slice: #slice_mut_name<'b> = self.reborrow(); @@ -699,7 +701,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { if input.generate_traits { generated.append_all(quote! { - impl<'a> ::soa_derive::ToSoAVec<#name> for #slice_mut_name<'a> { + impl<'a> #crate_name::ToSoAVec<#name> for #slice_mut_name<'a> { type SoAVecType = #vec_name; fn to_vec(&self) -> Self::SoAVecType { diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index 1e7aafb..4fc4af8 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -17,6 +17,7 @@ pub fn derive(input: &Input) -> TokenStream { let ref_mut_name = names::ref_mut_name(&input.name); let ptr_name = names::ptr_name(&input.name); let ptr_mut_name = names::ptr_mut_name(&input.name); + let crate_name = &input.soa_crate; let doc_url = format!("[`{0}`](struct.{0}.html)", input.name); @@ -367,7 +368,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::get()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.get). pub fn get<'a, I>(&'a self, index: I) -> Option where - I: ::soa_derive::SoAIndex<&'a #vec_name> + I: #crate_name::SoAIndex<&'a #vec_name> { index.get(self) } @@ -377,7 +378,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::get_unchecked()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.get_unchecked). pub unsafe fn get_unchecked<'a, I>(&'a self, index: I) -> I::RefOutput where - I: ::soa_derive::SoAIndex<&'a #vec_name> + I: #crate_name::SoAIndex<&'a #vec_name> { index.get_unchecked(self) } @@ -387,7 +388,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::index()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.index). pub fn index<'a, I>(&'a self, index: I) -> I::RefOutput where - I: ::soa_derive::SoAIndex<&'a #vec_name> + I: #crate_name::SoAIndex<&'a #vec_name> { index.index(self) } @@ -397,7 +398,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::get_mut()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.get_mut). pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option where - I: ::soa_derive::SoAIndexMut<&'a mut #vec_name> + I: #crate_name::SoAIndexMut<&'a mut #vec_name> { index.get_mut(self) } @@ -407,7 +408,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::get_unchecked_mut()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.get_unchecked_mut). pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::MutOutput where - I: ::soa_derive::SoAIndexMut<&'a mut #vec_name> + I: #crate_name::SoAIndexMut<&'a mut #vec_name> { index.get_unchecked_mut(self) } @@ -417,7 +418,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::index_mut()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.index_mut). pub fn index_mut<'a, I>(&'a mut self, index: I) -> I::MutOutput where - I: ::soa_derive::SoAIndexMut<&'a mut #vec_name> + I: #crate_name::SoAIndexMut<&'a mut #vec_name> { index.index_mut(self) } @@ -477,7 +478,7 @@ pub fn derive(input: &Input) -> TokenStream { if input.generate_traits { generated.append_all(quote! { - impl ::soa_derive::SoAAppendVec<#name> for #vec_name { + impl #crate_name::SoAAppendVec<#name> for #vec_name { fn extend_from_slice(&mut self, other: Self::Slice<'_>) { #( self.#fields_names.extend_from_slice(other.#fields_names); diff --git a/soa-derive/tests/particles/mod.rs b/soa-derive/tests/particles/mod.rs index 5c65864..b09afa6 100644 --- a/soa-derive/tests/particles/mod.rs +++ b/soa-derive/tests/particles/mod.rs @@ -5,6 +5,7 @@ use soa_derive::prelude::*; #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] #[cfg_attr(feature = "generic_traits", generate_traits)] +#[soa_crate(::soa_derive)] pub struct Particle { pub name: String, pub mass: f64, From a95fce88f51a27d412f5e079a7de0389f4770b71 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sun, 26 Jan 2025 22:32:33 -0500 Subject: [PATCH 23/37] chore: slightly better error message --- soa-derive-internal/src/input.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soa-derive-internal/src/input.rs b/soa-derive-internal/src/input.rs index 70d561e..2267a89 100644 --- a/soa-derive-internal/src/input.rs +++ b/soa-derive-internal/src/input.rs @@ -179,7 +179,7 @@ impl Input { } if attr.path().is_ident("soa_crate") { - let args = attr.parse_args::().expect("expected an attribute like a path"); + let args = attr.parse_args::().expect("expected an attribute like a module path, `#[soa_crate(::path::to::impl_of::soa_derive)]`"); soa_derive_crate = Some(args); } } From dec18c9abd5dc41b9f1f5cae1eccd5d73f74174a Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sun, 2 Feb 2025 13:02:24 -0500 Subject: [PATCH 24/37] checkpoint --- soa-derive/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soa-derive/Cargo.toml b/soa-derive/Cargo.toml index 5960f98..40c50af 100644 --- a/soa-derive/Cargo.toml +++ b/soa-derive/Cargo.toml @@ -14,6 +14,8 @@ homepage = "https://github.com/lumol-org/soa-derive" documentation = "https://docs.rs/soa_derive/" [features] +default = ["generic_traits"] + generic_traits = ["soa_derive_internal/generic_traits"] [dependencies] From 9daab559fb983a81d09bbcb03404980e0d87a486 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sun, 2 Feb 2025 13:21:59 -0500 Subject: [PATCH 25/37] restore original layout --- .github/workflows/tests.yml | 2 +- Cargo.toml | 29 +++++++++++++-- example/Cargo.toml | 2 +- soa-derive-internal/Cargo.toml | 1 - soa-derive-internal/src/input.rs | 6 +--- soa-derive-internal/src/lib.rs | 2 -- soa-derive/Cargo.toml | 33 ----------------- {soa-derive/src => src}/lib.rs | 37 -------------------- {soa-derive/tests => tests}/extreme.rs | 0 {soa-derive/tests => tests}/generic.rs | 3 -- {soa-derive/tests => tests}/index.rs | 0 {soa-derive/tests => tests}/iter.rs | 0 {soa-derive/tests => tests}/nested_soa.rs | 0 {soa-derive/tests => tests}/particles/mod.rs | 3 -- {soa-derive/tests => tests}/ptr.rs | 0 {soa-derive/tests => tests}/replace.rs | 0 {soa-derive/tests => tests}/serde.rs | 0 {soa-derive/tests => tests}/slice.rs | 0 {soa-derive/tests => tests}/slice_mut.rs | 0 {soa-derive/tests => tests}/soa_attr.rs | 0 {soa-derive/tests => tests}/vec.rs | 0 {soa-derive/tests => tests}/zip.rs | 0 22 files changed, 29 insertions(+), 89 deletions(-) delete mode 100644 soa-derive/Cargo.toml rename {soa-derive/src => src}/lib.rs (95%) rename {soa-derive/tests => tests}/extreme.rs (100%) rename {soa-derive/tests => tests}/generic.rs (97%) rename {soa-derive/tests => tests}/index.rs (100%) rename {soa-derive/tests => tests}/iter.rs (100%) rename {soa-derive/tests => tests}/nested_soa.rs (100%) rename {soa-derive/tests => tests}/particles/mod.rs (97%) rename {soa-derive/tests => tests}/ptr.rs (100%) rename {soa-derive/tests => tests}/replace.rs (100%) rename {soa-derive/tests => tests}/serde.rs (100%) rename {soa-derive/tests => tests}/slice.rs (100%) rename {soa-derive/tests => tests}/slice_mut.rs (100%) rename {soa-derive/tests => tests}/soa_attr.rs (100%) rename {soa-derive/tests => tests}/vec.rs (100%) rename {soa-derive/tests => tests}/zip.rs (100%) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ec58a38..f7f7610 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - rust-version: ["1.63", stable, beta, nightly] + rust-version: ["1.65", stable, beta, nightly] steps: - uses: actions/checkout@v3 with: diff --git a/Cargo.toml b/Cargo.toml index 9121352..9588bde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,33 @@ -[workspace] +[package] +name = "soa_derive" +version = "0.13.0" +edition = "2018" +rust-version = "1.65" + +authors = ["Guillaume Fraux "] +license = "MIT/Apache-2.0" -resolver = "2" +readme = "README.md" +description = "Automatic Struct of Array generation" +repository = "https://github.com/lumol-org/soa-derive" +homepage = "https://github.com/lumol-org/soa-derive" +documentation = "https://docs.rs/soa_derive/" +[workspace] members = [ "soa-derive-internal", - "soa-derive", "example", ] +[dependencies] +soa_derive_internal = {path = "soa-derive-internal", version = "0.13"} +permutation = "0.4.0" + +[dev-dependencies] +bencher = "0.1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +[[bench]] +name = "soa" +harness = false \ No newline at end of file diff --git a/example/Cargo.toml b/example/Cargo.toml index 9ffccad..a51eebf 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -8,7 +8,7 @@ publish = false edition = "2021" [dependencies] -soa_derive = { path = "../soa-derive", features = []} +soa_derive = { path = "..", features = []} [lib] path = "lib.rs" diff --git a/soa-derive-internal/Cargo.toml b/soa-derive-internal/Cargo.toml index 09432c0..494c89b 100644 --- a/soa-derive-internal/Cargo.toml +++ b/soa-derive-internal/Cargo.toml @@ -18,7 +18,6 @@ documentation = "https://docs.rs/soa_derive/" proc-macro = true [features] -generic_traits = [] [dependencies] syn = {version = "2", features = ["derive", "extra-traits"]} diff --git a/soa-derive-internal/src/input.rs b/soa-derive-internal/src/input.rs index 2267a89..452d6ab 100644 --- a/soa-derive-internal/src/input.rs +++ b/soa-derive-internal/src/input.rs @@ -117,7 +117,7 @@ impl Input { assert!(!fields.is_empty(), "#[derive(StructOfArray)] only supports struct with fields"); let mut extra_attrs = ExtraAttributes::new(); - let mut generate_traits: bool = false; + let generate_traits: bool = true; let mut soa_derive_crate: Option = Some(syn::parse_str("::soa_derive").unwrap()); for attr in input.attrs { @@ -174,10 +174,6 @@ impl Input { } } - if attr.path().is_ident("generate_traits") { - generate_traits = true; - } - if attr.path().is_ident("soa_crate") { let args = attr.parse_args::().expect("expected an attribute like a module path, `#[soa_crate(::path::to::impl_of::soa_derive)]`"); soa_derive_crate = Some(args); diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index b6e0925..68bc518 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -17,7 +17,6 @@ mod ptr; mod refs; mod slice; mod vec; -#[cfg(feature = "generic_traits")] mod generic; pub(crate) mod names; @@ -37,7 +36,6 @@ pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { generated.append_all(iter::derive(&input)); generated.append_all(derive_trait(&input)); - #[cfg(feature = "generic_traits")] if input.generate_traits { generated.append_all( generic::derive_slice(&input) diff --git a/soa-derive/Cargo.toml b/soa-derive/Cargo.toml deleted file mode 100644 index 40c50af..0000000 --- a/soa-derive/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "soa_derive" -version = "0.13.0" -edition = "2018" -rust-version = "1.63" - -authors = ["Guillaume Fraux "] -license = "MIT/Apache-2.0" - -readme = "../README.md" -description = "Automatic Struct of Array generation" -repository = "https://github.com/lumol-org/soa-derive" -homepage = "https://github.com/lumol-org/soa-derive" -documentation = "https://docs.rs/soa_derive/" - -[features] -default = ["generic_traits"] - -generic_traits = ["soa_derive_internal/generic_traits"] - -[dependencies] -soa_derive_internal = {path = "../soa-derive-internal", version = "0.13"} -permutation = "0.4.0" - -[dev-dependencies] -bencher = "0.1" -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[[bench]] -name = "soa" -path = "../benches/soa.rs" -harness = false diff --git a/soa-derive/src/lib.rs b/src/lib.rs similarity index 95% rename from soa-derive/src/lib.rs rename to src/lib.rs index 3a1fe2d..9ef5c68 100644 --- a/soa-derive/src/lib.rs +++ b/src/lib.rs @@ -421,7 +421,6 @@ pub trait SoAPointers { } -#[cfg(feature = "generic_traits")] mod generics { use super::*; @@ -783,42 +782,6 @@ mod generics { /// A trait to express the [`IntoIterator`] guarantee of [`SoASlice`] types in the type system. pub trait IntoSoAIter<'a, T: StructOfArray>: SoASlice + IntoIterator> + 'a {} } - -#[cfg(not(feature = "generic_traits"))] -mod generics { - use super::*; - - /** - The interface for the `Slice` immutable slice struct-of-arrays type. - */ - pub trait SoASlice {} - - /** - The interface for the `SliceMut` mutable slice struct-of-arrays type. A generalization of [`SoASlice`] - whose methods can modify elements of the arrays - */ - pub trait SoASliceMut {} - - /** - The interface for the `Vec`-like struct-of-arrays type. A generalization of [`SoAMutSlice`] whose methods can - also re-size the underlying arrays. - - **NOTE**: This interface is incomplete and additional methods may be added as needed. - */ - pub trait SoAVec {} - - /// A trait to implement `Clone`-dependent behavior to convert a non-owning SoA type into an - /// owning [`SoAVec`]. - pub trait ToSoAVec {} - - /// A trait to implement `Clone`-dependent behavior to extend an [`SoAVec`] with data copied - /// from its associated `Slice` type. - pub trait SoAAppendVec: SoAVec {} - - /// A trait to express the [`IntoIterator`] guarantee of [`SoASlice`] types in the type system. - pub trait IntoSoAIter<'a, T: StructOfArray> {} -} - pub use generics::*; /// A collection of supporting traits for [`StructOfArray`] bundled in one place for ease-of-access diff --git a/soa-derive/tests/extreme.rs b/tests/extreme.rs similarity index 100% rename from soa-derive/tests/extreme.rs rename to tests/extreme.rs diff --git a/soa-derive/tests/generic.rs b/tests/generic.rs similarity index 97% rename from soa-derive/tests/generic.rs rename to tests/generic.rs index 2d0cd35..7448151 100644 --- a/soa-derive/tests/generic.rs +++ b/tests/generic.rs @@ -1,6 +1,3 @@ -#![cfg(feature = "generic_traits")] -// use soa_derive::prelude::*; - mod particles; use std::marker::PhantomData; diff --git a/soa-derive/tests/index.rs b/tests/index.rs similarity index 100% rename from soa-derive/tests/index.rs rename to tests/index.rs diff --git a/soa-derive/tests/iter.rs b/tests/iter.rs similarity index 100% rename from soa-derive/tests/iter.rs rename to tests/iter.rs diff --git a/soa-derive/tests/nested_soa.rs b/tests/nested_soa.rs similarity index 100% rename from soa-derive/tests/nested_soa.rs rename to tests/nested_soa.rs diff --git a/soa-derive/tests/particles/mod.rs b/tests/particles/mod.rs similarity index 97% rename from soa-derive/tests/particles/mod.rs rename to tests/particles/mod.rs index b09afa6..1109155 100644 --- a/soa-derive/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -4,7 +4,6 @@ use soa_derive::prelude::*; #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] -#[cfg_attr(feature = "generic_traits", generate_traits)] #[soa_crate(::soa_derive)] pub struct Particle { pub name: String, @@ -21,8 +20,6 @@ impl Particle { } - -#[cfg(feature = "generic_traits")] mod impls { use std::cmp::Ordering; use std::marker::PhantomData; diff --git a/soa-derive/tests/ptr.rs b/tests/ptr.rs similarity index 100% rename from soa-derive/tests/ptr.rs rename to tests/ptr.rs diff --git a/soa-derive/tests/replace.rs b/tests/replace.rs similarity index 100% rename from soa-derive/tests/replace.rs rename to tests/replace.rs diff --git a/soa-derive/tests/serde.rs b/tests/serde.rs similarity index 100% rename from soa-derive/tests/serde.rs rename to tests/serde.rs diff --git a/soa-derive/tests/slice.rs b/tests/slice.rs similarity index 100% rename from soa-derive/tests/slice.rs rename to tests/slice.rs diff --git a/soa-derive/tests/slice_mut.rs b/tests/slice_mut.rs similarity index 100% rename from soa-derive/tests/slice_mut.rs rename to tests/slice_mut.rs diff --git a/soa-derive/tests/soa_attr.rs b/tests/soa_attr.rs similarity index 100% rename from soa-derive/tests/soa_attr.rs rename to tests/soa_attr.rs diff --git a/soa-derive/tests/vec.rs b/tests/vec.rs similarity index 100% rename from soa-derive/tests/vec.rs rename to tests/vec.rs diff --git a/soa-derive/tests/zip.rs b/tests/zip.rs similarity index 100% rename from soa-derive/tests/zip.rs rename to tests/zip.rs From c4989b5d797df0c368fddc9ec69bb08764256b24 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sun, 2 Feb 2025 13:32:45 -0500 Subject: [PATCH 26/37] Squashed commit of the following: commit a1cd5b655d06c49127116e91f31d4008b26b329b Author: Joshua Klein Date: Sun Feb 2 13:31:10 2025 -0500 make trait implementation automatic --- soa-derive-internal/src/generic.rs | 13 +++---- soa-derive-internal/src/index.rs | 57 +++++++++++++++--------------- soa-derive-internal/src/input.rs | 17 --------- soa-derive-internal/src/iter.rs | 19 +++++----- soa-derive-internal/src/lib.rs | 4 +-- soa-derive-internal/src/ptr.rs | 3 +- soa-derive-internal/src/slice.rs | 28 +++++++-------- soa-derive-internal/src/vec.rs | 17 +++++---- tests/particles/mod.rs | 1 - 9 files changed, 66 insertions(+), 93 deletions(-) diff --git a/soa-derive-internal/src/generic.rs b/soa-derive-internal/src/generic.rs index 924e28e..9406440 100644 --- a/soa-derive-internal/src/generic.rs +++ b/soa-derive-internal/src/generic.rs @@ -11,10 +11,9 @@ pub fn derive_slice(input: &Input) -> TokenStream { let ref_name = names::ref_name(&input.name); let ptr_name = names::ptr_name(&input.name); let iter_name = names::iter_name(name); - let crate_name = &input.soa_crate; let generated = quote! { - impl<'a> #crate_name::SoASlice<#name> for #slice_name<'a> { + impl<'a> ::soa_derive::SoASlice<#name> for #slice_name<'a> { type Ref<'t> = #ref_name<'t> where Self: 't, 'a: 't; type Slice<'t> = #slice_name<'t> where Self: 't, 'a: 't; type Iter<'t> = #iter_name<'t> where Self: 't, 'a: 't; @@ -77,11 +76,10 @@ pub fn derive_slice_mut(input: &Input) -> TokenStream { let ptr_mut_name = names::ptr_mut_name(&input.name); let iter_name = names::iter_name(name); let iter_mut_name = names::iter_mut_name(name); - let crate_name = &input.soa_crate; let generated = quote! { - impl<'a> #crate_name::SoASliceMut<#name> for #slice_mut_name<'a> { + impl<'a> ::soa_derive::SoASliceMut<#name> for #slice_mut_name<'a> { type Ref<'t> = #ref_name<'t> where Self: 't; type Slice<'t> = #slice_name<'t> where Self: 't; type Iter<'t> = #iter_name<'t> where Self: 't; @@ -161,7 +159,7 @@ pub fn derive_slice_mut(input: &Input) -> TokenStream { } fn apply_index(&mut self, indices: &[usize]) { - self.apply_permutation(&mut #crate_name::Permutation::oneline(indices).inverse()); + self.apply_permutation(&mut ::soa_derive::Permutation::oneline(indices).inverse()); } fn as_ptr(&self) -> Self::Ptr { @@ -188,11 +186,10 @@ pub fn derive_vec(input: &Input) -> TokenStream { let ptr_mut_name = names::ptr_mut_name(&input.name); let iter_name = names::iter_name(name); let iter_mut_name = names::iter_mut_name(name); - let crate_name = &input.soa_crate; let generated = quote! { - impl #crate_name::SoAVec<#name> for #vec_name { + impl ::soa_derive::SoAVec<#name> for #vec_name { type Ref<'t> = #ref_name<'t>; type Slice<'t> = #slice_name<'t>; type Iter<'t> = #iter_name<'t>; @@ -272,7 +269,7 @@ pub fn derive_vec(input: &Input) -> TokenStream { } fn apply_index(&mut self, indices: &[usize]) { - use #crate_name::SoASliceMut; + use ::soa_derive::SoASliceMut; self.as_mut_slice().apply_index(indices); } diff --git a/soa-derive-internal/src/index.rs b/soa-derive-internal/src/index.rs index ab76416..0a685b1 100644 --- a/soa-derive-internal/src/index.rs +++ b/soa-derive-internal/src/index.rs @@ -11,7 +11,6 @@ pub fn derive(input: &Input) -> TokenStream { let slice_mut_name = names::slice_mut_name(&input.name); let ref_name = names::ref_name(&input.name); let ref_mut_name = names::ref_mut_name(&input.name); - let crate_name = &input.soa_crate; let fields_names = &input.fields.iter() .map(|field| field.ident.clone().unwrap()) @@ -41,7 +40,7 @@ pub fn derive(input: &Input) -> TokenStream { quote!{ // usize - impl<'a> #crate_name::SoAIndex<&'a #vec_name> for usize { + impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for usize { type RefOutput = #ref_name<'a>; #[inline] @@ -64,7 +63,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for usize { + impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for usize { type MutOutput = #ref_mut_name<'a>; #[inline] @@ -90,7 +89,7 @@ pub fn derive(input: &Input) -> TokenStream { // Range - impl<'a> #crate_name::SoAIndex<&'a #vec_name> for ::std::ops::Range { + impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for ::std::ops::Range { type RefOutput = #slice_name<'a>; #[inline] @@ -113,7 +112,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for ::std::ops::Range { + impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for ::std::ops::Range { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -137,7 +136,7 @@ pub fn derive(input: &Input) -> TokenStream { } // RangeTo - impl<'a> #crate_name::SoAIndex<&'a #vec_name> for ::std::ops::RangeTo { + impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for ::std::ops::RangeTo { type RefOutput = #slice_name<'a>; #[inline] @@ -156,7 +155,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeTo { + impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeTo { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -176,7 +175,7 @@ pub fn derive(input: &Input) -> TokenStream { } // RangeFrom - impl<'a> #crate_name::SoAIndex<&'a #vec_name> for ::std::ops::RangeFrom { + impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for ::std::ops::RangeFrom { type RefOutput = #slice_name<'a>; #[inline] @@ -195,7 +194,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeFrom { + impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeFrom { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -215,7 +214,7 @@ pub fn derive(input: &Input) -> TokenStream { } // RangeFull - impl<'a> #crate_name::SoAIndex<&'a #vec_name> for ::std::ops::RangeFull { + impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for ::std::ops::RangeFull { type RefOutput = #slice_name<'a>; #[inline] @@ -234,7 +233,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeFull { + impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeFull { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -254,7 +253,7 @@ pub fn derive(input: &Input) -> TokenStream { } // RangeInclusive - impl<'a> #crate_name::SoAIndex<&'a #vec_name> for ::std::ops::RangeInclusive { + impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for ::std::ops::RangeInclusive { type RefOutput = #slice_name<'a>; #[inline] @@ -277,7 +276,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeInclusive { + impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeInclusive { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -301,7 +300,7 @@ pub fn derive(input: &Input) -> TokenStream { } // RangeToInclusive - impl<'a> #crate_name::SoAIndex<&'a #vec_name> for ::std::ops::RangeToInclusive { + impl<'a> ::soa_derive::SoAIndex<&'a #vec_name> for ::std::ops::RangeToInclusive { type RefOutput = #slice_name<'a>; #[inline] @@ -320,7 +319,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeToInclusive { + impl<'a> ::soa_derive::SoAIndexMut<&'a mut #vec_name> for ::std::ops::RangeToInclusive { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -340,7 +339,7 @@ pub fn derive(input: &Input) -> TokenStream { } // usize - impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for usize { + impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for usize { type RefOutput = #ref_name<'a>; #[inline] @@ -367,7 +366,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for usize { + impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for usize { type MutOutput = #ref_mut_name<'a>; #[inline] @@ -397,7 +396,7 @@ pub fn derive(input: &Input) -> TokenStream { // Range - impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for ::std::ops::Range { + impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for ::std::ops::Range { type RefOutput = #slice_name<'a>; #[inline] @@ -424,7 +423,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::Range { + impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::Range { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -454,7 +453,7 @@ pub fn derive(input: &Input) -> TokenStream { // RangeTo - impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for ::std::ops::RangeTo { + impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for ::std::ops::RangeTo { type RefOutput = #slice_name<'a>; #[inline] @@ -473,7 +472,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeTo { + impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeTo { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -494,7 +493,7 @@ pub fn derive(input: &Input) -> TokenStream { // RangeFrom - impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for ::std::ops::RangeFrom { + impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for ::std::ops::RangeFrom { type RefOutput = #slice_name<'a>; #[inline] @@ -513,7 +512,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeFrom { + impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeFrom { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -534,7 +533,7 @@ pub fn derive(input: &Input) -> TokenStream { // RangeFull - impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for ::std::ops::RangeFull { + impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for ::std::ops::RangeFull { type RefOutput = #slice_name<'a>; #[inline] @@ -553,7 +552,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeFull { + impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeFull { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -574,7 +573,7 @@ pub fn derive(input: &Input) -> TokenStream { // RangeInclusive - impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for ::std::ops::RangeInclusive { + impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for ::std::ops::RangeInclusive { type RefOutput = #slice_name<'a>; #[inline] @@ -597,7 +596,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeInclusive { + impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeInclusive { type MutOutput = #slice_mut_name<'a>; #[inline] @@ -622,7 +621,7 @@ pub fn derive(input: &Input) -> TokenStream { // RangeToInclusive - impl<'a> #crate_name::SoAIndex<#slice_name<'a>> for ::std::ops::RangeToInclusive { + impl<'a> ::soa_derive::SoAIndex<#slice_name<'a>> for ::std::ops::RangeToInclusive { type RefOutput = #slice_name<'a>; #[inline] @@ -641,7 +640,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl<'a> #crate_name::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeToInclusive { + impl<'a> ::soa_derive::SoAIndexMut<#slice_mut_name<'a>> for ::std::ops::RangeToInclusive { type MutOutput = #slice_mut_name<'a>; #[inline] diff --git a/soa-derive-internal/src/input.rs b/soa-derive-internal/src/input.rs index 452d6ab..0a272ad 100644 --- a/soa-derive-internal/src/input.rs +++ b/soa-derive-internal/src/input.rs @@ -18,14 +18,6 @@ pub struct Input { /// Additional attributes requested with `#[soa_attr(...)]` or /// `#[soa_derive()]` pub attrs: ExtraAttributes, - - /// Whether or not to generate extra trait implementations that make the SoA types usable - /// in a generic context enabled by the `generic_traits` feature. - pub generate_traits: bool, - - /// The path to import the `soa_derive` crate from, in case the library is vendored or - /// internalized. - pub soa_crate: syn::Path, } pub struct ExtraAttributes { @@ -117,8 +109,6 @@ impl Input { assert!(!fields.is_empty(), "#[derive(StructOfArray)] only supports struct with fields"); let mut extra_attrs = ExtraAttributes::new(); - let generate_traits: bool = true; - let mut soa_derive_crate: Option = Some(syn::parse_str("::soa_derive").unwrap()); for attr in input.attrs { if attr.path().is_ident("soa_derive") { @@ -173,11 +163,6 @@ impl Input { None => panic!("expected one of the SoA type, got {}", quote!(#soa_type)) } } - - if attr.path().is_ident("soa_crate") { - let args = attr.parse_args::().expect("expected an attribute like a module path, `#[soa_crate(::path::to::impl_of::soa_derive)]`"); - soa_derive_crate = Some(args); - } } Input { @@ -186,8 +171,6 @@ impl Input { visibility: input.vis, attrs: extra_attrs, field_is_nested, - generate_traits: generate_traits, - soa_crate: soa_derive_crate.unwrap(), } } diff --git a/soa-derive-internal/src/iter.rs b/soa-derive-internal/src/iter.rs index faebce2..caf99b9 100644 --- a/soa-derive-internal/src/iter.rs +++ b/soa-derive-internal/src/iter.rs @@ -15,7 +15,6 @@ pub fn derive(input: &Input) -> TokenStream { let ref_mut_name = names::ref_mut_name(&input.name); let iter_name = names::iter_name(&input.name); let iter_mut_name = names::iter_mut_name(&input.name); - let crate_name = &input.soa_crate; let doc_url = format!("[`{0}`](struct.{0}.html)", name); let ref_doc_url = format!("[`{0}`](struct.{0}.html)", ref_name); @@ -126,7 +125,7 @@ pub fn derive(input: &Input) -> TokenStream { /// Get an iterator over the #[doc = #ref_doc_url] /// in this vector - pub fn iter(&self) -> <#name as #crate_name::SoAIter>::Iter { + pub fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { self.as_slice().into_iter() } } @@ -135,14 +134,14 @@ pub fn derive(input: &Input) -> TokenStream { /// Get an iterator over the #[doc = #ref_doc_url] /// in this slice. - pub fn iter(&self) -> <#name as #crate_name::SoAIter>::Iter { + pub fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { #iter_name(#create_iter) } /// Get an iterator over the #[doc = #ref_doc_url] /// in this slice. - pub fn into_iter(self) -> <#name as #crate_name::SoAIter<'a>>::Iter { + pub fn into_iter(self) -> <#name as ::soa_derive::SoAIter<'a>>::Iter { #iter_name(#create_into_iter) } } @@ -190,7 +189,7 @@ pub fn derive(input: &Input) -> TokenStream { /// Get a mutable iterator over the #[doc = #ref_mut_doc_url] /// in this vector - pub fn iter_mut(&mut self) -> <#name as #crate_name::SoAIter>::IterMut { + pub fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { self.as_mut_slice().into_iter() } } @@ -199,21 +198,21 @@ pub fn derive(input: &Input) -> TokenStream { /// Get an iterator over the #[doc = #ref_doc_url] /// in this vector - pub fn iter(&mut self) -> <#name as #crate_name::SoAIter>::Iter { + pub fn iter(&mut self) -> <#name as ::soa_derive::SoAIter>::Iter { self.as_ref().into_iter() } /// Get a mutable iterator over the #[doc = #ref_mut_doc_url] /// in this vector - pub fn iter_mut(&mut self) -> <#name as #crate_name::SoAIter>::IterMut { + pub fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { #iter_mut_name(#create_iter_mut) } /// Get a mutable iterator over the #[doc = #ref_mut_doc_url] /// in this vector - pub fn into_iter(self) -> <#name as #crate_name::SoAIter<'a>>::IterMut { + pub fn into_iter(self) -> <#name as ::soa_derive::SoAIter<'a>>::IterMut { #iter_mut_name(#create_mut_into_iter) } } @@ -300,10 +299,10 @@ pub fn derive(input: &Input) -> TokenStream { } }; - if input.generate_traits { + { generated.append_all(quote! { - impl<'a> #crate_name::IntoSoAIter<'a, #name> for #slice_name<'a> {} + impl<'a> ::soa_derive::IntoSoAIter<'a, #name> for #slice_name<'a> {} }) } diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index 68bc518..8dc538e 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -21,7 +21,7 @@ mod generic; pub(crate) mod names; -#[proc_macro_derive(StructOfArray, attributes(soa_derive, soa_attr, nested_soa, generate_traits, soa_crate))] +#[proc_macro_derive(StructOfArray, attributes(soa_derive, soa_attr, nested_soa))] pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).expect("Failed to parse derive macro for StructOfArray"); let input = input::Input::new(ast); @@ -36,7 +36,7 @@ pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { generated.append_all(iter::derive(&input)); generated.append_all(derive_trait(&input)); - if input.generate_traits { + { generated.append_all( generic::derive_slice(&input) ); diff --git a/soa-derive-internal/src/ptr.rs b/soa-derive-internal/src/ptr.rs index e315a3f..65d2f81 100644 --- a/soa-derive-internal/src/ptr.rs +++ b/soa-derive-internal/src/ptr.rs @@ -14,7 +14,6 @@ pub fn derive(input: &Input) -> TokenStream { let ptr_mut_name = names::ptr_mut_name(&input.name); let ref_name = names::ref_name(&input.name); let ref_mut_name = names::ref_mut_name(&input.name); - let crate_name = &input.soa_crate; let doc_url = format!("[`{0}`](struct.{0}.html)", name); let vec_doc_url = format!("[`{0}`](struct.{0}.html)", vec_name); @@ -188,7 +187,7 @@ pub fn derive(input: &Input) -> TokenStream { } } - impl #crate_name::SoAPointers for #name { + impl ::soa_derive::SoAPointers for #name { type Ptr = #ptr_name; type MutPtr = #ptr_mut_name; } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index 6ba0c93..efd802a 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -14,7 +14,6 @@ pub fn derive(input: &Input) -> TokenStream { let vec_name = names::vec_name(&input.name); let ref_name = names::ref_name(&input.name); let ptr_name = names::ptr_name(&input.name); - let crate_name = &input.soa_crate; let slice_name_str = format!("[{}]", input.name); let doc_url = format!("[`{0}`](struct.{0}.html)", input.name); @@ -178,7 +177,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get). pub fn get<'b, I>(&'b self, index: I) -> Option where - I: #crate_name::SoAIndex<#slice_name<'b>>, + I: ::soa_derive::SoAIndex<#slice_name<'b>>, 'a: 'b { let slice: #slice_name<'b> = self.reborrow(); @@ -190,7 +189,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::get_unchecked()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked). pub unsafe fn get_unchecked<'b, I>(&'b self, index: I) -> I::RefOutput where - I: #crate_name::SoAIndex<#slice_name<'b>>, + I: ::soa_derive::SoAIndex<#slice_name<'b>>, 'a: 'b { let slice: #slice_name<'b> = self.reborrow(); @@ -205,7 +204,7 @@ pub fn derive(input: &Input) -> TokenStream { /// This is required because we cannot implement `std::ops::Index` directly since it requires returning a reference. pub fn index<'b, I>(&'b self, index: I) -> I::RefOutput where - I: #crate_name::SoAIndex<#slice_name<'b>>, + I: ::soa_derive::SoAIndex<#slice_name<'b>>, 'a: 'b { let slice: #slice_name<'b> = self.reborrow(); @@ -256,9 +255,9 @@ pub fn derive(input: &Input) -> TokenStream { } }); - if input.generate_traits { + { generated.append_all(quote! { - impl<'a> #crate_name::ToSoAVec<#name> for #slice_name<'a> { + impl<'a> ::soa_derive::ToSoAVec<#name> for #slice_name<'a> { type SoAVecType = #vec_name; fn to_vec(&self) -> Self::SoAVecType { @@ -283,7 +282,6 @@ pub fn derive_mut(input: &Input) -> TokenStream { let ref_mut_name = names::ref_mut_name(&input.name); let ptr_name = names::ptr_name(&input.name); let ptr_mut_name = names::ptr_mut_name(&input.name); - let crate_name = &input.soa_crate; let slice_name_str = format!("[{}]", input.name); let doc_url = format!("[`{0}`](struct.{0}.html)", input.name); @@ -506,7 +504,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { /// ::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get). pub fn get<'b, I>(&'b self, index: I) -> Option where - I: #crate_name::SoAIndex<#slice_name<'b>>, + I: ::soa_derive::SoAIndex<#slice_name<'b>>, 'a: 'b { let slice: #slice_name<'b> = self.as_slice(); @@ -518,7 +516,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { /// ::get_unchecked()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked). pub unsafe fn get_unchecked<'b, I>(&'b self, index: I) -> I::RefOutput where - I: #crate_name::SoAIndex<#slice_name<'b>>, + I: ::soa_derive::SoAIndex<#slice_name<'b>>, 'a: 'b { let slice: #slice_name<'b> = self.as_slice(); @@ -534,7 +532,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { /// This is required because we cannot implement that trait. pub fn index<'b, I>(&'b self, index: I) -> I::RefOutput where - I: #crate_name::SoAIndex<#slice_name<'b>>, + I: ::soa_derive::SoAIndex<#slice_name<'b>>, 'a: 'b { let slice: #slice_name<'b> = self.as_slice(); @@ -546,7 +544,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { /// ::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut). pub fn get_mut<'b, I>(&'b mut self, index: I) -> Option where - I: #crate_name::SoAIndexMut<#slice_mut_name<'b>>, + I: ::soa_derive::SoAIndexMut<#slice_mut_name<'b>>, 'a: 'b { let slice: #slice_mut_name<'b> = self.reborrow(); @@ -558,7 +556,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { /// ::get_unchecked_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked_mut). pub unsafe fn get_unchecked_mut<'b, I>(&'b mut self, index: I) -> I::MutOutput where - I: #crate_name::SoAIndexMut<#slice_mut_name<'b>>, + I: ::soa_derive::SoAIndexMut<#slice_mut_name<'b>>, 'a: 'b { let slice: #slice_mut_name<'b> = self.reborrow(); @@ -573,7 +571,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { /// This is required because we cannot implement `std::ops::IndexMut` directly since it requires returning a mutable reference. pub fn index_mut<'b, I>(&'b mut self, index: I) -> I::MutOutput where - I: #crate_name::SoAIndexMut<#slice_mut_name<'b>>, + I: ::soa_derive::SoAIndexMut<#slice_mut_name<'b>>, 'a: 'b { let slice: #slice_mut_name<'b> = self.reborrow(); @@ -699,9 +697,9 @@ pub fn derive_mut(input: &Input) -> TokenStream { } }); - if input.generate_traits { + { generated.append_all(quote! { - impl<'a> #crate_name::ToSoAVec<#name> for #slice_mut_name<'a> { + impl<'a> ::soa_derive::ToSoAVec<#name> for #slice_mut_name<'a> { type SoAVecType = #vec_name; fn to_vec(&self) -> Self::SoAVecType { diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index 4fc4af8..438c373 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -17,7 +17,6 @@ pub fn derive(input: &Input) -> TokenStream { let ref_mut_name = names::ref_mut_name(&input.name); let ptr_name = names::ptr_name(&input.name); let ptr_mut_name = names::ptr_mut_name(&input.name); - let crate_name = &input.soa_crate; let doc_url = format!("[`{0}`](struct.{0}.html)", input.name); @@ -368,7 +367,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::get()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.get). pub fn get<'a, I>(&'a self, index: I) -> Option where - I: #crate_name::SoAIndex<&'a #vec_name> + I: ::soa_derive::SoAIndex<&'a #vec_name> { index.get(self) } @@ -378,7 +377,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::get_unchecked()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.get_unchecked). pub unsafe fn get_unchecked<'a, I>(&'a self, index: I) -> I::RefOutput where - I: #crate_name::SoAIndex<&'a #vec_name> + I: ::soa_derive::SoAIndex<&'a #vec_name> { index.get_unchecked(self) } @@ -388,7 +387,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::index()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.index). pub fn index<'a, I>(&'a self, index: I) -> I::RefOutput where - I: #crate_name::SoAIndex<&'a #vec_name> + I: ::soa_derive::SoAIndex<&'a #vec_name> { index.index(self) } @@ -398,7 +397,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::get_mut()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.get_mut). pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option where - I: #crate_name::SoAIndexMut<&'a mut #vec_name> + I: ::soa_derive::SoAIndexMut<&'a mut #vec_name> { index.get_mut(self) } @@ -408,7 +407,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::get_unchecked_mut()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.get_unchecked_mut). pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::MutOutput where - I: #crate_name::SoAIndexMut<&'a mut #vec_name> + I: ::soa_derive::SoAIndexMut<&'a mut #vec_name> { index.get_unchecked_mut(self) } @@ -418,7 +417,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::index_mut()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.index_mut). pub fn index_mut<'a, I>(&'a mut self, index: I) -> I::MutOutput where - I: #crate_name::SoAIndexMut<&'a mut #vec_name> + I: ::soa_derive::SoAIndexMut<&'a mut #vec_name> { index.index_mut(self) } @@ -476,9 +475,9 @@ pub fn derive(input: &Input) -> TokenStream { } }); - if input.generate_traits { + { generated.append_all(quote! { - impl #crate_name::SoAAppendVec<#name> for #vec_name { + impl ::soa_derive::SoAAppendVec<#name> for #vec_name { fn extend_from_slice(&mut self, other: Self::Slice<'_>) { #( self.#fields_names.extend_from_slice(other.#fields_names); diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index 1109155..5b08d5c 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -4,7 +4,6 @@ use soa_derive::prelude::*; #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] #[soa_derive(Debug, Clone, PartialOrd, PartialEq)] -#[soa_crate(::soa_derive)] pub struct Particle { pub name: String, pub mass: f64, From cac64acf7c28cbb7acf8dd6f7fca7d0ff482668a Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sun, 2 Feb 2025 13:34:16 -0500 Subject: [PATCH 27/37] remove feature flag --- .github/workflows/tests.yml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f7f7610..259290e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,22 +26,3 @@ jobs: run: cargo test --release - name: check that benchmarks still compile run: cargo bench --no-run - tests_derive_generics: - runs-on: ubuntu-20.04 - strategy: - matrix: - rust-version: [stable, beta, nightly] - steps: - - uses: actions/checkout@v3 - with: - submodules: true - - name: setup rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: ${{ matrix.rust-version }} - - name: run tests in debug mode - run: cargo test -F generic_traits - - name: run tests in release mode - run: cargo test --release -F generic_traits - - name: check that benchmarks still compile - run: cargo bench --no-run -F generic_traits From 1c3f22716c1b129832b727ce025ff48467438e50 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sun, 2 Feb 2025 13:38:54 -0500 Subject: [PATCH 28/37] commence CI-based version search --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 259290e..8db9356 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - rust-version: ["1.65", stable, beta, nightly] + rust-version: ["1.68", "1.70", "1.75", "1.80", stable, beta, nightly] steps: - uses: actions/checkout@v3 with: From 1f18602404fa7380276fdf7a3ae7cd0eef51706f Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sun, 2 Feb 2025 13:42:18 -0500 Subject: [PATCH 29/37] update version range --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8db9356..159c4e2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - rust-version: ["1.68", "1.70", "1.75", "1.80", stable, beta, nightly] + rust-version: ["1.76", "1.78", "1.80", "1.82", stable, beta, nightly] steps: - uses: actions/checkout@v3 with: From 7ae3b44462b0546f2de0d98c2c4d32889ef394d2 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sun, 2 Feb 2025 13:43:33 -0500 Subject: [PATCH 30/37] min version found --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 159c4e2..7d3ddb7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - rust-version: ["1.76", "1.78", "1.80", "1.82", stable, beta, nightly] + rust-version: ["1.77", "1.78", stable, beta, nightly] steps: - uses: actions/checkout@v3 with: From 221e26ebef0130f6ae22cdde81c56bba47c5486a Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Sun, 2 Feb 2025 13:45:08 -0500 Subject: [PATCH 31/37] minimum version found --- .github/workflows/tests.yml | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7d3ddb7..1c6261d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - rust-version: ["1.77", "1.78", stable, beta, nightly] + rust-version: ["1.78", stable, beta, nightly] steps: - uses: actions/checkout@v3 with: diff --git a/Cargo.toml b/Cargo.toml index 9588bde..af9db43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "soa_derive" version = "0.13.0" edition = "2018" -rust-version = "1.65" +rust-version = "1.78" authors = ["Guillaume Fraux "] license = "MIT/Apache-2.0" From 511787d92a5c5eba978179459562f44c1f2f6bda Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Tue, 25 Feb 2025 18:31:22 -0500 Subject: [PATCH 32/37] Update soa-derive-internal/src/lib.rs Co-authored-by: Guillaume Fraux --- soa-derive-internal/src/lib.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index 8dc538e..fd0653e 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -36,17 +36,9 @@ pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { generated.append_all(iter::derive(&input)); generated.append_all(derive_trait(&input)); - { - generated.append_all( - generic::derive_slice(&input) - ); - generated.append_all( - generic::derive_slice_mut(&input) - ); - generated.append_all( - generic::derive_vec(&input) - ); - } + generated.append_all(generic::derive_slice(&input)); + generated.append_all(generic::derive_slice_mut(&input)); + generated.append_all(generic::derive_vec(&input)); generated.into() } From ae7ce4ca1226f8f21a61ff9fae9dd265d5a6b762 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Tue, 25 Feb 2025 18:31:31 -0500 Subject: [PATCH 33/37] Update example/Cargo.toml Co-authored-by: Guillaume Fraux --- example/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/Cargo.toml b/example/Cargo.toml index a51eebf..6df3c78 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -8,7 +8,7 @@ publish = false edition = "2021" [dependencies] -soa_derive = { path = "..", features = []} +soa_derive = { path = ".." } [lib] path = "lib.rs" From 333d2335ce11a693f5d5200c2bca40d8d66704dc Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Tue, 25 Feb 2025 19:11:20 -0500 Subject: [PATCH 34/37] Apply suggestions from code review Co-authored-by: Guillaume Fraux --- soa-derive-internal/Cargo.toml | 1 - soa-derive-internal/src/lib.rs | 7 ------- soa-derive-internal/src/slice.rs | 3 --- soa-derive-internal/src/vec.rs | 2 -- tests/particles/mod.rs | 1 - 5 files changed, 14 deletions(-) diff --git a/soa-derive-internal/Cargo.toml b/soa-derive-internal/Cargo.toml index 494c89b..33ff78b 100644 --- a/soa-derive-internal/Cargo.toml +++ b/soa-derive-internal/Cargo.toml @@ -17,7 +17,6 @@ documentation = "https://docs.rs/soa_derive/" [lib] proc-macro = true -[features] [dependencies] syn = {version = "2", features = ["derive", "extra-traits"]} diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index fd0653e..1b94626 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -45,16 +45,9 @@ pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { use crate::input::Input; use quote::quote; -#[allow(unused)] fn derive_trait(input: &Input) -> TokenStream { let name = &input.name; let vec_name = names::vec_name(name); - let slice_name = names::slice_name(name); - let slice_mut_name = names::slice_mut_name(name); - let ref_name = names::ref_name(name); - let ref_mut_name = names::ref_mut_name(name); - let ptr_name = names::ptr_name(name); - let ptr_mut_name = names::ptr_mut_name(name); quote! { impl soa_derive::StructOfArray for #name { diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index efd802a..4571987 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -55,7 +55,6 @@ pub fn derive(input: &Input) -> TokenStream { |ident, _| quote! { ::std::slice::from_raw_parts(data.#ident, len) }, ).collect::>(); - #[allow(unused)] let iter_name = names::iter_name(name); let mut generated = quote! { @@ -348,9 +347,7 @@ pub fn derive_mut(input: &Input) -> TokenStream { |ident, _| quote! { permutation.apply_slice_in_place(&mut self.#ident) }, ).collect::>(); - #[allow(unused)] let iter_name = names::iter_name(name); - #[allow(unused)] let iter_mut_name = names::iter_mut_name(name); let mut generated = quote! { diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index 438c373..b72c681 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -67,9 +67,7 @@ pub fn derive(input: &Input) -> TokenStream { |ident, _| quote! { ::std::mem::replace(&mut self.#ident[index], field) }, ).collect::>(); - #[allow(unused)] let iter_name = names::iter_name(name); - #[allow(unused)] let iter_mut_name = names::iter_mut_name(name); let mut generated = quote! { diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index 5b08d5c..65b8148 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -27,7 +27,6 @@ mod impls { fn iter_max_generic<'a, T: StructOfArray, V: SoASlice + 'a>(vec: &'a V) -> Option> where V::Ref<'a>: PartialOrd + Debug { let x= vec.iter().reduce(|a, b| { - eprintln!("{a:?}"); if a.partial_cmp(&b).unwrap().is_ge() { a } else { From 461ba24b6ead1550f2508888c4fc312c3430716b Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Tue, 25 Feb 2025 22:34:46 -0500 Subject: [PATCH 35/37] Apply more suggestions from code review, update documentation --- soa-derive-internal/src/iter.rs | 25 +++++++++---------------- soa-derive-internal/src/slice.rs | 5 ----- soa-derive-internal/src/vec.rs | 21 +++++++-------------- src/lib.rs | 17 +++++++++-------- 4 files changed, 25 insertions(+), 43 deletions(-) diff --git a/soa-derive-internal/src/iter.rs b/soa-derive-internal/src/iter.rs index caf99b9..6199409 100644 --- a/soa-derive-internal/src/iter.rs +++ b/soa-derive-internal/src/iter.rs @@ -1,6 +1,5 @@ use proc_macro2::TokenStream; use quote::quote; -use quote::TokenStreamExt; use crate::input::{Input, TokenStreamIterator}; use crate::names; @@ -80,7 +79,7 @@ pub fn derive(input: &Input) -> TokenStream { } }).expect("should be Some"); - let mut generated = quote! { + let generated = quote! { /// Iterator over #[doc = #doc_url] #[allow(missing_debug_implementations)] @@ -134,14 +133,14 @@ pub fn derive(input: &Input) -> TokenStream { /// Get an iterator over the #[doc = #ref_doc_url] /// in this slice. - pub fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { + pub fn iter(&self) -> #iter_name { #iter_name(#create_iter) } /// Get an iterator over the #[doc = #ref_doc_url] /// in this slice. - pub fn into_iter(self) -> <#name as ::soa_derive::SoAIter<'a>>::Iter { + pub fn into_iter(self) -> #iter_name<'a> { #iter_name(#create_into_iter) } } @@ -189,7 +188,7 @@ pub fn derive(input: &Input) -> TokenStream { /// Get a mutable iterator over the #[doc = #ref_mut_doc_url] /// in this vector - pub fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { + pub fn iter_mut(&mut self) -> #iter_mut_name { self.as_mut_slice().into_iter() } } @@ -198,21 +197,21 @@ pub fn derive(input: &Input) -> TokenStream { /// Get an iterator over the #[doc = #ref_doc_url] /// in this vector - pub fn iter(&mut self) -> <#name as ::soa_derive::SoAIter>::Iter { + pub fn iter(&mut self) -> #iter_name { self.as_ref().into_iter() } /// Get a mutable iterator over the #[doc = #ref_mut_doc_url] /// in this vector - pub fn iter_mut(&mut self) -> <#name as ::soa_derive::SoAIter>::IterMut { + pub fn iter_mut(&mut self) -> #iter_mut_name { #iter_mut_name(#create_iter_mut) } /// Get a mutable iterator over the #[doc = #ref_mut_doc_url] /// in this vector - pub fn into_iter(self) -> <#name as ::soa_derive::SoAIter<'a>>::IterMut { + pub fn into_iter(self) -> #iter_mut_name<'a> { #iter_mut_name(#create_mut_into_iter) } } @@ -297,15 +296,9 @@ pub fn derive(input: &Input) -> TokenStream { self.extend(iter.into_iter().map(|item| item.to_owned())) } } - }; - - { - generated.append_all(quote! { - impl<'a> ::soa_derive::IntoSoAIter<'a, #name> for #slice_name<'a> {} - - }) - } + impl<'a> ::soa_derive::IntoSoAIter<'a, #name> for #slice_name<'a> {} + }; return generated; } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index 4571987..e240006 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -55,8 +55,6 @@ pub fn derive(input: &Input) -> TokenStream { |ident, _| quote! { ::std::slice::from_raw_parts(data.#ident, len) }, ).collect::>(); - let iter_name = names::iter_name(name); - let mut generated = quote! { /// A slice of #[doc = #doc_url] @@ -347,9 +345,6 @@ pub fn derive_mut(input: &Input) -> TokenStream { |ident, _| quote! { permutation.apply_slice_in_place(&mut self.#ident) }, ).collect::>(); - let iter_name = names::iter_name(name); - let iter_mut_name = names::iter_mut_name(name); - let mut generated = quote! { /// A mutable slice of #[doc = #doc_url] diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index b72c681..1a15af9 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -67,9 +67,6 @@ pub fn derive(input: &Input) -> TokenStream { |ident, _| quote! { ::std::mem::replace(&mut self.#ident[index], field) }, ).collect::>(); - let iter_name = names::iter_name(name); - let iter_mut_name = names::iter_mut_name(name); - let mut generated = quote! { /// An analog to ` #[doc = #vec_name_str] @@ -471,19 +468,15 @@ pub fn derive(input: &Input) -> TokenStream { )* } } - }); - { - generated.append_all(quote! { - impl ::soa_derive::SoAAppendVec<#name> for #vec_name { - fn extend_from_slice(&mut self, other: Self::Slice<'_>) { - #( - self.#fields_names.extend_from_slice(other.#fields_names); - )* - } + impl ::soa_derive::SoAAppendVec<#name> for #vec_name { + fn extend_from_slice(&mut self, other: Self::Slice<'_>) { + #( + self.#fields_names.extend_from_slice(other.#fields_names); + )* } - }) - } + } + }); } return generated; diff --git a/src/lib.rs b/src/lib.rs index 9ef5c68..2768b94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -232,19 +232,13 @@ //! `StructOfArray` does not provide a set of common operations by default. Thus if you wanted to use a `StructOfArray` //! type in a generic context, there is no way to guarantee to the type system that any methods are available. //! -//! If the `generic_traits` feature is enabled, the attribute macro `#[generate_traits]` will generate -//! implementations of [`SoAVec`], [`SoASlice`], and [`SoASliceMut`] for the respective `Vec`, `Slice` -//! and `SliceMut` types. -//! -//! These rely on GATs, and so require Rust 1.65 or newer, and so this feature is disabled by default. -//! Even when enabled, trait implementations are only generated by opting in with the `#[generate_traits]` -//! attribute. +//! This will also generate implementations of [`SoAVec`], [`SoASlice`], and [`SoASliceMut`] for the respective +//! `Vec`, `Slice` and `SliceMut` types. These rely on GATs, and so require Rust 1.65 or newer. //! //! ```ignore //! # mod cheese { //! # use soa_derive::{StructOfArray, prelude::*}; //! #[derive(StructOfArray)] -//! #[generate_traits] //! pub struct Point { //! x: f32, //! y: f32, @@ -415,8 +409,15 @@ macro_rules! soa_zip { }}; } + +/// This trait is automatically implemented by the relevant generated by [`StructOfArray`]. +/// +/// Links a [`StructOfArray`] type to its raw pointer types, which is useful for generic +/// programming. pub trait SoAPointers { + /// The immutable pointer type for an SoA type type Ptr; + /// The mutable pointer type for an SoA type type MutPtr; } From 7dccb571cb6fb8cba33a4c61e3d0d7dacfc84504 Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Wed, 5 Mar 2025 17:47:42 -0500 Subject: [PATCH 36/37] Apply more suggestions from code review --- soa-derive-internal/src/iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soa-derive-internal/src/iter.rs b/soa-derive-internal/src/iter.rs index 6199409..0d5e646 100644 --- a/soa-derive-internal/src/iter.rs +++ b/soa-derive-internal/src/iter.rs @@ -124,7 +124,7 @@ pub fn derive(input: &Input) -> TokenStream { /// Get an iterator over the #[doc = #ref_doc_url] /// in this vector - pub fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { + pub fn iter(&self) -> #iter_name { self.as_slice().into_iter() } } From ee3f77e10640e5b5bff787afa7bdbb8d9583663c Mon Sep 17 00:00:00 2001 From: Joshua Klein Date: Mon, 17 Mar 2025 23:46:24 -0400 Subject: [PATCH 37/37] remove the prelude and alluded to in the review --- src/lib.rs | 5 ----- tests/particles/mod.rs | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2768b94..501a7e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -785,11 +785,6 @@ mod generics { } pub use generics::*; -/// A collection of supporting traits for [`StructOfArray`] bundled in one place for ease-of-access -pub mod prelude { - pub use super::{SoAVec, SoAIter, SoASlice, SoASliceMut, SoAPointers, StructOfArray, ToSoAVec, IntoSoAIter, SoAAppendVec}; -} - #[macro_export] #[doc(hidden)] diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index 65b8148..de0d589 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -1,6 +1,6 @@ use std::fmt::Debug; -use soa_derive::prelude::*; +use soa_derive::*; #[derive(Debug, Clone, PartialOrd, PartialEq, StructOfArray)] #[soa_derive(Debug, Clone, PartialOrd, PartialEq)]