From 0566a67b831b96e1500771915a86775e01d460ad Mon Sep 17 00:00:00 2001 From: "Lan, Jian" Date: Sun, 15 Feb 2026 04:28:30 +0800 Subject: [PATCH] refactor: improve pathable-macro - Rename internal helper functions - Encapsulate `From` trait field expression generation --- patchable-macro/src/context.rs | 62 +++++++++++++++++++++------------- patchable-macro/src/lib.rs | 6 ++-- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/patchable-macro/src/context.rs b/patchable-macro/src/context.rs index 0d346a1..4474e60 100644 --- a/patchable-macro/src/context.rs +++ b/patchable-macro/src/context.rs @@ -219,7 +219,7 @@ impl<'a> MacroContext<'a> { let input_struct_name = self.struct_name; let patch_struct_name = &self.patch_struct_name; - let from_body = self.generate_from_body(); + let from_method_body = self.build_from_method_body(); quote! { impl #impl_generics ::core::convert::From<#input_struct_name #type_generics> @@ -227,7 +227,7 @@ impl<'a> MacroContext<'a> { #where_clause { #[inline(always)] fn from(value: #input_struct_name #type_generics) -> Self { - #from_body + #from_method_body } } } @@ -292,29 +292,27 @@ impl<'a> MacroContext<'a> { } } - fn generate_from_body(&self) -> TokenStream2 { - let field_expressions = self.field_actions.iter().map(|action| { - let (member, expr) = match action { - FieldAction::Keep { member, .. } => (member, quote! { value.#member }), - FieldAction::Patch { member, .. } => ( - member, - quote! { ::core::convert::From::from(value.#member) }, - ), - }; - - match &self.fields { - Fields::Named(_) => quote! { #member: #expr }, - Fields::Unnamed(_) => quote! { #expr }, - Fields::Unit => quote! {}, - } - }); - - let body = quote! { #(#field_expressions),* }; - + fn build_from_method_body(&self) -> TokenStream2 { match &self.fields { - Fields::Named(_) => quote! { Self { #body } }, - Fields::Unnamed(_) => quote! { Self(#body) }, - Fields::Unit => quote! { Self }, + Fields::Named(_) => { + let field_initializers = self.field_actions.iter().map(|action| { + let member = action.member(); + let value = action.build_initializer_expr(); + quote! { #member: #value } + }); + quote! { Self { #(#field_initializers),* } } + } + Fields::Unnamed(_) => { + let field_values = self + .field_actions + .iter() + .map(|action| action.build_initializer_expr()); + quote! { Self(#(#field_values),*) } + } + Fields::Unit => { + debug_assert!(self.field_actions.is_empty()); + quote! { Self } + } } } @@ -428,6 +426,22 @@ enum FieldAction<'a> { }, } +impl<'a> FieldAction<'a> { + fn member(&self) -> &FieldMember<'a> { + match self { + FieldAction::Keep { member, .. } | FieldAction::Patch { member, .. } => member, + } + } + + fn build_initializer_expr(&self) -> TokenStream2 { + let member = self.member(); + match self { + FieldAction::Keep { .. } => quote! { value.#member }, + FieldAction::Patch { .. } => quote! { ::core::convert::From::from(value.#member) }, + } + } +} + fn patch_member(member: &FieldMember<'_>, patch_index: usize) -> TokenStream2 { match member { FieldMember::Named(name) => quote! { #name }, diff --git a/patchable-macro/src/lib.rs b/patchable-macro/src/lib.rs index 0ab551c..a67cc8b 100644 --- a/patchable-macro/src/lib.rs +++ b/patchable-macro/src/lib.rs @@ -79,7 +79,7 @@ pub fn patchable_model(_attr: TokenStream, item: TokenStream) -> TokenStream { /// When the `impl_from` feature is enabled for the macro crate, a /// `From` implementation is also generated for the patch type. pub fn derive_patchable(input: TokenStream) -> TokenStream { - derive_with(input, |ctx| { + expand(input, |ctx| { let patch_struct_def = ctx.build_patch_struct(); let patchable_trait_impl = ctx.build_patchable_trait_impl(); let from_struct_impl = IS_IMPL_FROM_ENABLED.then(|| { @@ -112,7 +112,7 @@ pub fn derive_patchable(input: TokenStream) -> TokenStream { /// - recursively calls `patch` on fields marked with `#[patchable]`, /// - respects `#[patchable(skip)]` by omitting those fields from patching. pub fn derive_patch(input: TokenStream) -> TokenStream { - derive_with(input, |ctx| { + expand(input, |ctx| { let patch_trait_impl = ctx.build_patch_trait_impl(); quote! { @@ -124,7 +124,7 @@ pub fn derive_patch(input: TokenStream) -> TokenStream { }) } -fn derive_with(input: TokenStream, f: F) -> TokenStream +fn expand(input: TokenStream, f: F) -> TokenStream where F: FnOnce(&context::MacroContext) -> TokenStream2, {