From 92ea6a56a0905eee3b456f06a2e68c45ef9e329e Mon Sep 17 00:00:00 2001 From: Danik Vitek Date: Sun, 15 Oct 2023 21:48:17 +0300 Subject: [PATCH 1/5] Code cleanup. Make build method generate as const --- typed-builder-macro/src/lib.rs | 2 ++ typed-builder-macro/src/mutator.rs | 2 +- typed-builder-macro/src/struct_info.rs | 31 ++++++++++++-------------- typed-builder-macro/src/util.rs | 16 ++++++++----- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/typed-builder-macro/src/lib.rs b/typed-builder-macro/src/lib.rs index a33292eb..5c15d06c 100644 --- a/typed-builder-macro/src/lib.rs +++ b/typed-builder-macro/src/lib.rs @@ -1,3 +1,5 @@ +#![forbid(rust_2018_idioms)] + use proc_macro2::TokenStream; use quote::quote; use syn::{parse::Error, parse_macro_input, spanned::Spanned, DeriveInput}; diff --git a/typed-builder-macro/src/mutator.rs b/typed-builder-macro/src/mutator.rs index 90bae1fd..bae937f4 100644 --- a/typed-builder-macro/src/mutator.rs +++ b/typed-builder-macro/src/mutator.rs @@ -52,7 +52,7 @@ impl ApplyMeta for MutatorAttribute { } impl Parse for Mutator { - fn parse(input: ParseStream) -> syn::Result { + fn parse(input: ParseStream<'_>) -> syn::Result { let mut fun: ItemFn = input.parse()?; let mut attribute = MutatorAttribute::default(); diff --git a/typed-builder-macro/src/struct_info.rs b/typed-builder-macro/src/struct_info.rs index 077bb812..211ee4f9 100644 --- a/typed-builder-macro/src/struct_info.rs +++ b/typed-builder-macro/src/struct_info.rs @@ -1,8 +1,7 @@ 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; @@ -49,7 +48,7 @@ impl<'a> StructInfo<'a> { .collect() } - pub fn new(ast: &'a syn::DeriveInput, fields: impl Iterator) -> Result, Error> { + pub fn new(ast: &'a syn::DeriveInput, fields: impl Iterator) -> syn::Result { let builder_attr = TypeBuilderAttr::new(&ast.attrs)?; let builder_name = builder_attr .builder_type @@ -70,7 +69,7 @@ impl<'a> StructInfo<'a> { }) } - pub fn builder_creation_impl(&self) -> Result { + pub fn builder_creation_impl(&self) -> syn::Result { let StructInfo { vis, ref name, @@ -177,10 +176,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 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 +205,7 @@ impl<'a> StructInfo<'a> { }) } - pub fn field_impl(&self, field: &FieldInfo) -> Result { + pub fn field_impl(&self, field: &FieldInfo<'_>) -> syn::Result { let StructInfo { ref builder_name, .. } = *self; let descructuring = self.included_fields().map(|f| { @@ -324,12 +323,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 = self .generics .params @@ -637,7 +634,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::()?.value(); @@ -701,7 +698,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 +753,8 @@ impl Default for TypeBuilderAttr<'_> { } } -impl<'a> TypeBuilderAttr<'a> { - pub fn new(attrs: &[syn::Attribute]) -> Result { +impl TypeBuilderAttr<'_> { + pub fn new(attrs: &[syn::Attribute]) -> syn::Result { let mut result = Self::default(); for attr in attrs { @@ -784,7 +781,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::()?; diff --git a/typed-builder-macro/src/util.rs b/typed-builder-macro/src/util.rs index e402d328..158b61dc 100644 --- a/typed-builder-macro/src/util.rs +++ b/typed-builder-macro/src/util.rs @@ -64,7 +64,7 @@ pub fn empty_type_tuple() -> syn::TypeTuple { } } -pub fn modify_types_generics_hack(ty_generics: &syn::TypeGenerics, mut mutator: F) -> syn::AngleBracketedGenericArguments +pub fn modify_types_generics_hack(ty_generics: &syn::TypeGenerics<'_>, mut mutator: F) -> syn::AngleBracketedGenericArguments where F: FnMut(&mut syn::punctuated::Punctuated), { @@ -212,7 +212,7 @@ impl ToTokens for KeyValue { } impl Parse for KeyValue { - fn parse(input: syn::parse::ParseStream) -> syn::Result { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { Ok(Self { name: input.parse()?, eq: input.parse()?, @@ -232,7 +232,8 @@ impl SubAttr { Punctuated::::parse_terminated.parse2(self.args) } pub fn undelimited(self) -> syn::Result> { - (|p: ParseStream| iter::from_fn(|| (!p.is_empty()).then(|| p.parse())).collect::>>()).parse2(self.args) + (|p: ParseStream<'_>| iter::from_fn(|| (!p.is_empty()).then(|| p.parse())).collect::>>()) + .parse2(self.args) } } @@ -243,7 +244,7 @@ impl ToTokens for SubAttr { } } -fn get_cursor_after_parsing(input: syn::parse::ParseBuffer) -> syn::Result { +fn get_cursor_after_parsing(input: syn::parse::ParseBuffer<'_>) -> syn::Result> { let parse_attempt: P = input.parse()?; let cursor = input.cursor(); if cursor.eof() || input.peek(Token![,]) { @@ -256,7 +257,10 @@ fn get_cursor_after_parsing(input: syn::parse::ParseBuffer) } } -fn get_token_stream_up_to_cursor(input: syn::parse::ParseStream, cursor: syn::buffer::Cursor) -> syn::Result { +fn get_token_stream_up_to_cursor( + input: syn::parse::ParseStream<'_>, + cursor: syn::buffer::Cursor<'_>, +) -> syn::Result { Ok(core::iter::from_fn(|| { if input.cursor() < cursor { input.parse::().ok() @@ -268,7 +272,7 @@ fn get_token_stream_up_to_cursor(input: syn::parse::ParseStream, cursor: syn::bu } impl Parse for AttrArg { - fn parse(input: syn::parse::ParseStream) -> syn::Result { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { if input.peek(Token![!]) { Ok(Self::Not { not: input.parse()?, From 0c3e6092d74192089c988ee4f0744e53ac50a73b Mon Sep 17 00:00:00 2001 From: Danik Vitek Date: Sun, 15 Oct 2023 22:28:19 +0300 Subject: [PATCH 2/5] Fix builder method being const when impossible --- typed-builder-macro/src/struct_info.rs | 33 ++++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/typed-builder-macro/src/struct_info.rs b/typed-builder-macro/src/struct_info.rs index 211ee4f9..42bd5817 100644 --- a/typed-builder-macro/src/struct_info.rs +++ b/typed-builder-macro/src/struct_info.rs @@ -1,3 +1,5 @@ +use std::cell::OnceCell; + use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote, quote_spanned, ToTokens}; use syn::punctuated::Punctuated; @@ -84,15 +86,26 @@ 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 = std::rc::Rc::new(OnceCell::new()); + 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( + || quote!(()), + |via_mutators| { + let init = &via_mutators.init; + if !matches!(init, syn::Expr::Lit(_)) { + _ = builder_method_const.set(quote!()); + } + quote!((#init,)) + }, + ) + } + }) + .collect::>(); + let builder_method_const = builder_method_const.get_or_init(|| 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()); @@ -176,7 +189,7 @@ 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 const 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::marker::PhantomData, From a4e2490495546938dfdeea46d85e0506de9fce4b Mon Sep 17 00:00:00 2001 From: Danik Vitek Date: Sun, 15 Oct 2023 22:35:28 +0300 Subject: [PATCH 3/5] Unwrap `Rc` and `OnceCell` --- typed-builder-macro/src/struct_info.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/typed-builder-macro/src/struct_info.rs b/typed-builder-macro/src/struct_info.rs index 42bd5817..fd8bdb9a 100644 --- a/typed-builder-macro/src/struct_info.rs +++ b/typed-builder-macro/src/struct_info.rs @@ -1,4 +1,5 @@ use std::cell::OnceCell; +use std::rc::Rc; use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote, quote_spanned, ToTokens}; @@ -105,7 +106,8 @@ impl<'a> StructInfo<'a> { } }) .collect::>(); - let builder_method_const = builder_method_const.get_or_init(|| quote!(const)); + 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()); From 822c46fce67d725fae5224296ab0e3eba313c4dd Mon Sep 17 00:00:00 2001 From: Danik Vitek Date: Sun, 15 Oct 2023 22:35:28 +0300 Subject: [PATCH 4/5] Unwrap `Rc` and `OnceCell` --- typed-builder-macro/src/struct_info.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/typed-builder-macro/src/struct_info.rs b/typed-builder-macro/src/struct_info.rs index 42bd5817..82af5d3c 100644 --- a/typed-builder-macro/src/struct_info.rs +++ b/typed-builder-macro/src/struct_info.rs @@ -1,4 +1,5 @@ use std::cell::OnceCell; +use std::rc::Rc; use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote, quote_spanned, ToTokens}; @@ -86,7 +87,7 @@ impl<'a> StructInfo<'a> { empty_type() } })); - let builder_method_const = std::rc::Rc::new(OnceCell::new()); + let builder_method_const = Rc::new(OnceCell::new()); let init_fields_expr = self .included_fields() .map({ @@ -105,7 +106,8 @@ impl<'a> StructInfo<'a> { } }) .collect::>(); - let builder_method_const = builder_method_const.get_or_init(|| quote!(const)); + 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()); From 370269183fbf017446307183f3f29a7de3118eb6 Mon Sep 17 00:00:00 2001 From: Danik Vitek Date: Sun, 15 Oct 2023 23:23:39 +0300 Subject: [PATCH 5/5] Make `fields` a boxed slice Because it's immutable --- typed-builder-macro/src/struct_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typed-builder-macro/src/struct_info.rs b/typed-builder-macro/src/struct_info.rs index 82af5d3c..399570f2 100644 --- a/typed-builder-macro/src/struct_info.rs +++ b/typed-builder-macro/src/struct_info.rs @@ -18,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>, + pub fields: Box<[FieldInfo<'a>]>, pub builder_attr: TypeBuilderAttr<'a>, pub builder_name: syn::Ident,