-
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
Code cleanup. Make build method generate as const #123
Changes from all commits
92ea6a5
0c3e609
a4e2490
822c46f
c0c5d77
3702691
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
use std::cell::OnceCell; | ||
use std::rc::Rc; | ||
|
||
use proc_macro2::{Ident, Span, TokenStream}; | ||
use quote::{format_ident, quote, quote_spanned, ToTokens}; | ||
use syn::parse::Error; | ||
use syn::punctuated::Punctuated; | ||
use syn::{parse_quote, GenericArgument, ItemFn, Token}; | ||
use syn::{parse_quote, Error, GenericArgument, ItemFn, Token}; | ||
|
||
use crate::field_info::{FieldBuilderAttr, FieldInfo}; | ||
use crate::mutator::Mutator; | ||
|
@@ -16,7 +18,7 @@ pub struct StructInfo<'a> { | |
pub vis: &'a syn::Visibility, | ||
pub name: &'a syn::Ident, | ||
pub generics: &'a syn::Generics, | ||
pub fields: Vec<FieldInfo<'a>>, | ||
pub fields: Box<[FieldInfo<'a>]>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was this really necessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, it is not very usefull, but the field is effectively immutable and so there is no need to take away additional 8 bytes for capacity. But the struct is already >2KiB in size so tbh no much difference |
||
|
||
pub builder_attr: TypeBuilderAttr<'a>, | ||
pub builder_name: syn::Ident, | ||
|
@@ -49,7 +51,7 @@ impl<'a> StructInfo<'a> { | |
.collect() | ||
} | ||
|
||
pub fn new(ast: &'a syn::DeriveInput, fields: impl Iterator<Item = &'a syn::Field>) -> Result<StructInfo<'a>, Error> { | ||
pub fn new(ast: &'a syn::DeriveInput, fields: impl Iterator<Item = &'a syn::Field>) -> syn::Result<Self> { | ||
let builder_attr = TypeBuilderAttr::new(&ast.attrs)?; | ||
let builder_name = builder_attr | ||
.builder_type | ||
|
@@ -70,7 +72,7 @@ impl<'a> StructInfo<'a> { | |
}) | ||
} | ||
|
||
pub fn builder_creation_impl(&self) -> Result<TokenStream, Error> { | ||
pub fn builder_creation_impl(&self) -> syn::Result<TokenStream> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TBH this is the only change I like in this PR. |
||
let StructInfo { | ||
vis, | ||
ref name, | ||
|
@@ -85,15 +87,27 @@ impl<'a> StructInfo<'a> { | |
empty_type() | ||
} | ||
})); | ||
let init_fields_expr = self.included_fields().map(|f| { | ||
f.builder_attr.via_mutators.as_ref().map_or_else( | ||
|| quote!(()), | ||
|via_mutators| { | ||
let init = &via_mutators.init; | ||
quote!((#init,)) | ||
}, | ||
) | ||
}); | ||
let builder_method_const = Rc::new(OnceCell::new()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Respectfully WTF? Looking at the code, it seems like a simple: let mut builder_method_const = true; would suffice. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Borrow checker was not happy about the moved value. It could be done with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried it locally and it worked. Had to remove the I speculate that it didn't work for you because you tried it before adding the Another option is to just do a second iteration: let builder_method_const = self
.included_fields()
.filter_map(|field| field.builder_attr.via_mutators.as_ref())
.all(|via_mutators| matches!(via_mutators.init, syn::Expr::Lit(_)))
.then(|| quote!(const)); But of course - all of this is irrelevant because #123 (comment). |
||
let init_fields_expr = self | ||
.included_fields() | ||
.map({ | ||
let builder_method_const = builder_method_const.clone(); | ||
move |f| { | ||
f.builder_attr.via_mutators.as_ref().map_or_else( | ||
idanarye marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|| quote!(()), | ||
|via_mutators| { | ||
let init = &via_mutators.init; | ||
if !matches!(init, syn::Expr::Lit(_)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like to make things explicit. If the build method is to be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, makes sense. It was just my compulsive thought to make it const when I saw the macro expansion for my usecase. But now I know that it is not so simple |
||
_ = builder_method_const.set(quote!()); | ||
} | ||
quote!((#init,)) | ||
}, | ||
) | ||
} | ||
}) | ||
.collect::<Box<[_]>>(); | ||
let builder_method_const = Rc::into_inner(builder_method_const).unwrap(); | ||
let builder_method_const = OnceCell::into_inner(builder_method_const).unwrap_or_else(|| quote!(const)); | ||
let mut all_fields_param_type: syn::TypeParam = | ||
syn::Ident::new("TypedBuilderFields", proc_macro2::Span::call_site()).into(); | ||
let all_fields_param = syn::GenericParam::Type(all_fields_param_type.clone()); | ||
|
@@ -177,10 +191,10 @@ impl<'a> StructInfo<'a> { | |
impl #impl_generics #name #ty_generics #where_clause { | ||
#builder_method_doc | ||
#[allow(dead_code, clippy::default_trait_access)] | ||
#builder_method_visibility fn #builder_method_name() -> #builder_name #generics_with_empty { | ||
#builder_method_visibility #builder_method_const fn #builder_method_name() -> #builder_name #generics_with_empty { | ||
#builder_name { | ||
fields: (#(#init_fields_expr,)*), | ||
phantom: ::core::default::Default::default(), | ||
phantom: ::core::marker::PhantomData, | ||
} | ||
} | ||
} | ||
|
@@ -206,7 +220,7 @@ impl<'a> StructInfo<'a> { | |
}) | ||
} | ||
|
||
pub fn field_impl(&self, field: &FieldInfo) -> Result<TokenStream, Error> { | ||
pub fn field_impl(&self, field: &FieldInfo<'_>) -> syn::Result<TokenStream> { | ||
let StructInfo { ref builder_name, .. } = *self; | ||
|
||
let descructuring = self.included_fields().map(|f| { | ||
|
@@ -324,12 +338,10 @@ impl<'a> StructInfo<'a> { | |
}) | ||
} | ||
|
||
pub fn required_field_impl(&self, field: &FieldInfo) -> TokenStream { | ||
let StructInfo { ref builder_name, .. } = self; | ||
pub fn required_field_impl(&self, field: &FieldInfo<'_>) -> TokenStream { | ||
let StructInfo { builder_name, .. } = self; | ||
|
||
let FieldInfo { | ||
name: ref field_name, .. | ||
} = field; | ||
let FieldInfo { name: field_name, .. } = *field; | ||
let mut builder_generics: Vec<syn::GenericArgument> = self | ||
.generics | ||
.params | ||
|
@@ -637,7 +649,7 @@ pub struct CommonDeclarationSettings { | |
} | ||
|
||
impl ApplyMeta for CommonDeclarationSettings { | ||
fn apply_meta(&mut self, expr: AttrArg) -> Result<(), Error> { | ||
fn apply_meta(&mut self, expr: AttrArg) -> syn::Result<()> { | ||
match expr.name().to_string().as_str() { | ||
"vis" => { | ||
let expr_str = expr.key_value()?.parse_value::<syn::LitStr>()?.value(); | ||
|
@@ -701,7 +713,7 @@ pub struct BuildMethodSettings { | |
} | ||
|
||
impl ApplyMeta for BuildMethodSettings { | ||
fn apply_meta(&mut self, expr: AttrArg) -> Result<(), Error> { | ||
fn apply_meta(&mut self, expr: AttrArg) -> syn::Result<()> { | ||
match expr.name().to_string().as_str() { | ||
"into" => match expr { | ||
AttrArg::Flag(_) => { | ||
|
@@ -756,8 +768,8 @@ impl Default for TypeBuilderAttr<'_> { | |
} | ||
} | ||
|
||
impl<'a> TypeBuilderAttr<'a> { | ||
pub fn new(attrs: &[syn::Attribute]) -> Result<Self, Error> { | ||
impl TypeBuilderAttr<'_> { | ||
pub fn new(attrs: &[syn::Attribute]) -> syn::Result<Self> { | ||
let mut result = Self::default(); | ||
|
||
for attr in attrs { | ||
|
@@ -784,7 +796,7 @@ impl<'a> TypeBuilderAttr<'a> { | |
} | ||
|
||
impl ApplyMeta for TypeBuilderAttr<'_> { | ||
fn apply_meta(&mut self, expr: AttrArg) -> Result<(), Error> { | ||
fn apply_meta(&mut self, expr: AttrArg) -> syn::Result<()> { | ||
match expr.name().to_string().as_str() { | ||
"crate_module_path" => { | ||
let crate_module_path = expr.key_value()?.parse_value::<syn::ExprPath>()?; | ||
|
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 seems redundant. Is this because of that
#![forbid(rust_2018_idioms)]
thing?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.
Yes. This lets to see at a glance where a borrowing occurs