From da55e50fd7ae08643ed1ac131865bdbddbbae5ad Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sun, 26 Oct 2025 09:40:14 +0000 Subject: [PATCH 1/2] Move replace self helpers to separate module --- .../cgp-macro-lib/src/derive_component/mod.rs | 6 --- .../src/derive_component/provider_trait.rs | 7 ++-- .../cgp-macro-lib/src/derive_getter/parse.rs | 2 +- .../cgp-macro-lib/src/entrypoints/cgp_impl.rs | 40 +++---------------- .../src/entrypoints/cgp_preset.rs | 2 +- crates/cgp-macro-lib/src/lib.rs | 1 + crates/cgp-macro-lib/src/replace_self/mod.rs | 9 +++++ .../replace_self_receiver.rs | 0 .../replace_self_type.rs | 0 .../src/replace_self/replace_self_var.rs | 35 ++++++++++++++++ .../snake_case.rs | 0 11 files changed, 55 insertions(+), 47 deletions(-) create mode 100644 crates/cgp-macro-lib/src/replace_self/mod.rs rename crates/cgp-macro-lib/src/{derive_component => replace_self}/replace_self_receiver.rs (100%) rename crates/cgp-macro-lib/src/{derive_component => replace_self}/replace_self_type.rs (100%) create mode 100644 crates/cgp-macro-lib/src/replace_self/replace_self_var.rs rename crates/cgp-macro-lib/src/{derive_component => replace_self}/snake_case.rs (100%) diff --git a/crates/cgp-macro-lib/src/derive_component/mod.rs b/crates/cgp-macro-lib/src/derive_component/mod.rs index 9a1b035c..30fe7f6a 100644 --- a/crates/cgp-macro-lib/src/derive_component/mod.rs +++ b/crates/cgp-macro-lib/src/derive_component/mod.rs @@ -5,14 +5,8 @@ mod delegate_type; mod derive; mod provider_impl; mod provider_trait; -mod replace_self_receiver; -mod replace_self_type; mod signature_args; -mod snake_case; mod use_context_impl; mod use_delegate_impl; pub use derive::*; -pub use replace_self_receiver::*; -pub use replace_self_type::*; -pub use snake_case::*; diff --git a/crates/cgp-macro-lib/src/derive_component/provider_trait.rs b/crates/cgp-macro-lib/src/derive_component/provider_trait.rs index 98ce49e9..c381d333 100644 --- a/crates/cgp-macro-lib/src/derive_component/provider_trait.rs +++ b/crates/cgp-macro-lib/src/derive_component/provider_trait.rs @@ -5,12 +5,11 @@ use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{Ident, ItemTrait, TraitItem, TypeParamBound, parse2}; -use crate::derive_component::replace_self_receiver::replace_self_receiver_in_signature; -use crate::derive_component::replace_self_type::{ +use crate::parse::parse_is_provider_params; +use crate::replace_self::{ iter_parse_and_replace_self_type, parse_and_replace_self_type, + replace_self_receiver_in_signature, to_snake_case_ident, }; -use crate::derive_component::to_snake_case_ident; -use crate::parse::parse_is_provider_params; pub fn derive_provider_trait( component_name: &Ident, diff --git a/crates/cgp-macro-lib/src/derive_getter/parse.rs b/crates/cgp-macro-lib/src/derive_getter/parse.rs index 9caff497..d19a8e2b 100644 --- a/crates/cgp-macro-lib/src/derive_getter/parse.rs +++ b/crates/cgp-macro-lib/src/derive_getter/parse.rs @@ -9,9 +9,9 @@ use syn::{ Signature, TraitItem, TraitItemFn, Type, TypePath, parse_quote, parse2, }; -use crate::derive_component::replace_self_type; use crate::derive_getter::getter_field::GetterField; use crate::derive_getter::{FieldMode, ReceiverMode}; +use crate::replace_self::replace_self_type; pub fn parse_getter_fields( context_type: &Ident, diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs index b93fb094..20794034 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs @@ -1,16 +1,18 @@ -use proc_macro2::{Group, Span, TokenStream, TokenTree}; -use quote::{ToTokens, format_ident, quote}; +use proc_macro2::{Span, TokenStream}; +use quote::{ToTokens, quote}; use syn::parse::discouraged::Speculative; use syn::parse::{Parse, ParseStream}; use syn::spanned::Spanned; use syn::token::{Colon, For}; use syn::{Error, FnArg, Ident, ImplItem, ItemImpl, Type, parse2}; -use crate::derive_component::{replace_self_receiver, replace_self_type, to_snake_case_ident}; use crate::derive_provider::{ derive_component_name_from_provider_impl, derive_is_provider_for, derive_provider_struct, }; use crate::parse::SimpleType; +use crate::replace_self::{ + replace_self_receiver, replace_self_type, replace_self_var, to_snake_case_ident, +}; pub fn cgp_impl(attr: TokenStream, body: TokenStream) -> syn::Result { let spec: ImplProviderSpec = parse2(attr)?; @@ -153,35 +155,3 @@ pub fn transform_impl_trait( Ok(out_impl) } - -fn replace_self_var(stream: TokenStream, replaced_ident: &Ident) -> TokenStream { - let self_ident = format_ident!("self"); - - let mut result_stream: Vec = Vec::new(); - - let token_iter = stream.into_iter(); - - for tree in token_iter { - match tree { - TokenTree::Ident(ident) => { - if ident == self_ident { - result_stream.push(TokenTree::Ident(replaced_ident.clone())); - } else { - result_stream.push(TokenTree::Ident(ident)); - } - } - TokenTree::Group(group) => { - let replaced_stream = replace_self_var(group.stream(), replaced_ident); - let replaced_group = Group::new(group.delimiter(), replaced_stream); - - result_stream.push(TokenTree::Group(replaced_group)); - } - TokenTree::Punct(punct) => { - result_stream.push(TokenTree::Punct(punct)); - } - TokenTree::Literal(lit) => result_stream.push(TokenTree::Literal(lit)), - } - } - - result_stream.into_iter().collect() -} diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs index 8d097fc2..847dfd96 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs @@ -7,9 +7,9 @@ use syn::token::{At, Comma}; use syn::{GenericParam, Ident, ItemTrait, TypeParamBound, parse_quote, parse2}; use crate::delegate_components::{define_struct, impl_delegate_components}; -use crate::derive_component::to_snake_case_str; use crate::parse::{DefinePreset, DelegateEntry, ImplGenerics, SimpleType}; use crate::preset::{define_substitution_macro, impl_components_is_preset}; +use crate::replace_self::to_snake_case_str; pub fn define_preset(body: TokenStream) -> syn::Result { let ast: DefinePreset = syn::parse2(body)?; diff --git a/crates/cgp-macro-lib/src/lib.rs b/crates/cgp-macro-lib/src/lib.rs index 4716d772..4a382da4 100644 --- a/crates/cgp-macro-lib/src/lib.rs +++ b/crates/cgp-macro-lib/src/lib.rs @@ -23,6 +23,7 @@ pub(crate) mod for_each_replace; pub(crate) mod parse; pub(crate) mod preset; pub(crate) mod product; +pub(crate) mod replace_self; pub(crate) mod symbol; pub(crate) mod type_component; diff --git a/crates/cgp-macro-lib/src/replace_self/mod.rs b/crates/cgp-macro-lib/src/replace_self/mod.rs new file mode 100644 index 00000000..630527d2 --- /dev/null +++ b/crates/cgp-macro-lib/src/replace_self/mod.rs @@ -0,0 +1,9 @@ +mod replace_self_receiver; +mod replace_self_type; +mod replace_self_var; +mod snake_case; + +pub use replace_self_receiver::*; +pub use replace_self_type::*; +pub use replace_self_var::*; +pub use snake_case::*; diff --git a/crates/cgp-macro-lib/src/derive_component/replace_self_receiver.rs b/crates/cgp-macro-lib/src/replace_self/replace_self_receiver.rs similarity index 100% rename from crates/cgp-macro-lib/src/derive_component/replace_self_receiver.rs rename to crates/cgp-macro-lib/src/replace_self/replace_self_receiver.rs diff --git a/crates/cgp-macro-lib/src/derive_component/replace_self_type.rs b/crates/cgp-macro-lib/src/replace_self/replace_self_type.rs similarity index 100% rename from crates/cgp-macro-lib/src/derive_component/replace_self_type.rs rename to crates/cgp-macro-lib/src/replace_self/replace_self_type.rs diff --git a/crates/cgp-macro-lib/src/replace_self/replace_self_var.rs b/crates/cgp-macro-lib/src/replace_self/replace_self_var.rs new file mode 100644 index 00000000..b94e6b2e --- /dev/null +++ b/crates/cgp-macro-lib/src/replace_self/replace_self_var.rs @@ -0,0 +1,35 @@ +use proc_macro2::{Group, TokenStream, TokenTree}; +use quote::format_ident; +use syn::Ident; + +pub fn replace_self_var(stream: TokenStream, replaced_ident: &Ident) -> TokenStream { + let self_ident = format_ident!("self"); + + let mut result_stream: Vec = Vec::new(); + + let token_iter = stream.into_iter(); + + for tree in token_iter { + match tree { + TokenTree::Ident(ident) => { + if ident == self_ident { + result_stream.push(TokenTree::Ident(replaced_ident.clone())); + } else { + result_stream.push(TokenTree::Ident(ident)); + } + } + TokenTree::Group(group) => { + let replaced_stream = replace_self_var(group.stream(), replaced_ident); + let replaced_group = Group::new(group.delimiter(), replaced_stream); + + result_stream.push(TokenTree::Group(replaced_group)); + } + TokenTree::Punct(punct) => { + result_stream.push(TokenTree::Punct(punct)); + } + TokenTree::Literal(lit) => result_stream.push(TokenTree::Literal(lit)), + } + } + + result_stream.into_iter().collect() +} diff --git a/crates/cgp-macro-lib/src/derive_component/snake_case.rs b/crates/cgp-macro-lib/src/replace_self/snake_case.rs similarity index 100% rename from crates/cgp-macro-lib/src/derive_component/snake_case.rs rename to crates/cgp-macro-lib/src/replace_self/snake_case.rs From d0c45e6ae48a9c1fdc15a90ca1867aad893bcee9 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sun, 26 Oct 2025 09:58:12 +0000 Subject: [PATCH 2/2] Fix use of self inside default trait method implementation body --- .../src/derive_component/provider_trait.rs | 11 ++++- .../src/replace_self/snake_case.rs | 11 +++-- .../cgp_component/default_impl.rs | 40 +++++++++++++++++++ .../component_tests/cgp_component/mod.rs | 1 + 4 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 crates/cgp-tests/tests/component_tests/cgp_component/default_impl.rs diff --git a/crates/cgp-macro-lib/src/derive_component/provider_trait.rs b/crates/cgp-macro-lib/src/derive_component/provider_trait.rs index c381d333..0e6a1f3f 100644 --- a/crates/cgp-macro-lib/src/derive_component/provider_trait.rs +++ b/crates/cgp-macro-lib/src/derive_component/provider_trait.rs @@ -8,7 +8,7 @@ use syn::{Ident, ItemTrait, TraitItem, TypeParamBound, parse2}; use crate::parse::parse_is_provider_params; use crate::replace_self::{ iter_parse_and_replace_self_type, parse_and_replace_self_type, - replace_self_receiver_in_signature, to_snake_case_ident, + replace_self_receiver_in_signature, replace_self_var, to_snake_case_ident, }; pub fn derive_provider_trait( @@ -84,6 +84,8 @@ pub fn derive_provider_trait( // Replace self type and argument into context type argument { + let context_var = to_snake_case_ident(context_type); + for item in provider_trait.items.iter_mut() { let mut replaced_item = parse_and_replace_self_type(item, context_type, &local_assoc_types)?; @@ -91,9 +93,14 @@ pub fn derive_provider_trait( if let TraitItem::Fn(func) = &mut replaced_item { replace_self_receiver_in_signature( &mut func.sig, - &to_snake_case_ident(context_type), + &context_var, context_type.to_token_stream(), ); + + if let Some(block) = &mut func.default { + let replaced = replace_self_var(block.to_token_stream(), &context_var); + *block = parse2(replaced)?; + } } *item = replaced_item; diff --git a/crates/cgp-macro-lib/src/replace_self/snake_case.rs b/crates/cgp-macro-lib/src/replace_self/snake_case.rs index c7cc504e..9a0e62ef 100644 --- a/crates/cgp-macro-lib/src/replace_self/snake_case.rs +++ b/crates/cgp-macro-lib/src/replace_self/snake_case.rs @@ -19,8 +19,11 @@ pub fn to_snake_case_str(val: &str) -> String { } pub fn to_snake_case_ident(val: &Ident) -> Ident { - Ident::new( - &format!("__{}__", to_snake_case_str(&val.to_string())), - Span::call_site(), - ) + let str_val = val.to_string(); + let mut snake_case_val = to_snake_case_str(&str_val); + if !str_val.starts_with('_') { + snake_case_val = format!("__{}__", snake_case_val); + } + + Ident::new(&snake_case_val, Span::call_site()) } diff --git a/crates/cgp-tests/tests/component_tests/cgp_component/default_impl.rs b/crates/cgp-tests/tests/component_tests/cgp_component/default_impl.rs new file mode 100644 index 00000000..0410f390 --- /dev/null +++ b/crates/cgp-tests/tests/component_tests/cgp_component/default_impl.rs @@ -0,0 +1,40 @@ +use cgp::prelude::*; + +#[cgp_getter] +pub trait HasName { + fn name(&self) -> &str { + "John" + } +} + +#[cgp_component(Greeter)] +pub trait CanGreet: HasName { + fn greet(&self) -> String { + format!("Hello, {}!", self.name()) + } +} + +pub struct UseDefault; + +#[cgp_impl(UseDefault)] +impl NameGetter for Context {} + +#[cgp_impl(UseDefault)] +impl Greeter for Context {} + +#[test] +fn test_default_method_impl() { + pub struct App; + + delegate_components! { + App { + [ + NameGetterComponent, + GreeterComponent, + ]: + UseDefault, + } + } + + assert_eq!(App.greet(), "Hello, John!"); +} diff --git a/crates/cgp-tests/tests/component_tests/cgp_component/mod.rs b/crates/cgp-tests/tests/component_tests/cgp_component/mod.rs index 78ca6b3e..a41c9ffb 100644 --- a/crates/cgp-tests/tests/component_tests/cgp_component/mod.rs +++ b/crates/cgp-tests/tests/component_tests/cgp_component/mod.rs @@ -1,3 +1,4 @@ pub mod constant; +pub mod default_impl; pub mod lifetime; pub mod sized;