-
Notifications
You must be signed in to change notification settings - Fork 29
Add opt-in generic traits for generated SoA types #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Added an additional optional type-level attribute macro |
This is unrelated to the generic trait, right? Could you split it into a separate PR? |
Regarding the main feature: it is quite a lot of new code, so I'll need to find the time to review it properly! |
From a very quick look, could you explain why we need a Also, please do not reorganize the code while contributing a feature. You moved the |
Technically no, it just required making changes to all generated code, including the newly added trait code. If you still want it split into another PR, I can revert the changes on this branch and then re-add them afterwards in a separate PR if this one is accepted.
I feature-gated this behavior because it requires GATs and you had explicitly called out a Rust version without GAT support in the CI configuration. If you want to enable the behavior all the time, while retaining the added
I wasn't able to get Cargo to recognize a feature on |
Just so I know whether to get started, do you agree I should remove the pre-GAT version of Rust from CI and restore the project layout? Thank you |
It looks like we only need to update the MSRV to 1.65 to get GAT, right? If so, I'm happy to update the MSRV here, remove the feature gate & code re-organization! EDIT: this would mean updating the pinned rustc in CI to 1.65. If 1.65 has other issues/missing parts, we could also update further, but I'm trying to make sure soa_derive is not forcing downstream projects to upgrade their rustc version. |
Yes please!
I guess this is because |
commit a1cd5b6 Author: Joshua Klein <[email protected]> Date: Sun Feb 2 13:31:10 2025 -0500 make trait implementation automatic
I have reverted changes to the project layout, made trait implementation automatic, and removed the crate name option |
It appears the minimum Rust version required to run the test suite is 1.78. The code itself might compile on an earlier Rust version though using it in a generic context would likely be constrained. |
@Luthaf just to make sure this is clear, the current state of the PR is ready for review, or at least to have the MSRV change requirement rejected so I can revert all the changes and restore the feature gate or attempt some other means of achieving the same idea without forcing the project layout to change. |
Hey @mobiusklein! Sorry for the delayed answer, both personal and work life have been taking a lot of my time recently. I'll likely have to continue dealing with it for a couple more weeks, so this might take some time, sorry in advance. Just to be clear, 1.78 is only required for the tests of the new traits, right? I'd like to keep the code in a state that can compile on recent-ish ubuntu, which is currently using 1.75. So for now bumping CI to 1.78 would be fine for me, and I can add another CI job that checks with an older version that the code still compiles, excluding the tests for the new traits. |
Thank you for the warning, not a problem. I am currently using this for prototyping, but if it advances, I may need to release a fork since I don't think vendoring works with proc-macros. This was a great way to learn about procedural macros and if I am not careful I'll rewrite more of my traits this way. Yes, that's correct. I had also looked into how hard it would be to introduce conditional compilation for a specific Rust version, but unfortunately that requires adding a build script and/or extra dependencies. At one point the GATs were actually causing a compiler crash on Rust 1.80 or 1.82, but I don't think that version of the code is being used here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good overall! There are a couple of places where I did not understand the reason behind the code, and what looks like a couple of leftover from development.
soa-derive-internal/src/iter.rs
Outdated
@@ -124,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) -> #iter_name { | |||
pub fn iter(&self) -> <#name as ::soa_derive::SoAIter>::Iter { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why this is required here?
For readbility, I find referring to the type directly better, instead of going through associated types of a trait
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was likely tying the type system in balloon animals at one point and that made the system happy, and after reverting that particular design, it remained happy with those aliases so they remained. I'll restored the generated names
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this still needs updating
src/lib.rs
Outdated
//! # mod cheese { | ||
//! # use soa_derive::{StructOfArray, prelude::*}; | ||
//! #[derive(StructOfArray)] | ||
//! #[generate_traits] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if this is up to date, but what would be the cost of always generating the trait implementations?
And if the cost is too high to always enable them, then this should be scoped with something like #[soa_derive(generate_traits)]
src/lib.rs
Outdated
pub mod prelude { | ||
pub use super::{SoAVec, SoAIter, SoASlice, SoASliceMut, SoAPointers, StructOfArray, ToSoAVec, IntoSoAIter, SoAAppendVec}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is everything defined by this crate, isn't it? I don't think it's worth having a separate prelude in this case, the same can be achieved with use soa_derive::*
instead of use soa_derive::prelude::*
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That'd also pull the soa_zip
macro and its helper, soa_zip_impl
, along with SoAIndex
, which isn't necessary to use the generic traits or the types themselves.
The prelude
also means that if in the future you were to add more things to the crate root, they would only be pulled by a wildcard import if they were also added to the prelude. This is probably overly defensive future-proofing though.
If you still think this is acceptable, I'm fine with removing the prelude
module.
Co-authored-by: Guillaume Fraux <[email protected]>
Co-authored-by: Guillaume Fraux <[email protected]>
Co-authored-by: Guillaume Fraux <[email protected]>
There were a lot of things left over from development, thank you for noting that. I had tried several different overlapping designs to try to find a way out of the corners I was painting myself into with the type system. At one point it was even crashing rustc 1.82. I'll go through the documentation again now that the implementation is more-or-less acceptable. Thank you. |
Can you please re-iterate your ruling on the |
Let's remove the prelude for now, we can always add it back down the line if it is needed, but for now I don't think it is worth doing. Thanks for your patience with this! I'll try to do a final review tomorrow, but I think the code is in a great shape overall! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for this work! I'll try to make the code work on CI with an earlier rustc, and then make a new release with this
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() | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, this makes sense. Thanks for the detailed explanation!
Now published as v0.14.0 on crates.io! |
This adds
SoASlice
,SoASliceMut
, andSoAVec
traits and adds a new attribute#[generate_traits]
to automatically implement them on the generated types.Because I saw a specific Rust version pinned in the test suite that predated the stabilization of GATs, I had to feature-gate the traits on both the internal and public-facing crates. Unfortunately, the mixed root + internal crates workspace setup didn't seem to support traits on the crate at the repository root, so I had to re-structure repository to a uniform workspace. The traits still exist when the
generic_traits
feature is disabled, but they have no methods or associated types so the source code is still Rust 1.63 compatible.Hopefully, that means there are no breaking changes unless the feature is enabled.
I couldn't implement a clean "root trait" that tied all of the different types and interfaces together. I could not find a way to do so while not generating a type system query overflow or cycle or cease to function as lifetime dependencies tangled. I'm still not satisfied with the API, but I've convinced myself that as the language stands today I can't make it any better.