-
Notifications
You must be signed in to change notification settings - Fork 52
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
Specify default field value for field with type that uses generic parameters with defaults #73
base: master
Are you sure you want to change the base?
Conversation
…t values if the field types using those generic params impl Default
…eld's type if all generic parameters in the type have default values provided or there are no generic parameters at all
…ons using this library
…d without defaults were not properly suffixing the generic types currently existing on the builder
…pplied in order for a field to have a default value set
@@ -29,18 +40,137 @@ impl<'a> StructInfo<'a> { | |||
pub fn new(ast: &'a syn::DeriveInput, fields: impl Iterator<Item = &'a syn::Field>) -> Result<StructInfo<'a>, Error> { | |||
let builder_attr = TypeBuilderAttr::new(&ast.attrs)?; | |||
let builder_name = strip_raw_ident_prefix(format!("{}Builder", ast.ident)); | |||
|
|||
let mut generics_without_defaults = ast.generics.clone(); | |||
generics_without_defaults.params = generics_without_defaults |
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.
Wouldn't it be easier change them in-place? Something like (haven't tested it):
for param in generics_without_defaults.params.iter_mut() {
match param {
syn::GenericParam::Type(type_param) => {
type_param.eq_token = None;
type_param.default = None;
}
syn::GenericParam::Const(const_param) => {
const_param.eq_token = None;
const_param.default = None;
}
_ => {}
}
}
.into_iter() | ||
.map::<Result<syn::GenericArgument, _>, _>(|param| match param { | ||
syn::GenericParam::Type(type_param) => match type_param.default { | ||
Some(default) => syn::parse(proc_macro::TokenStream::from(quote!(#default))), |
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.
}) | ||
.collect(); | ||
|
||
let ty_generics_with_defaults: Punctuated<_, syn::token::Comma> = ast |
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.
If I'm understanding the code correctly, does this mean that you are generating a list of all the generics for passing to things that accept generic parameters, where the generics with default type/value will have that type and the ones without will just have their identifiers? So e.g. <A, B = usize, const C: usize, const D: usize = 7>
(yes, I know it's without the <>
, I added them for aesthetics) will become <A, usize, C, 7>
?
If so, the name is a bit misleading - it implies either that we are getting the generics together with their default values, or that we are getting only the generics that have a default values (the other ones are removed)
let ty = &field.ty; | ||
let mut ty_str = format!("{}", quote! { #ty }); | ||
for (generic_param, regular_expression, default_type) in generic_defaults.iter() { | ||
if regular_expression.is_match(&ty_str) { |
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.
Are you doing this to determine if the type depends on the generic parameter? I'd prefer doing this with https://docs.rs/syn/latest/syn/visit/index.html
Closes #44
This would support the example in #44
if and only if a default generic type is specified for
T
like so#44 (comment)
I totally agree with your assessment here. Specifying the default type for generic parameters in order to enable this feature feels like a happy medium since it keeps all the default type information in the struct signature.
I also added some tests and examples which show how this new feature interacts with more complex types that use both generic parameters with and without defaults. The code might not be the cleanest at the moment, just wanted to get a working model up first and then can refactor as needed. Let me know what you think!