From e45d714afb9fc5adda3c89ab3049ae7b19b27ea0 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 26 May 2026 22:56:07 +0200 Subject: [PATCH 01/46] Rename and move ImplArgs --- .../src/types/cgp_impl/args.rs} | 6 +++--- .../cgp-macro-core/src/types/cgp_impl/mod.rs | 3 +++ crates/cgp-macro-core/src/types/mod.rs | 1 + .../src/types/namespace/ident.rs | 18 ------------------ .../cgp-macro-core/src/types/namespace/mod.rs | 2 -- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 8 +++----- crates/cgp-macro-lib/src/cgp_impl/mod.rs | 2 -- .../cgp-macro-lib/src/entrypoints/cgp_impl.rs | 5 +++-- 8 files changed, 13 insertions(+), 32 deletions(-) rename crates/{cgp-macro-lib/src/cgp_impl/spec.rs => cgp-macro-core/src/types/cgp_impl/args.rs} (91%) create mode 100644 crates/cgp-macro-core/src/types/cgp_impl/mod.rs delete mode 100644 crates/cgp-macro-core/src/types/namespace/ident.rs diff --git a/crates/cgp-macro-lib/src/cgp_impl/spec.rs b/crates/cgp-macro-core/src/types/cgp_impl/args.rs similarity index 91% rename from crates/cgp-macro-lib/src/cgp_impl/spec.rs rename to crates/cgp-macro-core/src/types/cgp_impl/args.rs index 5c7dcc34..985590f9 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/spec.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/args.rs @@ -3,13 +3,13 @@ use syn::parse::{Parse, ParseStream}; use syn::token::Colon; use syn::{Ident, Type}; -pub struct ImplProviderSpec { +pub struct ImplArgs { pub new_struct: bool, pub provider_type: Type, pub component_type: Option, } -impl Parse for ImplProviderSpec { +impl Parse for ImplArgs { fn parse(input: ParseStream) -> syn::Result { let new_struct = { let fork = input.fork(); @@ -32,7 +32,7 @@ impl Parse for ImplProviderSpec { None }; - Ok(ImplProviderSpec { + Ok(ImplArgs { new_struct, provider_type, component_type, diff --git a/crates/cgp-macro-core/src/types/cgp_impl/mod.rs b/crates/cgp-macro-core/src/types/cgp_impl/mod.rs new file mode 100644 index 00000000..b1eedd04 --- /dev/null +++ b/crates/cgp-macro-core/src/types/cgp_impl/mod.rs @@ -0,0 +1,3 @@ +mod args; + +pub use args::*; diff --git a/crates/cgp-macro-core/src/types/mod.rs b/crates/cgp-macro-core/src/types/mod.rs index 166a4e6d..822a5f98 100644 --- a/crates/cgp-macro-core/src/types/mod.rs +++ b/crates/cgp-macro-core/src/types/mod.rs @@ -1,3 +1,4 @@ +pub mod cgp_impl; pub mod delegate_component; pub mod generics; pub mod ident_type; diff --git a/crates/cgp-macro-core/src/types/namespace/ident.rs b/crates/cgp-macro-core/src/types/namespace/ident.rs deleted file mode 100644 index 2aa80364..00000000 --- a/crates/cgp-macro-core/src/types/namespace/ident.rs +++ /dev/null @@ -1,18 +0,0 @@ -use syn::Ident; -use syn::parse::{Parse, ParseStream}; - -use crate::types::generics::TypeGenerics; - -pub struct NamespaceIdent { - pub ident: Ident, - pub generics: TypeGenerics, -} - -impl Parse for NamespaceIdent { - fn parse(input: ParseStream) -> syn::Result { - let ident = input.parse()?; - let generics = input.parse()?; - - Ok(Self { ident, generics }) - } -} diff --git a/crates/cgp-macro-core/src/types/namespace/mod.rs b/crates/cgp-macro-core/src/types/namespace/mod.rs index d8f487b1..d3292a9d 100644 --- a/crates/cgp-macro-core/src/types/namespace/mod.rs +++ b/crates/cgp-macro-core/src/types/namespace/mod.rs @@ -1,9 +1,7 @@ mod eval; -mod ident; mod inherit; mod table; pub use eval::*; -pub use ident::*; pub use inherit::*; pub use table::*; diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index d0460e67..f254585c 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -1,3 +1,4 @@ +use cgp_macro_core::types::cgp_impl::ImplArgs; use proc_macro2::TokenStream; use quote::quote; use syn::punctuated::Punctuated; @@ -8,15 +9,12 @@ use syn::{Error, ItemImpl, TypeParamBound, parse_quote, parse2}; use crate::cgp_fn::{apply_use_type_attributes_to_item_impl, build_implicit_args_bounds}; use crate::cgp_impl::attributes::parse_impl_attributes; use crate::cgp_impl::provider_bounds::derive_provider_bounds; -use crate::cgp_impl::{ImplProviderSpec, derive_provider_impl, implicit_args}; +use crate::cgp_impl::{derive_provider_impl, implicit_args}; use crate::derive_provider::{ derive_component_name_from_provider_impl, derive_is_provider_for, derive_provider_struct, }; -pub fn derive_cgp_impl( - spec: ImplProviderSpec, - mut item_impl: ItemImpl, -) -> syn::Result { +pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result { let attributes = parse_impl_attributes(&mut item_impl.attrs)?; let implicit_args = implicit_args::extract_implicit_args_from_impl_items(&mut item_impl.items)?; diff --git a/crates/cgp-macro-lib/src/cgp_impl/mod.rs b/crates/cgp-macro-lib/src/cgp_impl/mod.rs index 79e49bc4..b0e2e102 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/mod.rs @@ -3,13 +3,11 @@ mod derive; mod implicit_args; mod provider_bounds; mod provider_impl; -mod spec; mod transform; mod use_provider; pub use derive::*; pub use provider_bounds::*; pub use provider_impl::*; -pub use spec::*; pub use transform::*; pub use use_provider::*; diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs index 199b9029..f5ac31ab 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs @@ -1,10 +1,11 @@ +use cgp_macro_core::types::cgp_impl::ImplArgs; use proc_macro2::TokenStream; use syn::{ItemImpl, parse2}; -use crate::cgp_impl::{ImplProviderSpec, derive_cgp_impl}; +use crate::cgp_impl::derive_cgp_impl; pub fn cgp_impl(attr: TokenStream, body: TokenStream) -> syn::Result { - let spec: ImplProviderSpec = parse2(attr)?; + let spec: ImplArgs = parse2(attr)?; let item_impl: ItemImpl = parse2(body)?; derive_cgp_impl(spec, item_impl) From 87844e785320fc70388a3982bc541ab69de7c4fe Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 26 May 2026 23:01:13 +0200 Subject: [PATCH 02/46] Use keyword in ImplArgs --- crates/cgp-macro-core/src/traits/keyword.rs | 18 +++++++++++++++ .../cgp-macro-core/src/types/cgp_impl/args.rs | 23 +++++++------------ .../types/delegate_component/table/main.rs | 8 ++----- .../src/types/namespace/table.rs | 8 ++----- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 2 +- 5 files changed, 31 insertions(+), 28 deletions(-) diff --git a/crates/cgp-macro-core/src/traits/keyword.rs b/crates/cgp-macro-core/src/traits/keyword.rs index 125c7937..c7d3ef6e 100644 --- a/crates/cgp-macro-core/src/traits/keyword.rs +++ b/crates/cgp-macro-core/src/traits/keyword.rs @@ -1,6 +1,8 @@ use syn::Ident; use syn::parse::ParseBuffer; +use crate::types::keyword::Keyword; + pub trait IsKeyword { const IDENT: &'static str; } @@ -20,3 +22,19 @@ impl<'a> PeekKeyword for ParseBuffer<'a> { } } } + +pub trait ParseOptionalKeyword { + fn parse_optional_keyword(&self) -> syn::Result>>; +} + +impl<'a> ParseOptionalKeyword for ParseBuffer<'a> { + fn parse_optional_keyword(&self) -> syn::Result>> { + let keyword = if self.peek_keyword::() { + Some(self.parse()?) + } else { + None + }; + + Ok(keyword) + } +} diff --git a/crates/cgp-macro-core/src/types/cgp_impl/args.rs b/crates/cgp-macro-core/src/types/cgp_impl/args.rs index 985590f9..2b1ad9dd 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/args.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/args.rs @@ -1,27 +1,20 @@ -use syn::parse::discouraged::Speculative; +use syn::Type; use syn::parse::{Parse, ParseStream}; use syn::token::Colon; -use syn::{Ident, Type}; + +use crate::traits::ParseOptionalKeyword; +use crate::types::keyword::Keyword; +use crate::types::keywords::New; pub struct ImplArgs { - pub new_struct: bool, + pub new: Option>, pub provider_type: Type, pub component_type: Option, } impl Parse for ImplArgs { fn parse(input: ParseStream) -> syn::Result { - let new_struct = { - let fork = input.fork(); - let new_ident: Option = fork.parse().ok(); - match new_ident { - Some(new_ident) if new_ident == "new" => { - input.advance_to(&fork); - true - } - _ => false, - } - }; + let new = input.parse_optional_keyword()?; let provider_type = input.parse()?; @@ -33,7 +26,7 @@ impl Parse for ImplArgs { }; Ok(ImplArgs { - new_struct, + new, provider_type, component_type, }) diff --git a/crates/cgp-macro-core/src/types/delegate_component/table/main.rs b/crates/cgp-macro-core/src/types/delegate_component/table/main.rs index 6a5bb9db..107dfb7f 100644 --- a/crates/cgp-macro-core/src/types/delegate_component/table/main.rs +++ b/crates/cgp-macro-core/src/types/delegate_component/table/main.rs @@ -3,7 +3,7 @@ use quote::ToTokens; use syn::parse::{Parse, ParseStream}; use syn::{ItemImpl, ItemStruct, Type, braced, parse2}; -use crate::traits::PeekKeyword; +use crate::traits::ParseOptionalKeyword; use crate::types::delegate_component::{DelegateEntries, ExtractInnerDelegateTables}; use crate::types::generics::ImplGenerics; use crate::types::ident_type::IdentType; @@ -27,11 +27,7 @@ impl Parse for DelegateTable { fn parse(input: ParseStream) -> syn::Result { let impl_generics = input.parse()?; - let new = if input.peek_keyword::() { - Some(input.parse()?) - } else { - None - }; + let new = input.parse_optional_keyword()?; let table_type = input.parse()?; diff --git a/crates/cgp-macro-core/src/types/namespace/table.rs b/crates/cgp-macro-core/src/types/namespace/table.rs index d84b9400..d0078262 100644 --- a/crates/cgp-macro-core/src/types/namespace/table.rs +++ b/crates/cgp-macro-core/src/types/namespace/table.rs @@ -2,7 +2,7 @@ use syn::parse::{Parse, ParseStream}; use syn::token::Colon; use syn::{Error, Ident, ItemImpl, ItemStruct, ItemTrait, Type, braced, parse_quote}; -use crate::traits::PeekKeyword; +use crate::traits::ParseOptionalKeyword; use crate::types::delegate_component::{ DelegateEntries, EvalDelegateEntries, EvalDelegateEntry, EvalForEntry, }; @@ -24,11 +24,7 @@ impl Parse for NamespaceTable { fn parse(input: ParseStream) -> syn::Result { let impl_generics = input.parse()?; - let new = if input.peek_keyword::() { - Some(input.parse()?) - } else { - None - }; + let new = input.parse_optional_keyword()?; let namespace_type = input.parse()?; let parent_namespace = if input.peek(Colon) { diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index f254585c..865e79f5 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -79,7 +79,7 @@ pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result Date: Tue, 26 May 2026 23:29:30 +0200 Subject: [PATCH 03/46] Refactor replace_provider_in_generics --- .../cgp-macro-core/src/types/cgp_impl/item.rs | 8 +++++ .../cgp-macro-core/src/types/cgp_impl/mod.rs | 2 ++ .../src/types/cgp_provider/item.rs | 6 ++++ .../src/types/cgp_provider/mod.rs | 3 ++ crates/cgp-macro-core/src/types/mod.rs | 1 + .../src/derive_provider/replace_constraint.rs | 35 +++++++++---------- 6 files changed, 36 insertions(+), 19 deletions(-) create mode 100644 crates/cgp-macro-core/src/types/cgp_impl/item.rs create mode 100644 crates/cgp-macro-core/src/types/cgp_provider/item.rs create mode 100644 crates/cgp-macro-core/src/types/cgp_provider/mod.rs diff --git a/crates/cgp-macro-core/src/types/cgp_impl/item.rs b/crates/cgp-macro-core/src/types/cgp_impl/item.rs new file mode 100644 index 00000000..08c6c660 --- /dev/null +++ b/crates/cgp-macro-core/src/types/cgp_impl/item.rs @@ -0,0 +1,8 @@ +use syn::ItemImpl; + +use crate::types::cgp_impl::ImplArgs; + +pub struct ItemCgpImpl { + pub args: ImplArgs, + pub item_impl: ItemImpl, +} diff --git a/crates/cgp-macro-core/src/types/cgp_impl/mod.rs b/crates/cgp-macro-core/src/types/cgp_impl/mod.rs index b1eedd04..d05a74f5 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/mod.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/mod.rs @@ -1,3 +1,5 @@ mod args; +mod item; pub use args::*; +pub use item::*; diff --git a/crates/cgp-macro-core/src/types/cgp_provider/item.rs b/crates/cgp-macro-core/src/types/cgp_provider/item.rs new file mode 100644 index 00000000..c24969cd --- /dev/null +++ b/crates/cgp-macro-core/src/types/cgp_provider/item.rs @@ -0,0 +1,6 @@ +use syn::{ItemImpl, Type}; + +pub struct ItemCgpProvider { + pub component_type: Option, + pub item_impl: ItemImpl, +} diff --git a/crates/cgp-macro-core/src/types/cgp_provider/mod.rs b/crates/cgp-macro-core/src/types/cgp_provider/mod.rs new file mode 100644 index 00000000..95e0a691 --- /dev/null +++ b/crates/cgp-macro-core/src/types/cgp_provider/mod.rs @@ -0,0 +1,3 @@ +mod item; + +pub use item::*; diff --git a/crates/cgp-macro-core/src/types/mod.rs b/crates/cgp-macro-core/src/types/mod.rs index 822a5f98..38e287f9 100644 --- a/crates/cgp-macro-core/src/types/mod.rs +++ b/crates/cgp-macro-core/src/types/mod.rs @@ -1,4 +1,5 @@ pub mod cgp_impl; +pub mod cgp_provider; pub mod delegate_component; pub mod generics; pub mod ident_type; diff --git a/crates/cgp-macro-lib/src/derive_provider/replace_constraint.rs b/crates/cgp-macro-lib/src/derive_provider/replace_constraint.rs index 3cf89bea..f7bbf9b4 100644 --- a/crates/cgp-macro-lib/src/derive_provider/replace_constraint.rs +++ b/crates/cgp-macro-lib/src/derive_provider/replace_constraint.rs @@ -2,35 +2,32 @@ use std::collections::BTreeMap; use syn::punctuated::Punctuated; use syn::token::{Comma, Plus}; +use syn::visit_mut::{VisitMut, visit_generics_mut}; use syn::{ - GenericArgument, GenericParam, Generics, Ident, PathArguments, Type, TypeParamBound, - WherePredicate, parse_quote, + GenericArgument, Generics, Ident, PathArguments, PredicateType, Type, TypeParam, + TypeParamBound, parse_quote, }; pub fn replace_provider_in_generics(provider_map: &BTreeMap, generics: &mut Generics) { - for param in &mut generics.params { - if let GenericParam::Type(type_param) = param { - replace_provider_in_type_params(provider_map, &mut type_param.bounds); - } - } + let mut visitor = ReplaceProviderVisitor { provider_map }; + visit_generics_mut(&mut visitor, generics); +} - if let Some(where_clause) = &mut generics.where_clause { - replace_provider_in_where_predicate(provider_map, &mut where_clause.predicates); - } +struct ReplaceProviderVisitor<'a> { + provider_map: &'a BTreeMap, } -pub fn replace_provider_in_where_predicate( - provider_map: &BTreeMap, - predicates: &mut Punctuated, -) { - for predicate in predicates.iter_mut() { - if let WherePredicate::Type(type_predicate) = predicate { - replace_provider_in_type_params(provider_map, &mut type_predicate.bounds); - } +impl<'a> VisitMut for ReplaceProviderVisitor<'a> { + fn visit_type_param_mut(&mut self, type_param: &mut TypeParam) { + replace_provider_in_type_params(self.provider_map, &mut type_param.bounds); + } + + fn visit_predicate_type_mut(&mut self, type_predicate: &mut PredicateType) { + replace_provider_in_type_params(self.provider_map, &mut type_predicate.bounds); } } -pub fn replace_provider_in_type_params( +fn replace_provider_in_type_params( provider_map: &BTreeMap, type_params: &mut Punctuated, ) { From 97e582e7bfb4af4927a1f31462c6be7635d357c5 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 29 May 2026 20:50:05 +0200 Subject: [PATCH 04/46] Rename replace_self_var to replace_self_value --- crates/cgp-macro-lib/src/cgp_impl/transform.rs | 9 +++++---- .../cgp-macro-lib/src/derive_component/provider_trait.rs | 8 ++++---- crates/cgp-macro-lib/src/replace_self/mod.rs | 4 ++-- .../{replace_self_var.rs => replace_self_value.rs} | 4 ++-- 4 files changed, 13 insertions(+), 12 deletions(-) rename crates/cgp-macro-lib/src/replace_self/{replace_self_var.rs => replace_self_value.rs} (85%) diff --git a/crates/cgp-macro-lib/src/cgp_impl/transform.rs b/crates/cgp-macro-lib/src/cgp_impl/transform.rs index 57d804dc..b670e3a9 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/transform.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/transform.rs @@ -5,7 +5,7 @@ use syn::{FnArg, Ident, ImplItem, ItemImpl, Type, parse2}; use crate::parse::SimpleType; use crate::replace_self::{ - replace_self_receiver, replace_self_type, replace_self_var, to_snake_case_ident, + replace_self_receiver, replace_self_type, replace_self_value, to_snake_case_ident, }; pub fn transform_impl_trait( @@ -14,7 +14,7 @@ pub fn transform_impl_trait( provider_type: &Type, context_type: &Type, ) -> syn::Result { - let context_var = if let Ok(ident) = parse2::(context_type.to_token_stream()) { + let context_value = if let Ok(ident) = parse2::(context_type.to_token_stream()) { to_snake_case_ident(&ident) } else { Ident::new("__context__", Span::call_site()) @@ -69,9 +69,10 @@ pub fn transform_impl_trait( && let Some(arg) = item_fn.sig.inputs.first_mut() && let FnArg::Receiver(receiver) = arg { - *arg = replace_self_receiver(receiver, &context_var, context_type.to_token_stream()); + *arg = replace_self_receiver(receiver, &context_value, context_type.to_token_stream()); - let replaced_block = replace_self_var(item_fn.block.to_token_stream(), &context_var); + let replaced_block = + replace_self_value(item_fn.block.to_token_stream(), &context_value); item_fn.block = parse2(replaced_block)?; } } 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 0e6a1f3f..cb58d899 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, replace_self_var, to_snake_case_ident, + replace_self_receiver_in_signature, replace_self_value, to_snake_case_ident, }; pub fn derive_provider_trait( @@ -84,7 +84,7 @@ pub fn derive_provider_trait( // Replace self type and argument into context type argument { - let context_var = to_snake_case_ident(context_type); + let context_value = to_snake_case_ident(context_type); for item in provider_trait.items.iter_mut() { let mut replaced_item = @@ -93,12 +93,12 @@ pub fn derive_provider_trait( if let TraitItem::Fn(func) = &mut replaced_item { replace_self_receiver_in_signature( &mut func.sig, - &context_var, + &context_value, context_type.to_token_stream(), ); if let Some(block) = &mut func.default { - let replaced = replace_self_var(block.to_token_stream(), &context_var); + let replaced = replace_self_value(block.to_token_stream(), &context_value); *block = parse2(replaced)?; } } diff --git a/crates/cgp-macro-lib/src/replace_self/mod.rs b/crates/cgp-macro-lib/src/replace_self/mod.rs index 630527d2..ae067e07 100644 --- a/crates/cgp-macro-lib/src/replace_self/mod.rs +++ b/crates/cgp-macro-lib/src/replace_self/mod.rs @@ -1,9 +1,9 @@ mod replace_self_receiver; mod replace_self_type; -mod replace_self_var; +mod replace_self_value; mod snake_case; pub use replace_self_receiver::*; pub use replace_self_type::*; -pub use replace_self_var::*; +pub use replace_self_value::*; pub use snake_case::*; diff --git a/crates/cgp-macro-lib/src/replace_self/replace_self_var.rs b/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs similarity index 85% rename from crates/cgp-macro-lib/src/replace_self/replace_self_var.rs rename to crates/cgp-macro-lib/src/replace_self/replace_self_value.rs index b94e6b2e..6fb63040 100644 --- a/crates/cgp-macro-lib/src/replace_self/replace_self_var.rs +++ b/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs @@ -2,7 +2,7 @@ use proc_macro2::{Group, TokenStream, TokenTree}; use quote::format_ident; use syn::Ident; -pub fn replace_self_var(stream: TokenStream, replaced_ident: &Ident) -> TokenStream { +pub fn replace_self_value(stream: TokenStream, replaced_ident: &Ident) -> TokenStream { let self_ident = format_ident!("self"); let mut result_stream: Vec = Vec::new(); @@ -19,7 +19,7 @@ pub fn replace_self_var(stream: TokenStream, replaced_ident: &Ident) -> TokenStr } } TokenTree::Group(group) => { - let replaced_stream = replace_self_var(group.stream(), replaced_ident); + let replaced_stream = replace_self_value(group.stream(), replaced_ident); let replaced_group = Group::new(group.delimiter(), replaced_stream); result_stream.push(TokenTree::Group(replaced_group)); From 7758bac8d6f8adfefaaa1ac69411cd7fa60691d3 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 29 May 2026 21:27:16 +0200 Subject: [PATCH 05/46] Implement replace_self_value_in_block using VisitorMut --- .../cgp-macro-lib/src/cgp_impl/transform.rs | 10 ++--- .../src/derive_component/provider_trait.rs | 9 ++-- .../src/replace_self/replace_self_value.rs | 43 +++++++++++++++++-- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/crates/cgp-macro-lib/src/cgp_impl/transform.rs b/crates/cgp-macro-lib/src/cgp_impl/transform.rs index b670e3a9..fab8849c 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/transform.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/transform.rs @@ -5,7 +5,7 @@ use syn::{FnArg, Ident, ImplItem, ItemImpl, Type, parse2}; use crate::parse::SimpleType; use crate::replace_self::{ - replace_self_receiver, replace_self_type, replace_self_value, to_snake_case_ident, + replace_self_receiver, replace_self_type, replace_self_value_in_block, to_snake_case_ident, }; pub fn transform_impl_trait( @@ -14,7 +14,7 @@ pub fn transform_impl_trait( provider_type: &Type, context_type: &Type, ) -> syn::Result { - let context_value = if let Ok(ident) = parse2::(context_type.to_token_stream()) { + let context_ident = if let Ok(ident) = parse2::(context_type.to_token_stream()) { to_snake_case_ident(&ident) } else { Ident::new("__context__", Span::call_site()) @@ -69,11 +69,9 @@ pub fn transform_impl_trait( && let Some(arg) = item_fn.sig.inputs.first_mut() && let FnArg::Receiver(receiver) = arg { - *arg = replace_self_receiver(receiver, &context_value, context_type.to_token_stream()); + *arg = replace_self_receiver(receiver, &context_ident, context_type.to_token_stream()); - let replaced_block = - replace_self_value(item_fn.block.to_token_stream(), &context_value); - item_fn.block = parse2(replaced_block)?; + replace_self_value_in_block(&mut item_fn.block, &context_ident); } } 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 cb58d899..433e8939 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, replace_self_value, to_snake_case_ident, + replace_self_receiver_in_signature, replace_self_value_in_block, to_snake_case_ident, }; pub fn derive_provider_trait( @@ -84,7 +84,7 @@ pub fn derive_provider_trait( // Replace self type and argument into context type argument { - let context_value = to_snake_case_ident(context_type); + let context_ident = to_snake_case_ident(context_type); for item in provider_trait.items.iter_mut() { let mut replaced_item = @@ -93,13 +93,12 @@ pub fn derive_provider_trait( if let TraitItem::Fn(func) = &mut replaced_item { replace_self_receiver_in_signature( &mut func.sig, - &context_value, + &context_ident, context_type.to_token_stream(), ); if let Some(block) = &mut func.default { - let replaced = replace_self_value(block.to_token_stream(), &context_value); - *block = parse2(replaced)?; + replace_self_value_in_block(block, &context_ident); } } diff --git a/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs b/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs index 6fb63040..2f147632 100644 --- a/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs +++ b/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs @@ -1,8 +1,44 @@ use proc_macro2::{Group, TokenStream, TokenTree}; use quote::format_ident; -use syn::Ident; +use syn::visit_mut::{self, VisitMut}; +use syn::{Block, Expr, Ident, ItemFn, Macro, Path}; -pub fn replace_self_value(stream: TokenStream, replaced_ident: &Ident) -> TokenStream { +pub fn replace_self_value_in_block(block: &mut Block, replaced_ident: &Ident) { + ReplaceSelfVisitor { replaced_ident }.visit_block_mut(block); +} + +struct ReplaceSelfVisitor<'a> { + replaced_ident: &'a Ident, +} + +impl VisitMut for ReplaceSelfVisitor<'_> { + fn visit_expr_mut(&mut self, expr: &mut Expr) { + match expr { + // Replace bare `self` expression (also covers `self.field`, `self.method()`, + // `&self`, `*self`, `self[i]`, `..self`, closure captures, etc. via recursion). + Expr::Path(expr_path) + if expr_path.qself.is_none() && expr_path.path.is_ident("self") => + { + expr_path.path = Path::from(self.replaced_ident.clone()); + } + _ => visit_mut::visit_expr_mut(self, expr), + } + } + + fn visit_macro_mut(&mut self, mac: &mut Macro) { + // Macro bodies are opaque to VisitMut, so fall back to token-level replacement. + mac.tokens = replace_self_value_in_token_stream(mac.tokens.clone(), self.replaced_ident); + } + + fn visit_item_fn_mut(&mut self, _: &mut ItemFn) { + // Nested fn items don't capture `self` from the outer scope; stop recursion. + } +} + +pub fn replace_self_value_in_token_stream( + stream: TokenStream, + replaced_ident: &Ident, +) -> TokenStream { let self_ident = format_ident!("self"); let mut result_stream: Vec = Vec::new(); @@ -19,7 +55,8 @@ pub fn replace_self_value(stream: TokenStream, replaced_ident: &Ident) -> TokenS } } TokenTree::Group(group) => { - let replaced_stream = replace_self_value(group.stream(), replaced_ident); + let replaced_stream = + replace_self_value_in_token_stream(group.stream(), replaced_ident); let replaced_group = Group::new(group.delimiter(), replaced_stream); result_stream.push(TokenTree::Group(replaced_group)); From 40a63e74b5b8b88d4e84866ab93a146098560611 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 29 May 2026 22:00:43 +0200 Subject: [PATCH 06/46] Implement visitor-based replace_self_type --- .../cgp-macro-lib/src/cgp_impl/transform.rs | 21 ++-- .../src/replace_self/replace_self_type.rs | 106 +++++++++++++++++- .../src/replace_self/replace_self_value.rs | 2 - 3 files changed, 111 insertions(+), 18 deletions(-) diff --git a/crates/cgp-macro-lib/src/cgp_impl/transform.rs b/crates/cgp-macro-lib/src/cgp_impl/transform.rs index fab8849c..7aaced73 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/transform.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/transform.rs @@ -5,7 +5,8 @@ use syn::{FnArg, Ident, ImplItem, ItemImpl, Type, parse2}; use crate::parse::SimpleType; use crate::replace_self::{ - replace_self_receiver, replace_self_type, replace_self_value_in_block, to_snake_case_ident, + replace_self_receiver, replace_self_type_in_generic_args, replace_self_type_in_item_impl, + replace_self_value_in_block, to_snake_case_ident, }; pub fn transform_impl_trait( @@ -32,20 +33,16 @@ pub fn transform_impl_trait( }) .collect(); - let raw_out_impl = replace_self_type( - item_impl.to_token_stream(), - context_type.to_token_stream(), - &local_assoc_types, - ); + let mut out_impl = item_impl.clone(); + + replace_self_type_in_item_impl(&mut out_impl, context_type, &local_assoc_types); - let mut out_impl: ItemImpl = parse2(raw_out_impl)?; out_impl.self_ty = Box::new(provider_type.clone()); - let mut provider_trait_path: SimpleType = parse2(replace_self_type( - consumer_trait_path.to_token_stream(), - context_type.to_token_stream(), - &local_assoc_types, - ))?; + let mut provider_trait_path = consumer_trait_path.clone(); + if let Some(generics) = &mut provider_trait_path.generics { + replace_self_type_in_generic_args(generics, &context_type, &local_assoc_types); + } match &mut provider_trait_path.generics { Some(generics) => { diff --git a/crates/cgp-macro-lib/src/replace_self/replace_self_type.rs b/crates/cgp-macro-lib/src/replace_self/replace_self_type.rs index bf8a6952..f727974f 100644 --- a/crates/cgp-macro-lib/src/replace_self/replace_self_type.rs +++ b/crates/cgp-macro-lib/src/replace_self/replace_self_type.rs @@ -4,6 +4,8 @@ use itertools::Itertools; use proc_macro2::{Group, Ident, TokenStream, TokenTree}; use quote::{ToTokens, format_ident}; use syn::parse::Parse; +use syn::visit_mut::{self, VisitMut}; +use syn::{AngleBracketedGenericArguments, ItemImpl, Macro, Path, Type}; pub fn iter_parse_and_replace_self_type( vals: I, @@ -21,16 +23,17 @@ where pub fn parse_and_replace_self_type( val: &T, - replaced_ident: &Ident, - local_assoc_types: &Vec, + replaced_type: &Ident, + // Skip the replacement of `Self` if it is an associated type expression, e.g. `Self::Foo`. + skip_assoc_types: &Vec, ) -> syn::Result where T: ToTokens + Parse, { let stream = replace_self_type( val.to_token_stream(), - replaced_ident.to_token_stream(), - local_assoc_types, + replaced_type.to_token_stream(), + skip_assoc_types, ); syn::parse2(stream) } @@ -93,3 +96,98 @@ pub fn replace_self_type( result_stream.into_iter().collect() } + +pub fn replace_self_type_in_item_impl( + item_impl: &mut ItemImpl, + replaced_type: &Type, + skip_assoc_types: &Vec, +) { + ReplaceSelfTypeVisitor { + replaced_type, + skip_assoc_types, + } + .visit_item_impl_mut(item_impl); +} + +// pub fn replace_self_type_in_generics( +// generics: &mut Generics, +// replaced_type: &Type, +// skip_assoc_types: &Vec, +// ) { +// ReplaceSelfTypeVisitor { +// replaced_type, +// skip_assoc_types, +// } +// .visit_generics_mut(generics); +// } + +pub fn replace_self_type_in_generic_args( + generics: &mut AngleBracketedGenericArguments, + replaced_type: &Type, + skip_assoc_types: &Vec, +) { + ReplaceSelfTypeVisitor { + replaced_type, + skip_assoc_types, + } + .visit_angle_bracketed_generic_arguments_mut(generics); +} + +struct ReplaceSelfTypeVisitor<'a> { + replaced_type: &'a Type, + skip_assoc_types: &'a Vec, +} + +impl<'a> ReplaceSelfTypeVisitor<'a> { + fn replace_self_in_path(&self, path: &mut Path) { + let Some(first) = path.segments.first() else { + return; + }; + if first.ident != "Self" { + return; + } + if path.segments.len() >= 2 && self.skip_assoc_types.contains(&path.segments[1].ident) { + return; + } + if let Type::Path(replaced) = self.replaced_type { + if replaced.qself.is_none() { + let rest: Vec<_> = path.segments.iter().skip(1).cloned().collect(); + let mut new_path = replaced.path.clone(); + new_path.segments.extend(rest); + *path = new_path; + } + } + } +} + +impl VisitMut for ReplaceSelfTypeVisitor<'_> { + fn visit_type_mut(&mut self, ty: &mut Type) { + // Handle standalone `Self` type — replaced_type may not be a path (e.g. a reference), + // so we must replace the whole Type node here rather than going through visit_path_mut. + if let Type::Path(type_path) = ty { + if type_path.qself.is_none() + && type_path.path.segments.len() == 1 + && type_path.path.segments[0].ident == "Self" + { + *ty = self.replaced_type.clone(); + return; + } + } + visit_mut::visit_type_mut(self, ty); + } + + fn visit_path_mut(&mut self, path: &mut Path) { + // Handles Self::Foo in type paths (multi-segment) and Self in expression/struct paths. + // Single-segment Self in type position is already handled by visit_type_mut above. + self.replace_self_in_path(path); + visit_mut::visit_path_mut(self, path); + } + + fn visit_macro_mut(&mut self, mac: &mut Macro) { + mac.tokens = replace_self_type( + mac.tokens.clone(), + self.replaced_type.to_token_stream(), + self.skip_assoc_types, + ); + } +} diff --git a/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs b/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs index 2f147632..9898cca1 100644 --- a/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs +++ b/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs @@ -14,8 +14,6 @@ struct ReplaceSelfVisitor<'a> { impl VisitMut for ReplaceSelfVisitor<'_> { fn visit_expr_mut(&mut self, expr: &mut Expr) { match expr { - // Replace bare `self` expression (also covers `self.field`, `self.method()`, - // `&self`, `*self`, `self[i]`, `..self`, closure captures, etc. via recursion). Expr::Path(expr_path) if expr_path.qself.is_none() && expr_path.path.is_ident("self") => { From d7e7646ca6f6f2f6955fca4d6964550aad174b84 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 29 May 2026 22:37:18 +0200 Subject: [PATCH 07/46] Use ReplaceSelfTypeVisitor in all other places --- .../cgp-macro-lib/src/cgp_impl/transform.rs | 13 +- .../src/derive_component/provider_trait.rs | 43 ++-- .../cgp-macro-lib/src/derive_getter/parse.rs | 32 ++- .../src/replace_self/replace_self_type.rs | 189 ++++++------------ 4 files changed, 110 insertions(+), 167 deletions(-) diff --git a/crates/cgp-macro-lib/src/cgp_impl/transform.rs b/crates/cgp-macro-lib/src/cgp_impl/transform.rs index 7aaced73..1a874a4e 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/transform.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/transform.rs @@ -1,12 +1,12 @@ use proc_macro2::Span; use quote::{ToTokens, quote}; use syn::token::For; +use syn::visit_mut::VisitMut; use syn::{FnArg, Ident, ImplItem, ItemImpl, Type, parse2}; use crate::parse::SimpleType; use crate::replace_self::{ - replace_self_receiver, replace_self_type_in_generic_args, replace_self_type_in_item_impl, - replace_self_value_in_block, to_snake_case_ident, + ReplaceSelfTypeVisitor, replace_self_receiver, replace_self_value_in_block, to_snake_case_ident, }; pub fn transform_impl_trait( @@ -33,15 +33,20 @@ pub fn transform_impl_trait( }) .collect(); + let mut replace_self_type_visitor = ReplaceSelfTypeVisitor { + replaced_type: &context_type, + skip_assoc_types: &local_assoc_types, + }; + let mut out_impl = item_impl.clone(); - replace_self_type_in_item_impl(&mut out_impl, context_type, &local_assoc_types); + replace_self_type_visitor.visit_item_impl_mut(&mut out_impl); out_impl.self_ty = Box::new(provider_type.clone()); let mut provider_trait_path = consumer_trait_path.clone(); if let Some(generics) = &mut provider_trait_path.generics { - replace_self_type_in_generic_args(generics, &context_type, &local_assoc_types); + replace_self_type_visitor.visit_angle_bracketed_generic_arguments_mut(generics); } match &mut provider_trait_path.generics { 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 433e8939..ab4017a2 100644 --- a/crates/cgp-macro-lib/src/derive_component/provider_trait.rs +++ b/crates/cgp-macro-lib/src/derive_component/provider_trait.rs @@ -3,12 +3,13 @@ use alloc::vec::Vec; use quote::{ToTokens, quote}; use syn::punctuated::Punctuated; use syn::token::Comma; -use syn::{Ident, ItemTrait, TraitItem, TypeParamBound, parse2}; +use syn::visit_mut::VisitMut; +use syn::{Ident, ItemTrait, TraitItem, TypeParamBound, parse_quote, 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, replace_self_value_in_block, to_snake_case_ident, + ReplaceSelfTypeVisitor, replace_self_receiver_in_signature, replace_self_value_in_block, + to_snake_case_ident, }; pub fn derive_provider_trait( @@ -42,13 +43,18 @@ pub fn derive_provider_trait( }) .collect(); + let mut replace_self_type_visitor = ReplaceSelfTypeVisitor { + replaced_type: &parse_quote!(#context_type), + skip_assoc_types: &local_assoc_types, + }; + // Turn the supertrait constraints into `Context` constraints in the `where` clause { - let context_constraints = iter_parse_and_replace_self_type( - provider_trait.supertraits.clone(), - context_type, - &local_assoc_types, - )?; + let mut context_constraints = provider_trait.supertraits.clone(); + + for constraint in &mut context_constraints { + replace_self_type_visitor.visit_type_param_bound_mut(constraint); + } let is_provider_params = parse_is_provider_params(&consumer_trait.generics)?; @@ -61,17 +67,7 @@ pub fn derive_provider_trait( if !context_constraints.is_empty() { match &mut provider_trait.generics.where_clause { Some(where_clause) => { - let mut predicates = iter_parse_and_replace_self_type( - where_clause.predicates.clone(), - context_type, - &local_assoc_types, - )?; - - predicates.push(parse2(quote! { - #context_type : #context_constraints - })?); - - where_clause.predicates = predicates; + replace_self_type_visitor.visit_where_clause_mut(where_clause); } _ => { provider_trait.generics.where_clause = Some(parse2(quote! { @@ -86,11 +82,10 @@ pub fn derive_provider_trait( { let context_ident = 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)?; + for trait_item in provider_trait.items.iter_mut() { + replace_self_type_visitor.visit_trait_item_mut(trait_item); - if let TraitItem::Fn(func) = &mut replaced_item { + if let TraitItem::Fn(func) = trait_item { replace_self_receiver_in_signature( &mut func.sig, &context_ident, @@ -101,8 +96,6 @@ pub fn derive_provider_trait( replace_self_value_in_block(block, &context_ident); } } - - *item = replaced_item; } } diff --git a/crates/cgp-macro-lib/src/derive_getter/parse.rs b/crates/cgp-macro-lib/src/derive_getter/parse.rs index bfac7468..e282ee4f 100644 --- a/crates/cgp-macro-lib/src/derive_getter/parse.rs +++ b/crates/cgp-macro-lib/src/derive_getter/parse.rs @@ -4,6 +4,7 @@ use quote::{ToTokens, quote}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::token::{Comma, Mut}; +use syn::visit_mut::VisitMut; use syn::{ Error, FnArg, GenericArgument, Ident, ItemTrait, PathArguments, PathSegment, ReturnType, Signature, TraitItem, TraitItemFn, TraitItemType, Type, TypePath, parse_quote, parse2, @@ -11,7 +12,7 @@ use syn::{ use crate::derive_getter::getter_field::GetterField; use crate::derive_getter::{FieldMode, ReceiverMode}; -use crate::replace_self::replace_self_type; +use crate::replace_self::ReplaceSelfTypeVisitor; pub fn parse_getter_fields( context_type: &Ident, @@ -228,11 +229,14 @@ fn parse_receiver(context_ident: &Ident, arg: &FnArg) -> syn::Result<(ReceiverMo } FnArg::Typed(arg) => match arg.ty.as_ref() { Type::Reference(ty) => { - let receiver = parse2(replace_self_type( - ty.elem.to_token_stream(), - context_ident.to_token_stream(), - &Vec::new(), - ))?; + let mut receiver = ty.elem.clone(); + + ReplaceSelfTypeVisitor { + replaced_type: &parse_quote!(#context_ident), + skip_assoc_types: &Vec::new(), + } + .visit_type_mut(&mut receiver); + Ok((ReceiverMode::Type(receiver), ty.mutability)) } _ => Err(Error::new( @@ -249,11 +253,17 @@ fn parse_return_type( field_assoc_type: &Option, ) -> syn::Result { match return_type { - ReturnType::Type(_, ty) => parse2(replace_self_type( - ty.to_token_stream(), - context_type.to_token_stream(), - &field_assoc_type.iter().cloned().collect::>(), - )), + ReturnType::Type(_, ty) => { + let mut replaced_type = ty.as_ref().clone(); + + ReplaceSelfTypeVisitor { + replaced_type: &parse_quote!(#context_type), + skip_assoc_types: &Vec::from_iter(field_assoc_type.clone()), + } + .visit_type_mut(&mut replaced_type); + + Ok(replaced_type) + } _ => Err(Error::new( return_type.span(), "return type must be specified", diff --git a/crates/cgp-macro-lib/src/replace_self/replace_self_type.rs b/crates/cgp-macro-lib/src/replace_self/replace_self_type.rs index f727974f..9e96ebce 100644 --- a/crates/cgp-macro-lib/src/replace_self/replace_self_type.rs +++ b/crates/cgp-macro-lib/src/replace_self/replace_self_type.rs @@ -3,42 +3,69 @@ use alloc::vec::Vec; use itertools::Itertools; use proc_macro2::{Group, Ident, TokenStream, TokenTree}; use quote::{ToTokens, format_ident}; -use syn::parse::Parse; use syn::visit_mut::{self, VisitMut}; -use syn::{AngleBracketedGenericArguments, ItemImpl, Macro, Path, Type}; +use syn::{Macro, Path, Type}; -pub fn iter_parse_and_replace_self_type( - vals: I, - replaced_ident: &Ident, - local_assoc_types: &Vec, -) -> syn::Result -where - I: IntoIterator + FromIterator, - T: ToTokens + Parse, -{ - vals.into_iter() - .map(|val| parse_and_replace_self_type(&val, replaced_ident, local_assoc_types)) - .collect() +pub struct ReplaceSelfTypeVisitor<'a> { + pub replaced_type: &'a Type, + pub skip_assoc_types: &'a Vec, +} + +impl<'a> ReplaceSelfTypeVisitor<'a> { + fn replace_self_in_path(&self, path: &mut Path) { + let Some(first) = path.segments.first() else { + return; + }; + if first.ident != "Self" { + return; + } + if path.segments.len() >= 2 && self.skip_assoc_types.contains(&path.segments[1].ident) { + return; + } + if let Type::Path(replaced) = self.replaced_type { + if replaced.qself.is_none() { + let rest: Vec<_> = path.segments.iter().skip(1).cloned().collect(); + let mut new_path = replaced.path.clone(); + new_path.segments.extend(rest); + *path = new_path; + } + } + } } -pub fn parse_and_replace_self_type( - val: &T, - replaced_type: &Ident, - // Skip the replacement of `Self` if it is an associated type expression, e.g. `Self::Foo`. - skip_assoc_types: &Vec, -) -> syn::Result -where - T: ToTokens + Parse, -{ - let stream = replace_self_type( - val.to_token_stream(), - replaced_type.to_token_stream(), - skip_assoc_types, - ); - syn::parse2(stream) +impl VisitMut for ReplaceSelfTypeVisitor<'_> { + fn visit_type_mut(&mut self, ty: &mut Type) { + // Handle standalone `Self` type — replaced_type may not be a path (e.g. a reference), + // so we must replace the whole Type node here rather than going through visit_path_mut. + if let Type::Path(type_path) = ty { + if type_path.qself.is_none() + && type_path.path.segments.len() == 1 + && type_path.path.segments[0].ident == "Self" + { + *ty = self.replaced_type.clone(); + return; + } + } + visit_mut::visit_type_mut(self, ty); + } + + fn visit_path_mut(&mut self, path: &mut Path) { + // Handles Self::Foo in type paths (multi-segment) and Self in expression/struct paths. + // Single-segment Self in type position is already handled by visit_type_mut above. + self.replace_self_in_path(path); + visit_mut::visit_path_mut(self, path); + } + + fn visit_macro_mut(&mut self, mac: &mut Macro) { + mac.tokens = replace_self_type_in_token_stream( + core::mem::take(&mut mac.tokens), + self.replaced_type.to_token_stream(), + self.skip_assoc_types, + ); + } } -pub fn replace_self_type( +pub fn replace_self_type_in_token_stream( stream: TokenStream, replaced_ident: TokenStream, local_assoc_types: &Vec, @@ -81,8 +108,11 @@ pub fn replace_self_type( } } TokenTree::Group(group) => { - let replaced_stream = - replace_self_type(group.stream(), replaced_ident.clone(), local_assoc_types); + let replaced_stream = replace_self_type_in_token_stream( + group.stream(), + replaced_ident.clone(), + local_assoc_types, + ); let replaced_group = Group::new(group.delimiter(), replaced_stream); result_stream.push(TokenTree::Group(replaced_group)); @@ -96,98 +126,3 @@ pub fn replace_self_type( result_stream.into_iter().collect() } - -pub fn replace_self_type_in_item_impl( - item_impl: &mut ItemImpl, - replaced_type: &Type, - skip_assoc_types: &Vec, -) { - ReplaceSelfTypeVisitor { - replaced_type, - skip_assoc_types, - } - .visit_item_impl_mut(item_impl); -} - -// pub fn replace_self_type_in_generics( -// generics: &mut Generics, -// replaced_type: &Type, -// skip_assoc_types: &Vec, -// ) { -// ReplaceSelfTypeVisitor { -// replaced_type, -// skip_assoc_types, -// } -// .visit_generics_mut(generics); -// } - -pub fn replace_self_type_in_generic_args( - generics: &mut AngleBracketedGenericArguments, - replaced_type: &Type, - skip_assoc_types: &Vec, -) { - ReplaceSelfTypeVisitor { - replaced_type, - skip_assoc_types, - } - .visit_angle_bracketed_generic_arguments_mut(generics); -} - -struct ReplaceSelfTypeVisitor<'a> { - replaced_type: &'a Type, - skip_assoc_types: &'a Vec, -} - -impl<'a> ReplaceSelfTypeVisitor<'a> { - fn replace_self_in_path(&self, path: &mut Path) { - let Some(first) = path.segments.first() else { - return; - }; - if first.ident != "Self" { - return; - } - if path.segments.len() >= 2 && self.skip_assoc_types.contains(&path.segments[1].ident) { - return; - } - if let Type::Path(replaced) = self.replaced_type { - if replaced.qself.is_none() { - let rest: Vec<_> = path.segments.iter().skip(1).cloned().collect(); - let mut new_path = replaced.path.clone(); - new_path.segments.extend(rest); - *path = new_path; - } - } - } -} - -impl VisitMut for ReplaceSelfTypeVisitor<'_> { - fn visit_type_mut(&mut self, ty: &mut Type) { - // Handle standalone `Self` type — replaced_type may not be a path (e.g. a reference), - // so we must replace the whole Type node here rather than going through visit_path_mut. - if let Type::Path(type_path) = ty { - if type_path.qself.is_none() - && type_path.path.segments.len() == 1 - && type_path.path.segments[0].ident == "Self" - { - *ty = self.replaced_type.clone(); - return; - } - } - visit_mut::visit_type_mut(self, ty); - } - - fn visit_path_mut(&mut self, path: &mut Path) { - // Handles Self::Foo in type paths (multi-segment) and Self in expression/struct paths. - // Single-segment Self in type position is already handled by visit_type_mut above. - self.replace_self_in_path(path); - visit_mut::visit_path_mut(self, path); - } - - fn visit_macro_mut(&mut self, mac: &mut Macro) { - mac.tokens = replace_self_type( - mac.tokens.clone(), - self.replaced_type.to_token_stream(), - self.skip_assoc_types, - ); - } -} From bd55d6e6d591fda7ac028c3c671474e46ce76b70 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 29 May 2026 23:02:35 +0200 Subject: [PATCH 08/46] Use visitors in more places --- .../cgp-macro-lib/src/cgp_impl/transform.rs | 27 ++++++------ .../src/derive_component/provider_trait.rs | 44 +++++++++---------- .../src/replace_self/replace_self_receiver.rs | 42 ++++++++++-------- .../src/replace_self/replace_self_value.rs | 12 ++--- 4 files changed, 61 insertions(+), 64 deletions(-) diff --git a/crates/cgp-macro-lib/src/cgp_impl/transform.rs b/crates/cgp-macro-lib/src/cgp_impl/transform.rs index 1a874a4e..e336751f 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/transform.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/transform.rs @@ -2,11 +2,12 @@ use proc_macro2::Span; use quote::{ToTokens, quote}; use syn::token::For; use syn::visit_mut::VisitMut; -use syn::{FnArg, Ident, ImplItem, ItemImpl, Type, parse2}; +use syn::{Ident, ImplItem, ItemImpl, Type, parse2}; use crate::parse::SimpleType; use crate::replace_self::{ - ReplaceSelfTypeVisitor, replace_self_receiver, replace_self_value_in_block, to_snake_case_ident, + ReplaceSelfReceiverVisitor, ReplaceSelfTypeVisitor, ReplaceSelfValueVisitor, + to_snake_case_ident, }; pub fn transform_impl_trait( @@ -42,6 +43,17 @@ pub fn transform_impl_trait( replace_self_type_visitor.visit_item_impl_mut(&mut out_impl); + ReplaceSelfReceiverVisitor { + replaced_ident: &context_ident, + replaced_type: &context_type, + } + .visit_item_impl_mut(&mut out_impl); + + ReplaceSelfValueVisitor { + replaced_ident: &context_ident, + } + .visit_item_impl_mut(&mut out_impl); + out_impl.self_ty = Box::new(provider_type.clone()); let mut provider_trait_path = consumer_trait_path.clone(); @@ -66,16 +78,5 @@ pub fn transform_impl_trait( For(Span::call_site()), )); - for item in out_impl.items.iter_mut() { - if let ImplItem::Fn(item_fn) = item - && let Some(arg) = item_fn.sig.inputs.first_mut() - && let FnArg::Receiver(receiver) = arg - { - *arg = replace_self_receiver(receiver, &context_ident, context_type.to_token_stream()); - - replace_self_value_in_block(&mut item_fn.block, &context_ident); - } - } - Ok(out_impl) } 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 ab4017a2..eb8b680c 100644 --- a/crates/cgp-macro-lib/src/derive_component/provider_trait.rs +++ b/crates/cgp-macro-lib/src/derive_component/provider_trait.rs @@ -1,14 +1,14 @@ use alloc::vec::Vec; -use quote::{ToTokens, quote}; +use quote::quote; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::visit_mut::VisitMut; -use syn::{Ident, ItemTrait, TraitItem, TypeParamBound, parse_quote, parse2}; +use syn::{Ident, ItemTrait, TraitItem, Type, TypeParamBound, parse_quote, parse2}; use crate::parse::parse_is_provider_params; use crate::replace_self::{ - ReplaceSelfTypeVisitor, replace_self_receiver_in_signature, replace_self_value_in_block, + ReplaceSelfReceiverVisitor, ReplaceSelfTypeVisitor, ReplaceSelfValueVisitor, to_snake_case_ident, }; @@ -17,18 +17,20 @@ pub fn derive_provider_trait( component_params: &Punctuated, consumer_trait: &ItemTrait, provider_name: &Ident, - context_type: &Ident, + context_type_ident: &Ident, ) -> syn::Result { let mut provider_trait = consumer_trait.clone(); provider_trait.ident = provider_name.clone(); + let context_type: Type = parse_quote!(#context_type_ident); + // Add generic parameter `Context` to the front of generics { provider_trait .generics .params - .insert(0, parse2(quote!(#context_type))?); + .insert(0, parse2(quote!(#context_type_ident))?); } let local_assoc_types: Vec = provider_trait @@ -44,7 +46,7 @@ pub fn derive_provider_trait( .collect(); let mut replace_self_type_visitor = ReplaceSelfTypeVisitor { - replaced_type: &parse_quote!(#context_type), + replaced_type: &context_type, skip_assoc_types: &local_assoc_types, }; @@ -59,7 +61,7 @@ pub fn derive_provider_trait( let is_provider_params = parse_is_provider_params(&consumer_trait.generics)?; let provider_supertrait: TypeParamBound = parse2(quote!( - IsProviderFor< #component_name < #component_params >, #context_type, ( #is_provider_params ) > + IsProviderFor< #component_name < #component_params >, #context_type_ident, ( #is_provider_params ) > ))?; provider_trait.supertraits = Punctuated::from_iter([provider_supertrait]); @@ -71,33 +73,27 @@ pub fn derive_provider_trait( } _ => { provider_trait.generics.where_clause = Some(parse2(quote! { - where #context_type : #context_constraints + where #context_type_ident : #context_constraints })?); } } } } - // Replace self type and argument into context type argument - { - let context_ident = to_snake_case_ident(context_type); + let context_value_ident = to_snake_case_ident(context_type_ident); - for trait_item in provider_trait.items.iter_mut() { - replace_self_type_visitor.visit_trait_item_mut(trait_item); + replace_self_type_visitor.visit_item_trait_mut(&mut provider_trait); - if let TraitItem::Fn(func) = trait_item { - replace_self_receiver_in_signature( - &mut func.sig, - &context_ident, - context_type.to_token_stream(), - ); + ReplaceSelfReceiverVisitor { + replaced_ident: &context_value_ident, + replaced_type: &context_type, + } + .visit_item_trait_mut(&mut provider_trait); - if let Some(block) = &mut func.default { - replace_self_value_in_block(block, &context_ident); - } - } - } + ReplaceSelfValueVisitor { + replaced_ident: &context_value_ident, } + .visit_item_trait_mut(&mut provider_trait); Ok(provider_trait) } diff --git a/crates/cgp-macro-lib/src/replace_self/replace_self_receiver.rs b/crates/cgp-macro-lib/src/replace_self/replace_self_receiver.rs index 425843c5..7fdf0bce 100644 --- a/crates/cgp-macro-lib/src/replace_self/replace_self_receiver.rs +++ b/crates/cgp-macro-lib/src/replace_self/replace_self_receiver.rs @@ -1,41 +1,45 @@ -use proc_macro2::{Ident, TokenStream}; -use syn::{FnArg, Receiver, Signature, parse_quote}; +use proc_macro2::Ident; +use syn::visit_mut::VisitMut; +use syn::{FnArg, Receiver, Signature, Type, parse_quote}; -pub fn replace_self_receiver_in_signature( - sig: &mut Signature, - replaced_var: &Ident, - replaced_type: TokenStream, -) { - if let Some(arg) = sig.inputs.first_mut() - && let FnArg::Receiver(receiver) = arg - { - *arg = replace_self_receiver(receiver, replaced_var, replaced_type); +pub struct ReplaceSelfReceiverVisitor<'a> { + pub replaced_ident: &'a Ident, + pub replaced_type: &'a Type, +} + +impl<'a> VisitMut for ReplaceSelfReceiverVisitor<'a> { + fn visit_signature_mut(&mut self, sig: &mut Signature) { + if let Some(arg) = sig.inputs.first_mut() + && let FnArg::Receiver(receiver) = arg + { + *arg = replace_self_receiver(receiver, self.replaced_ident, self.replaced_type); + } } } pub fn replace_self_receiver( receiver: &mut Receiver, - replaced_var: &Ident, - replaced_type: TokenStream, + replaced_ident: &Ident, + replaced_type: &Type, ) -> FnArg { match (&receiver.reference, &receiver.mutability) { (None, None) => { - parse_quote!(#replaced_var : #replaced_type) + parse_quote!(#replaced_ident : #replaced_type) } (Some((_and, None)), None) => { - parse_quote!(#replaced_var : & #replaced_type) + parse_quote!(#replaced_ident : & #replaced_type) } (Some((_and, Some(life))), None) => { - parse_quote!(#replaced_var : & #life #replaced_type) + parse_quote!(#replaced_ident : & #life #replaced_type) } (Some((_and, None)), Some(_mut)) => { - parse_quote!(#replaced_var : &mut #replaced_type) + parse_quote!(#replaced_ident : &mut #replaced_type) } (Some((_and, Some(life))), Some(_mut)) => { - parse_quote!(#replaced_var : & #life mut #replaced_type) + parse_quote!(#replaced_ident : & #life mut #replaced_type) } (None, Some(_mut)) => { - parse_quote!(#replaced_var : mut #replaced_type) + parse_quote!(#replaced_ident : mut #replaced_type) } } } diff --git a/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs b/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs index 9898cca1..9e144a5a 100644 --- a/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs +++ b/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs @@ -1,17 +1,13 @@ use proc_macro2::{Group, TokenStream, TokenTree}; use quote::format_ident; use syn::visit_mut::{self, VisitMut}; -use syn::{Block, Expr, Ident, ItemFn, Macro, Path}; +use syn::{Expr, Ident, ItemFn, Macro, Path}; -pub fn replace_self_value_in_block(block: &mut Block, replaced_ident: &Ident) { - ReplaceSelfVisitor { replaced_ident }.visit_block_mut(block); +pub struct ReplaceSelfValueVisitor<'a> { + pub replaced_ident: &'a Ident, } -struct ReplaceSelfVisitor<'a> { - replaced_ident: &'a Ident, -} - -impl VisitMut for ReplaceSelfVisitor<'_> { +impl VisitMut for ReplaceSelfValueVisitor<'_> { fn visit_expr_mut(&mut self, expr: &mut Expr) { match expr { Expr::Path(expr_path) From 968dfd038b18f171ed71a47a05294ceb49a4006d Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 29 May 2026 23:08:44 +0200 Subject: [PATCH 09/46] Simplify self replacements --- .../cgp-macro-lib/src/cgp_impl/transform.rs | 38 ++++++------- .../src/derive_component/provider_trait.rs | 56 ++++++++----------- 2 files changed, 40 insertions(+), 54 deletions(-) diff --git a/crates/cgp-macro-lib/src/cgp_impl/transform.rs b/crates/cgp-macro-lib/src/cgp_impl/transform.rs index e336751f..f7516896 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/transform.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/transform.rs @@ -34,32 +34,11 @@ pub fn transform_impl_trait( }) .collect(); - let mut replace_self_type_visitor = ReplaceSelfTypeVisitor { - replaced_type: &context_type, - skip_assoc_types: &local_assoc_types, - }; - let mut out_impl = item_impl.clone(); - replace_self_type_visitor.visit_item_impl_mut(&mut out_impl); - - ReplaceSelfReceiverVisitor { - replaced_ident: &context_ident, - replaced_type: &context_type, - } - .visit_item_impl_mut(&mut out_impl); - - ReplaceSelfValueVisitor { - replaced_ident: &context_ident, - } - .visit_item_impl_mut(&mut out_impl); - out_impl.self_ty = Box::new(provider_type.clone()); let mut provider_trait_path = consumer_trait_path.clone(); - if let Some(generics) = &mut provider_trait_path.generics { - replace_self_type_visitor.visit_angle_bracketed_generic_arguments_mut(generics); - } match &mut provider_trait_path.generics { Some(generics) => { @@ -78,5 +57,22 @@ pub fn transform_impl_trait( For(Span::call_site()), )); + ReplaceSelfTypeVisitor { + replaced_type: &context_type, + skip_assoc_types: &local_assoc_types, + } + .visit_item_impl_mut(&mut out_impl); + + ReplaceSelfReceiverVisitor { + replaced_ident: &context_ident, + replaced_type: &context_type, + } + .visit_item_impl_mut(&mut out_impl); + + ReplaceSelfValueVisitor { + replaced_ident: &context_ident, + } + .visit_item_impl_mut(&mut out_impl); + Ok(out_impl) } 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 eb8b680c..0f156965 100644 --- a/crates/cgp-macro-lib/src/derive_component/provider_trait.rs +++ b/crates/cgp-macro-lib/src/derive_component/provider_trait.rs @@ -45,44 +45,34 @@ pub fn derive_provider_trait( }) .collect(); - let mut replace_self_type_visitor = ReplaceSelfTypeVisitor { - replaced_type: &context_type, - skip_assoc_types: &local_assoc_types, - }; - // Turn the supertrait constraints into `Context` constraints in the `where` clause - { - let mut context_constraints = provider_trait.supertraits.clone(); - - for constraint in &mut context_constraints { - replace_self_type_visitor.visit_type_param_bound_mut(constraint); - } - - let is_provider_params = parse_is_provider_params(&consumer_trait.generics)?; - - let provider_supertrait: TypeParamBound = parse2(quote!( - IsProviderFor< #component_name < #component_params >, #context_type_ident, ( #is_provider_params ) > - ))?; - - provider_trait.supertraits = Punctuated::from_iter([provider_supertrait]); - - if !context_constraints.is_empty() { - match &mut provider_trait.generics.where_clause { - Some(where_clause) => { - replace_self_type_visitor.visit_where_clause_mut(where_clause); - } - _ => { - provider_trait.generics.where_clause = Some(parse2(quote! { - where #context_type_ident : #context_constraints - })?); - } - } - } + if !provider_trait.supertraits.is_empty() { + let supertraits = &provider_trait.supertraits; + + provider_trait + .generics + .make_where_clause() + .predicates + .push(parse_quote! { + #context_type_ident : #supertraits + }); } + let is_provider_params = parse_is_provider_params(&consumer_trait.generics)?; + + let provider_supertrait: TypeParamBound = parse2(quote!( + IsProviderFor< #component_name < #component_params >, #context_type_ident, ( #is_provider_params ) > + ))?; + + provider_trait.supertraits = Punctuated::from_iter([provider_supertrait]); + let context_value_ident = to_snake_case_ident(context_type_ident); - replace_self_type_visitor.visit_item_trait_mut(&mut provider_trait); + ReplaceSelfTypeVisitor { + replaced_type: &context_type, + skip_assoc_types: &local_assoc_types, + } + .visit_item_trait_mut(&mut provider_trait); ReplaceSelfReceiverVisitor { replaced_ident: &context_value_ident, From c44afd2131b9a5bcbb3ea8144d4d1dce50e6c202 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 29 May 2026 23:11:47 +0200 Subject: [PATCH 10/46] Move replace self constructs --- crates/cgp-macro-core/src/functions/mod.rs | 2 ++ .../src/functions}/snake_case.rs | 2 -- crates/cgp-macro-core/src/lib.rs | 1 + crates/cgp-macro-core/src/visitors/mod.rs | 3 +++ .../src/visitors}/replace_self/mod.rs | 2 -- .../src/visitors}/replace_self/replace_self_receiver.rs | 0 .../src/visitors}/replace_self/replace_self_type.rs | 2 -- .../src/visitors}/replace_self/replace_self_value.rs | 0 crates/cgp-macro-lib/src/cgp_impl/transform.rs | 8 ++++---- .../cgp-macro-lib/src/derive_component/provider_trait.rs | 8 ++++---- crates/cgp-macro-lib/src/derive_getter/parse.rs | 2 +- crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs | 2 +- crates/cgp-macro-lib/src/lib.rs | 1 - 13 files changed, 16 insertions(+), 17 deletions(-) rename crates/{cgp-macro-lib/src/replace_self => cgp-macro-core/src/functions}/snake_case.rs (94%) create mode 100644 crates/cgp-macro-core/src/visitors/mod.rs rename crates/{cgp-macro-lib/src => cgp-macro-core/src/visitors}/replace_self/mod.rs (81%) rename crates/{cgp-macro-lib/src => cgp-macro-core/src/visitors}/replace_self/replace_self_receiver.rs (100%) rename crates/{cgp-macro-lib/src => cgp-macro-core/src/visitors}/replace_self/replace_self_type.rs (99%) rename crates/{cgp-macro-lib/src => cgp-macro-core/src/visitors}/replace_self/replace_self_value.rs (100%) diff --git a/crates/cgp-macro-core/src/functions/mod.rs b/crates/cgp-macro-core/src/functions/mod.rs index f5b39fc2..51e0278e 100644 --- a/crates/cgp-macro-core/src/functions/mod.rs +++ b/crates/cgp-macro-core/src/functions/mod.rs @@ -1,3 +1,5 @@ mod merge_generics; +mod snake_case; pub use merge_generics::*; +pub use snake_case::*; diff --git a/crates/cgp-macro-lib/src/replace_self/snake_case.rs b/crates/cgp-macro-core/src/functions/snake_case.rs similarity index 94% rename from crates/cgp-macro-lib/src/replace_self/snake_case.rs rename to crates/cgp-macro-core/src/functions/snake_case.rs index 9a0e62ef..19b2b3d7 100644 --- a/crates/cgp-macro-lib/src/replace_self/snake_case.rs +++ b/crates/cgp-macro-core/src/functions/snake_case.rs @@ -1,5 +1,3 @@ -use alloc::string::{String, ToString}; - use proc_macro2::Span; use syn::Ident; diff --git a/crates/cgp-macro-core/src/lib.rs b/crates/cgp-macro-core/src/lib.rs index a6dbd9e7..aa5aeac3 100644 --- a/crates/cgp-macro-core/src/lib.rs +++ b/crates/cgp-macro-core/src/lib.rs @@ -5,3 +5,4 @@ pub mod functions; pub mod macros; pub mod traits; pub mod types; +pub mod visitors; diff --git a/crates/cgp-macro-core/src/visitors/mod.rs b/crates/cgp-macro-core/src/visitors/mod.rs new file mode 100644 index 00000000..8b8ab8da --- /dev/null +++ b/crates/cgp-macro-core/src/visitors/mod.rs @@ -0,0 +1,3 @@ +mod replace_self; + +pub use replace_self::*; diff --git a/crates/cgp-macro-lib/src/replace_self/mod.rs b/crates/cgp-macro-core/src/visitors/replace_self/mod.rs similarity index 81% rename from crates/cgp-macro-lib/src/replace_self/mod.rs rename to crates/cgp-macro-core/src/visitors/replace_self/mod.rs index ae067e07..0cf5c5a6 100644 --- a/crates/cgp-macro-lib/src/replace_self/mod.rs +++ b/crates/cgp-macro-core/src/visitors/replace_self/mod.rs @@ -1,9 +1,7 @@ mod replace_self_receiver; mod replace_self_type; mod replace_self_value; -mod snake_case; pub use replace_self_receiver::*; pub use replace_self_type::*; pub use replace_self_value::*; -pub use snake_case::*; diff --git a/crates/cgp-macro-lib/src/replace_self/replace_self_receiver.rs b/crates/cgp-macro-core/src/visitors/replace_self/replace_self_receiver.rs similarity index 100% rename from crates/cgp-macro-lib/src/replace_self/replace_self_receiver.rs rename to crates/cgp-macro-core/src/visitors/replace_self/replace_self_receiver.rs diff --git a/crates/cgp-macro-lib/src/replace_self/replace_self_type.rs b/crates/cgp-macro-core/src/visitors/replace_self/replace_self_type.rs similarity index 99% rename from crates/cgp-macro-lib/src/replace_self/replace_self_type.rs rename to crates/cgp-macro-core/src/visitors/replace_self/replace_self_type.rs index 9e96ebce..5251394a 100644 --- a/crates/cgp-macro-lib/src/replace_self/replace_self_type.rs +++ b/crates/cgp-macro-core/src/visitors/replace_self/replace_self_type.rs @@ -1,5 +1,3 @@ -use alloc::vec::Vec; - use itertools::Itertools; use proc_macro2::{Group, Ident, TokenStream, TokenTree}; use quote::{ToTokens, format_ident}; diff --git a/crates/cgp-macro-lib/src/replace_self/replace_self_value.rs b/crates/cgp-macro-core/src/visitors/replace_self/replace_self_value.rs similarity index 100% rename from crates/cgp-macro-lib/src/replace_self/replace_self_value.rs rename to crates/cgp-macro-core/src/visitors/replace_self/replace_self_value.rs diff --git a/crates/cgp-macro-lib/src/cgp_impl/transform.rs b/crates/cgp-macro-lib/src/cgp_impl/transform.rs index f7516896..08a1d16c 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/transform.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/transform.rs @@ -1,3 +1,7 @@ +use cgp_macro_core::functions::to_snake_case_ident; +use cgp_macro_core::visitors::{ + ReplaceSelfReceiverVisitor, ReplaceSelfTypeVisitor, ReplaceSelfValueVisitor, +}; use proc_macro2::Span; use quote::{ToTokens, quote}; use syn::token::For; @@ -5,10 +9,6 @@ use syn::visit_mut::VisitMut; use syn::{Ident, ImplItem, ItemImpl, Type, parse2}; use crate::parse::SimpleType; -use crate::replace_self::{ - ReplaceSelfReceiverVisitor, ReplaceSelfTypeVisitor, ReplaceSelfValueVisitor, - to_snake_case_ident, -}; pub fn transform_impl_trait( item_impl: &ItemImpl, 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 0f156965..93084d0c 100644 --- a/crates/cgp-macro-lib/src/derive_component/provider_trait.rs +++ b/crates/cgp-macro-lib/src/derive_component/provider_trait.rs @@ -1,5 +1,9 @@ use alloc::vec::Vec; +use cgp_macro_core::functions::to_snake_case_ident; +use cgp_macro_core::visitors::{ + ReplaceSelfReceiverVisitor, ReplaceSelfTypeVisitor, ReplaceSelfValueVisitor, +}; use quote::quote; use syn::punctuated::Punctuated; use syn::token::Comma; @@ -7,10 +11,6 @@ use syn::visit_mut::VisitMut; use syn::{Ident, ItemTrait, TraitItem, Type, TypeParamBound, parse_quote, parse2}; use crate::parse::parse_is_provider_params; -use crate::replace_self::{ - ReplaceSelfReceiverVisitor, ReplaceSelfTypeVisitor, ReplaceSelfValueVisitor, - to_snake_case_ident, -}; 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 e282ee4f..5b04f6db 100644 --- a/crates/cgp-macro-lib/src/derive_getter/parse.rs +++ b/crates/cgp-macro-lib/src/derive_getter/parse.rs @@ -1,5 +1,6 @@ use alloc::vec::Vec; +use cgp_macro_core::visitors::ReplaceSelfTypeVisitor; use quote::{ToTokens, quote}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; @@ -12,7 +13,6 @@ use syn::{ use crate::derive_getter::getter_field::GetterField; use crate::derive_getter::{FieldMode, ReceiverMode}; -use crate::replace_self::ReplaceSelfTypeVisitor; pub fn parse_getter_fields( context_type: &Ident, diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs index 11d1bed7..7c276990 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; +use cgp_macro_core::functions::to_snake_case_str; use cgp_macro_core::types::generics::ImplGenerics; use cgp_macro_core::types::provider_struct::ProviderStruct; use proc_macro2::{Span, TokenStream}; @@ -11,7 +12,6 @@ use syn::{GenericParam, Ident, ItemTrait, TypeParamBound, parse_quote, parse2}; use crate::delegate_components::impl_delegate_components; use crate::parse::{DefinePreset, DelegateEntry, 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 2b322b95..3969a465 100644 --- a/crates/cgp-macro-lib/src/lib.rs +++ b/crates/cgp-macro-lib/src/lib.rs @@ -24,7 +24,6 @@ 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; From 0965d58e818e0b8d1a27b1951fb13cb48d5bde74 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 30 May 2026 21:50:43 +0200 Subject: [PATCH 11/46] Add IdentWithTypeArgs --- .../delegate_component/statement/for_loop.rs | 6 ++-- .../types/delegate_component/table/main.rs | 6 ++-- .../src/types/generics/arguments.rs | 28 +++++++++++++++++ .../cgp-macro-core/src/types/generics/mod.rs | 2 ++ .../src/types/ident/ident_type.rs | 31 +++++++++++++++++++ .../src/types/ident/ident_with_args.rs | 27 ++++++++++++++++ crates/cgp-macro-core/src/types/ident/mod.rs | 5 +++ crates/cgp-macro-core/src/types/ident_type.rs | 19 ------------ crates/cgp-macro-core/src/types/mod.rs | 2 +- .../src/types/namespace/table.rs | 10 +++--- 10 files changed, 105 insertions(+), 31 deletions(-) create mode 100644 crates/cgp-macro-core/src/types/generics/arguments.rs create mode 100644 crates/cgp-macro-core/src/types/ident/ident_type.rs create mode 100644 crates/cgp-macro-core/src/types/ident/ident_with_args.rs create mode 100644 crates/cgp-macro-core/src/types/ident/mod.rs delete mode 100644 crates/cgp-macro-core/src/types/ident_type.rs diff --git a/crates/cgp-macro-core/src/types/delegate_component/statement/for_loop.rs b/crates/cgp-macro-core/src/types/delegate_component/statement/for_loop.rs index 511c633a..3a3b416b 100644 --- a/crates/cgp-macro-core/src/types/delegate_component/statement/for_loop.rs +++ b/crates/cgp-macro-core/src/types/delegate_component/statement/for_loop.rs @@ -8,7 +8,7 @@ use crate::types::delegate_component::{ EvaluatedDelegateEntry, EvaluatedForEntry, NormalDelegateMapping, eval_delegate_entries_via_for, }; -use crate::types::ident_type::IdentType; +use crate::types::ident::IdentWithTypeGenerics; #[derive(Debug, Clone)] pub struct ForDelegateStatement { @@ -19,7 +19,7 @@ pub struct ForDelegateStatement { pub value: Ident, pub gt: Gt, pub in_token: In, - pub namespace: IdentType, + pub namespace: IdentWithTypeGenerics, pub where_clause: Option, pub mappings: Punctuated, } @@ -72,7 +72,7 @@ impl EvalForEntries for ForDelegateStatement { for_key: self.key.clone(), for_value: self.value.clone(), namespace_ident: self.namespace.ident.clone(), - namespace_generics: self.namespace.generics.clone(), + namespace_generics: self.namespace.type_generics.clone(), mapping_key: key.key, mapping_value: value_type.clone(), }; diff --git a/crates/cgp-macro-core/src/types/delegate_component/table/main.rs b/crates/cgp-macro-core/src/types/delegate_component/table/main.rs index 107dfb7f..103fb1d7 100644 --- a/crates/cgp-macro-core/src/types/delegate_component/table/main.rs +++ b/crates/cgp-macro-core/src/types/delegate_component/table/main.rs @@ -6,7 +6,7 @@ use syn::{ItemImpl, ItemStruct, Type, braced, parse2}; use crate::traits::ParseOptionalKeyword; use crate::types::delegate_component::{DelegateEntries, ExtractInnerDelegateTables}; use crate::types::generics::ImplGenerics; -use crate::types::ident_type::IdentType; +use crate::types::ident::IdentWithTypeGenerics; use crate::types::keyword::Keyword; use crate::types::keywords::New; use crate::types::provider_struct::ProviderStruct; @@ -53,11 +53,11 @@ impl DelegateTable { let mut item_structs = Vec::new(); if self.new.is_some() { - let struct_type: IdentType = parse2(self.table_type.to_token_stream())?; + let struct_type: IdentWithTypeGenerics = parse2(self.table_type.to_token_stream())?; item_structs.push( ProviderStruct { ident: struct_type.ident, - generics: struct_type.generics.generics, + generics: struct_type.type_generics.generics, } .to_item_struct()?, ); diff --git a/crates/cgp-macro-core/src/types/generics/arguments.rs b/crates/cgp-macro-core/src/types/generics/arguments.rs new file mode 100644 index 00000000..ec4d80a4 --- /dev/null +++ b/crates/cgp-macro-core/src/types/generics/arguments.rs @@ -0,0 +1,28 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::AngleBracketedGenericArguments; +use syn::parse::{Parse, ParseStream}; +use syn::token::Lt; + +pub struct GenericArguments { + pub args: Option, +} + +impl Parse for GenericArguments { + fn parse(input: ParseStream) -> syn::Result { + if input.peek(Lt) { + let args = input.parse()?; + Ok(Self { args: Some(args) }) + } else { + Ok(Self { args: None }) + } + } +} + +impl ToTokens for GenericArguments { + fn to_tokens(&self, tokens: &mut TokenStream) { + if let Some(args) = &self.args { + args.to_tokens(tokens); + } + } +} diff --git a/crates/cgp-macro-core/src/types/generics/mod.rs b/crates/cgp-macro-core/src/types/generics/mod.rs index 9d6eafc8..85037d78 100644 --- a/crates/cgp-macro-core/src/types/generics/mod.rs +++ b/crates/cgp-macro-core/src/types/generics/mod.rs @@ -1,5 +1,7 @@ +mod arguments; mod impl_generics; mod type_generics; +pub use arguments::*; pub use impl_generics::*; pub use type_generics::*; diff --git a/crates/cgp-macro-core/src/types/ident/ident_type.rs b/crates/cgp-macro-core/src/types/ident/ident_type.rs new file mode 100644 index 00000000..f2c6a36a --- /dev/null +++ b/crates/cgp-macro-core/src/types/ident/ident_type.rs @@ -0,0 +1,31 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::Ident; +use syn::parse::{Parse, ParseStream}; + +use crate::types::generics::TypeGenerics; + +#[derive(Debug, Clone)] +pub struct IdentWithTypeGenerics { + pub ident: Ident, + pub type_generics: TypeGenerics, +} + +impl Parse for IdentWithTypeGenerics { + fn parse(input: ParseStream) -> syn::Result { + let ident = input.parse()?; + let type_generics = input.parse()?; + + Ok(Self { + ident, + type_generics, + }) + } +} + +impl ToTokens for IdentWithTypeGenerics { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + self.type_generics.to_tokens(tokens); + } +} diff --git a/crates/cgp-macro-core/src/types/ident/ident_with_args.rs b/crates/cgp-macro-core/src/types/ident/ident_with_args.rs new file mode 100644 index 00000000..bf8aa663 --- /dev/null +++ b/crates/cgp-macro-core/src/types/ident/ident_with_args.rs @@ -0,0 +1,27 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::Ident; +use syn::parse::{Parse, ParseStream}; + +use crate::types::generics::GenericArguments; + +pub struct IdentWithTypeArgs { + pub ident: Ident, + pub type_args: GenericArguments, +} + +impl Parse for IdentWithTypeArgs { + fn parse(input: ParseStream) -> syn::Result { + let ident = input.parse()?; + let type_args = input.parse()?; + + Ok(Self { ident, type_args }) + } +} + +impl ToTokens for IdentWithTypeArgs { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + self.type_args.to_tokens(tokens); + } +} diff --git a/crates/cgp-macro-core/src/types/ident/mod.rs b/crates/cgp-macro-core/src/types/ident/mod.rs new file mode 100644 index 00000000..219cbfa5 --- /dev/null +++ b/crates/cgp-macro-core/src/types/ident/mod.rs @@ -0,0 +1,5 @@ +pub mod ident_type; +pub mod ident_with_args; + +pub use ident_type::*; +pub use ident_with_args::*; diff --git a/crates/cgp-macro-core/src/types/ident_type.rs b/crates/cgp-macro-core/src/types/ident_type.rs deleted file mode 100644 index 2578807c..00000000 --- a/crates/cgp-macro-core/src/types/ident_type.rs +++ /dev/null @@ -1,19 +0,0 @@ -use syn::Ident; -use syn::parse::{Parse, ParseStream}; - -use crate::types::generics::TypeGenerics; - -#[derive(Debug, Clone)] -pub struct IdentType { - pub ident: Ident, - pub generics: TypeGenerics, -} - -impl Parse for IdentType { - fn parse(input: ParseStream) -> syn::Result { - let ident = input.parse()?; - let generics = input.parse()?; - - Ok(Self { ident, generics }) - } -} diff --git a/crates/cgp-macro-core/src/types/mod.rs b/crates/cgp-macro-core/src/types/mod.rs index 38e287f9..4674579e 100644 --- a/crates/cgp-macro-core/src/types/mod.rs +++ b/crates/cgp-macro-core/src/types/mod.rs @@ -2,7 +2,7 @@ pub mod cgp_impl; pub mod cgp_provider; pub mod delegate_component; pub mod generics; -pub mod ident_type; +pub mod ident; pub mod keyword; pub mod keywords; pub mod namespace; diff --git a/crates/cgp-macro-core/src/types/namespace/table.rs b/crates/cgp-macro-core/src/types/namespace/table.rs index d0078262..6d15436d 100644 --- a/crates/cgp-macro-core/src/types/namespace/table.rs +++ b/crates/cgp-macro-core/src/types/namespace/table.rs @@ -7,7 +7,7 @@ use crate::types::delegate_component::{ DelegateEntries, EvalDelegateEntries, EvalDelegateEntry, EvalForEntry, }; use crate::types::generics::ImplGenerics; -use crate::types::ident_type::IdentType; +use crate::types::ident::IdentWithTypeGenerics; use crate::types::keyword::Keyword; use crate::types::keywords::New; use crate::types::namespace::{EvaluatedNamespaceTable, InheritNamespaceStatement}; @@ -15,8 +15,8 @@ use crate::types::namespace::{EvaluatedNamespaceTable, InheritNamespaceStatement pub struct NamespaceTable { pub impl_generics: ImplGenerics, pub new: Option>, - pub namespace_type: IdentType, - pub parent_namespace: Option<(Colon, IdentType)>, + pub namespace_type: IdentWithTypeGenerics, + pub parent_namespace: Option<(Colon, IdentWithTypeGenerics)>, pub entries: DelegateEntries, } @@ -55,7 +55,7 @@ impl Parse for NamespaceTable { impl NamespaceTable { pub fn build_namespace_trait(&self) -> syn::Result { let namespace_ident = &self.namespace_type.ident; - let mut namespace_generics = self.namespace_type.generics.clone(); + let mut namespace_generics = self.namespace_type.type_generics.clone(); namespace_generics.params.push(parse_quote!(__Table__)); let namespace_trait: Type = parse_quote!( #namespace_ident #namespace_generics ); @@ -128,7 +128,7 @@ impl NamespaceTable { let for_entry = InheritNamespaceStatement { ident: parent_namespace.ident.clone(), - type_generics: parent_namespace.generics.clone(), + type_generics: parent_namespace.type_generics.clone(), local_table_ident: namespace_struct_ident, } .eval_for_entry(&table_type)?; From c9fb625b28e3ff65d0240b5b57d8a7696b1419e6 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 30 May 2026 22:10:56 +0200 Subject: [PATCH 12/46] Use IdentWithTypeArgs for namespace --- .../delegate_component/statement/eval.rs | 17 ++++++-------- .../delegate_component/statement/for_loop.rs | 7 +++--- .../delegate_component/statement/namespace.rs | 4 +--- .../src/types/generics/arguments.rs | 22 ++++++++++++++++++- .../src/types/ident/ident_with_args.rs | 10 +++++++++ .../src/types/namespace/inherit.rs | 20 ++++++++--------- .../src/types/namespace/table.rs | 7 +++--- 7 files changed, 54 insertions(+), 33 deletions(-) diff --git a/crates/cgp-macro-core/src/types/delegate_component/statement/eval.rs b/crates/cgp-macro-core/src/types/delegate_component/statement/eval.rs index 8a47c5b5..fc09911e 100644 --- a/crates/cgp-macro-core/src/types/delegate_component/statement/eval.rs +++ b/crates/cgp-macro-core/src/types/delegate_component/statement/eval.rs @@ -1,7 +1,7 @@ use syn::{Generics, Ident, Type, parse_quote}; use crate::types::delegate_component::{EvalDelegateEntry, EvaluatedDelegateEntry}; -use crate::types::generics::TypeGenerics; +use crate::types::ident::IdentWithTypeArgs; pub trait EvalForEntries { fn eval_for_entries(&self, table_type: &Type) -> syn::Result>; @@ -16,8 +16,7 @@ pub struct EvaluatedForEntry { pub table_type: Type, pub for_key: Ident, pub for_value: Ident, - pub namespace_ident: Ident, - pub namespace_generics: TypeGenerics, + pub namespace: IdentWithTypeArgs, pub mapping_key: Type, pub mapping_value: Type, } @@ -47,15 +46,13 @@ impl EvalDelegateEntry for EvaluatedForEntry { let table_type = &self.table_type; let namespace_trait: Type = { - let namespace_ident = &self.namespace_ident; - let mut namespace_generics = self.namespace_generics.clone(); + let namespace_ident = &self.namespace.ident; + let mut namespace_generics = self.namespace.type_args.clone(); + let namespace_generic_args = &mut namespace_generics.make_args().args; - namespace_generics - .generics - .params - .push(parse_quote!(#table_type)); + namespace_generic_args.push(parse_quote!(#table_type)); - namespace_generics.generics.params.push(parse_quote! { + namespace_generic_args.push(parse_quote! { Delegate = #mapping_value }); diff --git a/crates/cgp-macro-core/src/types/delegate_component/statement/for_loop.rs b/crates/cgp-macro-core/src/types/delegate_component/statement/for_loop.rs index 3a3b416b..d483312c 100644 --- a/crates/cgp-macro-core/src/types/delegate_component/statement/for_loop.rs +++ b/crates/cgp-macro-core/src/types/delegate_component/statement/for_loop.rs @@ -8,7 +8,7 @@ use crate::types::delegate_component::{ EvaluatedDelegateEntry, EvaluatedForEntry, NormalDelegateMapping, eval_delegate_entries_via_for, }; -use crate::types::ident::IdentWithTypeGenerics; +use crate::types::ident::IdentWithTypeArgs; #[derive(Debug, Clone)] pub struct ForDelegateStatement { @@ -19,7 +19,7 @@ pub struct ForDelegateStatement { pub value: Ident, pub gt: Gt, pub in_token: In, - pub namespace: IdentWithTypeGenerics, + pub namespace: IdentWithTypeArgs, pub where_clause: Option, pub mappings: Punctuated, } @@ -71,8 +71,7 @@ impl EvalForEntries for ForDelegateStatement { table_type: table_type.clone(), for_key: self.key.clone(), for_value: self.value.clone(), - namespace_ident: self.namespace.ident.clone(), - namespace_generics: self.namespace.type_generics.clone(), + namespace: self.namespace.clone(), mapping_key: key.key, mapping_value: value_type.clone(), }; diff --git a/crates/cgp-macro-core/src/types/delegate_component/statement/namespace.rs b/crates/cgp-macro-core/src/types/delegate_component/statement/namespace.rs index 81074ae3..04736773 100644 --- a/crates/cgp-macro-core/src/types/delegate_component/statement/namespace.rs +++ b/crates/cgp-macro-core/src/types/delegate_component/statement/namespace.rs @@ -6,7 +6,6 @@ use crate::types::delegate_component::{ EvalDelegateEntries, EvalForEntries, EvalForEntry, EvaluatedDelegateEntry, EvaluatedForEntry, eval_delegate_entries_via_for, }; -use crate::types::generics::TypeGenerics; use crate::types::keyword::Keyword; use crate::types::keywords::Namespace; @@ -40,8 +39,7 @@ impl EvalForEntry for NamespaceDelegateStatement { for_value: parse_quote!(__Value__), mapping_key: parse_quote!(__Key__), mapping_value: parse_quote!(__Value__), - namespace_ident: self.ident.clone(), - namespace_generics: TypeGenerics::default(), + namespace: self.ident.clone().into(), }; Ok(entry) diff --git a/crates/cgp-macro-core/src/types/generics/arguments.rs b/crates/cgp-macro-core/src/types/generics/arguments.rs index ec4d80a4..ba29be59 100644 --- a/crates/cgp-macro-core/src/types/generics/arguments.rs +++ b/crates/cgp-macro-core/src/types/generics/arguments.rs @@ -1,13 +1,22 @@ use proc_macro2::TokenStream; use quote::ToTokens; -use syn::AngleBracketedGenericArguments; use syn::parse::{Parse, ParseStream}; use syn::token::Lt; +use syn::{AngleBracketedGenericArguments, parse_quote}; +use crate::types::generics::TypeGenerics; + +#[derive(Debug, Clone, Default)] pub struct GenericArguments { pub args: Option, } +impl GenericArguments { + pub fn make_args(&mut self) -> &mut AngleBracketedGenericArguments { + self.args.get_or_insert_with(|| parse_quote!(<>)) + } +} + impl Parse for GenericArguments { fn parse(input: ParseStream) -> syn::Result { if input.peek(Lt) { @@ -26,3 +35,14 @@ impl ToTokens for GenericArguments { } } } + +impl From for GenericArguments { + fn from(generics: TypeGenerics) -> Self { + if generics.params.is_empty() { + Self { args: None } + } else { + let args = parse_quote!(#generics); + Self { args: Some(args) } + } + } +} diff --git a/crates/cgp-macro-core/src/types/ident/ident_with_args.rs b/crates/cgp-macro-core/src/types/ident/ident_with_args.rs index bf8aa663..8b295432 100644 --- a/crates/cgp-macro-core/src/types/ident/ident_with_args.rs +++ b/crates/cgp-macro-core/src/types/ident/ident_with_args.rs @@ -5,6 +5,7 @@ use syn::parse::{Parse, ParseStream}; use crate::types::generics::GenericArguments; +#[derive(Debug, Clone)] pub struct IdentWithTypeArgs { pub ident: Ident, pub type_args: GenericArguments, @@ -25,3 +26,12 @@ impl ToTokens for IdentWithTypeArgs { self.type_args.to_tokens(tokens); } } + +impl From for IdentWithTypeArgs { + fn from(ident: Ident) -> Self { + Self { + ident, + type_args: GenericArguments::default(), + } + } +} diff --git a/crates/cgp-macro-core/src/types/namespace/inherit.rs b/crates/cgp-macro-core/src/types/namespace/inherit.rs index 7852a286..19a14a7b 100644 --- a/crates/cgp-macro-core/src/types/namespace/inherit.rs +++ b/crates/cgp-macro-core/src/types/namespace/inherit.rs @@ -1,29 +1,28 @@ use syn::{Generics, Ident, Type, parse_quote}; use crate::types::delegate_component::{EvalForEntry, EvaluatedForEntry}; -use crate::types::generics::TypeGenerics; +use crate::types::ident::IdentWithTypeArgs; #[derive(Debug, Clone)] pub struct InheritNamespaceStatement { - pub ident: Ident, - pub type_generics: TypeGenerics, + pub namespace: IdentWithTypeArgs, pub local_table_ident: Ident, } impl EvalForEntry for InheritNamespaceStatement { fn eval_for_entry(&self, table_type: &Type) -> syn::Result { - let namespace_ident = self.ident.clone(); let local_table_ident = &self.local_table_ident; - let mut namespace_where_generics = self.type_generics.clone(); - - namespace_where_generics - .params + let mut namespace_constraint = self.namespace.clone(); + namespace_constraint + .type_args + .make_args() + .args .push(parse_quote!(#local_table_ident)); let mut generics = Generics::default(); generics.make_where_clause().predicates.push(parse_quote! { - __Key__: #namespace_ident #namespace_where_generics + __Key__: #namespace_constraint }); let for_entry = EvaluatedForEntry { @@ -33,8 +32,7 @@ impl EvalForEntry for InheritNamespaceStatement { for_value: parse_quote!(__Value__), mapping_key: parse_quote!(__Key__), mapping_value: parse_quote!(__Value__), - namespace_ident, - namespace_generics: self.type_generics.clone(), + namespace: self.namespace.clone(), }; Ok(for_entry) diff --git a/crates/cgp-macro-core/src/types/namespace/table.rs b/crates/cgp-macro-core/src/types/namespace/table.rs index 6d15436d..846195e4 100644 --- a/crates/cgp-macro-core/src/types/namespace/table.rs +++ b/crates/cgp-macro-core/src/types/namespace/table.rs @@ -7,7 +7,7 @@ use crate::types::delegate_component::{ DelegateEntries, EvalDelegateEntries, EvalDelegateEntry, EvalForEntry, }; use crate::types::generics::ImplGenerics; -use crate::types::ident::IdentWithTypeGenerics; +use crate::types::ident::{IdentWithTypeArgs, IdentWithTypeGenerics}; use crate::types::keyword::Keyword; use crate::types::keywords::New; use crate::types::namespace::{EvaluatedNamespaceTable, InheritNamespaceStatement}; @@ -16,7 +16,7 @@ pub struct NamespaceTable { pub impl_generics: ImplGenerics, pub new: Option>, pub namespace_type: IdentWithTypeGenerics, - pub parent_namespace: Option<(Colon, IdentWithTypeGenerics)>, + pub parent_namespace: Option<(Colon, IdentWithTypeArgs)>, pub entries: DelegateEntries, } @@ -127,8 +127,7 @@ impl NamespaceTable { }; let for_entry = InheritNamespaceStatement { - ident: parent_namespace.ident.clone(), - type_generics: parent_namespace.type_generics.clone(), + namespace: parent_namespace.clone(), local_table_ident: namespace_struct_ident, } .eval_for_entry(&table_type)?; From 5914fa2cc3bd69bec57e407ed3b688836973d5b2 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 30 May 2026 22:25:14 +0200 Subject: [PATCH 13/46] Replacing SimpleType with IdentWithTypeArgs --- .../delegate_component/statement/eval.rs | 2 +- .../src/types/generics/arguments.rs | 9 ++++---- .../src/types/ident/ident_with_args.rs | 8 ++++++- ...nt_type.rs => ident_with_type_generics.rs} | 0 crates/cgp-macro-core/src/types/ident/mod.rs | 4 ++-- .../src/types/namespace/inherit.rs | 1 - .../src/types/namespace/table.rs | 10 ++++---- crates/cgp-macro-lib/src/cgp_fn/attributes.rs | 6 ++--- crates/cgp-macro-lib/src/cgp_fn/spec.rs | 4 ++-- crates/cgp-macro-lib/src/cgp_fn/use_type.rs | 18 +++++---------- .../cgp-macro-lib/src/cgp_impl/attributes.rs | 8 +++---- .../src/cgp_impl/provider_bounds.rs | 19 ++++++--------- .../cgp-macro-lib/src/cgp_impl/transform.rs | 23 +++++++------------ .../src/cgp_impl/use_provider.rs | 5 ++-- crates/cgp-macro-lib/src/for_each_replace.rs | 10 ++++---- 15 files changed, 58 insertions(+), 69 deletions(-) rename crates/cgp-macro-core/src/types/ident/{ident_type.rs => ident_with_type_generics.rs} (100%) diff --git a/crates/cgp-macro-core/src/types/delegate_component/statement/eval.rs b/crates/cgp-macro-core/src/types/delegate_component/statement/eval.rs index fc09911e..dfc8530e 100644 --- a/crates/cgp-macro-core/src/types/delegate_component/statement/eval.rs +++ b/crates/cgp-macro-core/src/types/delegate_component/statement/eval.rs @@ -48,7 +48,7 @@ impl EvalDelegateEntry for EvaluatedForEntry { let namespace_trait: Type = { let namespace_ident = &self.namespace.ident; let mut namespace_generics = self.namespace.type_args.clone(); - let namespace_generic_args = &mut namespace_generics.make_args().args; + let namespace_generic_args = &mut namespace_generics.make_args(); namespace_generic_args.push(parse_quote!(#table_type)); diff --git a/crates/cgp-macro-core/src/types/generics/arguments.rs b/crates/cgp-macro-core/src/types/generics/arguments.rs index ba29be59..f0284ea9 100644 --- a/crates/cgp-macro-core/src/types/generics/arguments.rs +++ b/crates/cgp-macro-core/src/types/generics/arguments.rs @@ -1,8 +1,9 @@ use proc_macro2::TokenStream; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; -use syn::token::Lt; -use syn::{AngleBracketedGenericArguments, parse_quote}; +use syn::punctuated::Punctuated; +use syn::token::{Comma, Lt}; +use syn::{AngleBracketedGenericArguments, GenericArgument, parse_quote}; use crate::types::generics::TypeGenerics; @@ -12,8 +13,8 @@ pub struct GenericArguments { } impl GenericArguments { - pub fn make_args(&mut self) -> &mut AngleBracketedGenericArguments { - self.args.get_or_insert_with(|| parse_quote!(<>)) + pub fn make_args(&mut self) -> &mut Punctuated { + &mut self.args.get_or_insert_with(|| parse_quote!(<>)).args } } diff --git a/crates/cgp-macro-core/src/types/ident/ident_with_args.rs b/crates/cgp-macro-core/src/types/ident/ident_with_args.rs index 8b295432..3d32de1c 100644 --- a/crates/cgp-macro-core/src/types/ident/ident_with_args.rs +++ b/crates/cgp-macro-core/src/types/ident/ident_with_args.rs @@ -1,7 +1,7 @@ use proc_macro2::TokenStream; use quote::ToTokens; -use syn::Ident; use syn::parse::{Parse, ParseStream}; +use syn::{Ident, Type, parse_quote}; use crate::types::generics::GenericArguments; @@ -35,3 +35,9 @@ impl From for IdentWithTypeArgs { } } } + +impl From for Type { + fn from(value: IdentWithTypeArgs) -> Self { + parse_quote!(#value) + } +} diff --git a/crates/cgp-macro-core/src/types/ident/ident_type.rs b/crates/cgp-macro-core/src/types/ident/ident_with_type_generics.rs similarity index 100% rename from crates/cgp-macro-core/src/types/ident/ident_type.rs rename to crates/cgp-macro-core/src/types/ident/ident_with_type_generics.rs diff --git a/crates/cgp-macro-core/src/types/ident/mod.rs b/crates/cgp-macro-core/src/types/ident/mod.rs index 219cbfa5..db89db13 100644 --- a/crates/cgp-macro-core/src/types/ident/mod.rs +++ b/crates/cgp-macro-core/src/types/ident/mod.rs @@ -1,5 +1,5 @@ -pub mod ident_type; pub mod ident_with_args; +pub mod ident_with_type_generics; -pub use ident_type::*; pub use ident_with_args::*; +pub use ident_with_type_generics::*; diff --git a/crates/cgp-macro-core/src/types/namespace/inherit.rs b/crates/cgp-macro-core/src/types/namespace/inherit.rs index 19a14a7b..e565c5ab 100644 --- a/crates/cgp-macro-core/src/types/namespace/inherit.rs +++ b/crates/cgp-macro-core/src/types/namespace/inherit.rs @@ -17,7 +17,6 @@ impl EvalForEntry for InheritNamespaceStatement { namespace_constraint .type_args .make_args() - .args .push(parse_quote!(#local_table_ident)); let mut generics = Generics::default(); diff --git a/crates/cgp-macro-core/src/types/namespace/table.rs b/crates/cgp-macro-core/src/types/namespace/table.rs index 846195e4..2d5e4c58 100644 --- a/crates/cgp-macro-core/src/types/namespace/table.rs +++ b/crates/cgp-macro-core/src/types/namespace/table.rs @@ -15,7 +15,7 @@ use crate::types::namespace::{EvaluatedNamespaceTable, InheritNamespaceStatement pub struct NamespaceTable { pub impl_generics: ImplGenerics, pub new: Option>, - pub namespace_type: IdentWithTypeGenerics, + pub namespace: IdentWithTypeGenerics, pub parent_namespace: Option<(Colon, IdentWithTypeArgs)>, pub entries: DelegateEntries, } @@ -45,7 +45,7 @@ impl Parse for NamespaceTable { Ok(Self { impl_generics, new, - namespace_type, + namespace: namespace_type, parent_namespace, entries, }) @@ -54,8 +54,8 @@ impl Parse for NamespaceTable { impl NamespaceTable { pub fn build_namespace_trait(&self) -> syn::Result { - let namespace_ident = &self.namespace_type.ident; - let mut namespace_generics = self.namespace_type.type_generics.clone(); + let namespace_ident = &self.namespace.ident; + let mut namespace_generics = self.namespace.type_generics.clone(); namespace_generics.params.push(parse_quote!(__Table__)); let namespace_trait: Type = parse_quote!( #namespace_ident #namespace_generics ); @@ -113,7 +113,7 @@ impl NamespaceTable { )); } - let namespace_ident = self.namespace_type.ident.clone(); + let namespace_ident = self.namespace.ident.clone(); let table_type: Type = parse_quote!(__Table__); diff --git a/crates/cgp-macro-lib/src/cgp_fn/attributes.rs b/crates/cgp-macro-lib/src/cgp_fn/attributes.rs index 9f6e30f6..c341e8ca 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/attributes.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/attributes.rs @@ -1,10 +1,10 @@ +use cgp_macro_core::types::ident::IdentWithTypeArgs; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{Attribute, GenericParam, TypeParamBound, WherePredicate}; use crate::cgp_fn::{FunctionAttributes, UseTypeSpec}; use crate::cgp_impl::UseProviderSpec; -use crate::parse::SimpleType; pub fn parse_function_attributes( attributes: Vec, @@ -25,8 +25,8 @@ pub fn parse_function_attributes( parsed_attributes.extend_where.extend(where_predicates); } else if ident == "uses" { - let uses = - attribute.parse_args_with(Punctuated::::parse_terminated)?; + let uses = attribute + .parse_args_with(Punctuated::::parse_terminated)?; parsed_attributes.uses.extend(uses); } else if ident == "use_type" { diff --git a/crates/cgp-macro-lib/src/cgp_fn/spec.rs b/crates/cgp-macro-lib/src/cgp_fn/spec.rs index 3dc2ad94..9b66afae 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/spec.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/spec.rs @@ -1,10 +1,10 @@ +use cgp_macro_core::types::ident::IdentWithTypeArgs; use syn::token::Mut; use syn::{GenericParam, Ident, Type, TypeParamBound, WherePredicate}; use crate::cgp_fn::UseTypeSpec; use crate::cgp_impl::UseProviderSpec; use crate::derive_getter::FieldMode; -use crate::parse::SimpleType; #[derive(Clone, Eq, PartialEq)] pub struct ImplicitArgField { @@ -19,7 +19,7 @@ pub struct ImplicitArgField { pub struct FunctionAttributes { pub extend: Vec, pub extend_where: Vec, - pub uses: Vec, + pub uses: Vec, pub use_type: Vec, pub use_provider: Vec, pub impl_generics: Vec, diff --git a/crates/cgp-macro-lib/src/cgp_fn/use_type.rs b/crates/cgp-macro-lib/src/cgp_fn/use_type.rs index f35c38fb..ff0bf132 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/use_type.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/use_type.rs @@ -1,13 +1,11 @@ -use quote::ToTokens; +use cgp_macro_core::types::ident::IdentWithTypeArgs; use syn::parse::{Parse, ParseStream}; use syn::token::{As, At, Brace, Colon, Comma, Eq, Gt, Lt}; -use syn::{Ident, Type, braced, parse_quote, parse2}; - -use crate::parse::SimpleType; +use syn::{Ident, Type, braced, parse_quote}; pub struct UseTypeSpec { pub context_type: Type, - pub trait_path: SimpleType, + pub trait_path: IdentWithTypeArgs, pub type_idents: Vec, } @@ -44,8 +42,7 @@ impl Parse for UseTypeSpec { let (context_type, body) = if input.peek(At) { let _: At = input.parse()?; - let context_type: SimpleType = input.parse()?; - let context_type = parse2(context_type.into_token_stream())?; + let context_type: Type = input.parse::()?.into(); let _: Colon = input.parse()?; let _: Colon = input.parse()?; @@ -62,15 +59,12 @@ impl Parse for UseTypeSpec { let trait_path = if body.peek(Lt) { let _: Lt = body.parse()?; - let trait_path: SimpleType = body.parse()?; + let trait_path: IdentWithTypeArgs = body.parse()?; let _: Gt = body.parse()?; trait_path } else { let name: Ident = body.parse()?; - SimpleType { - name, - generics: None, - } + name.into() }; let _: Colon = body.parse()?; diff --git a/crates/cgp-macro-lib/src/cgp_impl/attributes.rs b/crates/cgp-macro-lib/src/cgp_impl/attributes.rs index 7b81e3a3..35128b27 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/attributes.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/attributes.rs @@ -1,12 +1,12 @@ use core::mem; +use cgp_macro_core::types::ident::IdentWithTypeArgs; use syn::Attribute; use syn::punctuated::Punctuated; use syn::token::Comma; use crate::cgp_fn::UseTypeSpec; use crate::cgp_impl::use_provider::UseProviderSpec; -use crate::parse::SimpleType; pub fn parse_impl_attributes(attributes: &mut Vec) -> syn::Result { let mut parsed_attributes = ImplAttributes::default(); @@ -16,8 +16,8 @@ pub fn parse_impl_attributes(attributes: &mut Vec) -> syn::Result::parse_terminated)?; + let uses = attribute + .parse_args_with(Punctuated::::parse_terminated)?; parsed_attributes.uses.extend(uses); } else if ident == "use_type" { let use_type = attribute @@ -40,7 +40,7 @@ pub fn parse_impl_attributes(attributes: &mut Vec) -> syn::Result, + pub uses: Vec, pub use_type: Vec, pub use_provider: Vec, } diff --git a/crates/cgp-macro-lib/src/cgp_impl/provider_bounds.rs b/crates/cgp-macro-lib/src/cgp_impl/provider_bounds.rs index b518a4ef..94a8e870 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/provider_bounds.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/provider_bounds.rs @@ -1,4 +1,4 @@ -use quote::{ToTokens, quote}; +use quote::quote; use syn::punctuated::Punctuated; use syn::token::Plus; use syn::{Type, TypeParamBound, WherePredicate, parse_quote, parse2}; @@ -19,18 +19,13 @@ pub fn derive_provider_bounds( let mut bounds = Punctuated::::new(); for bound in &spec.provider_trait_bounds { - let trait_ident = &bound.name; - let mut m_generics = bound.generics.clone(); + let mut bound = bound.clone(); + bound + .type_args + .make_args() + .insert(0, parse_quote!(#context_type)); - let generics = m_generics.get_or_insert_with(|| parse_quote!(<>)); - generics - .args - .insert(0, parse2(context_type.to_token_stream())?); - - let trait_bound = parse2(quote! { - #trait_ident #generics - })?; - bounds.push(trait_bound); + bounds.push(parse_quote!(#bound)); } let predicate = parse2(quote! { diff --git a/crates/cgp-macro-lib/src/cgp_impl/transform.rs b/crates/cgp-macro-lib/src/cgp_impl/transform.rs index 08a1d16c..f64d272d 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/transform.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/transform.rs @@ -1,18 +1,17 @@ use cgp_macro_core::functions::to_snake_case_ident; +use cgp_macro_core::types::ident::IdentWithTypeArgs; use cgp_macro_core::visitors::{ ReplaceSelfReceiverVisitor, ReplaceSelfTypeVisitor, ReplaceSelfValueVisitor, }; use proc_macro2::Span; -use quote::{ToTokens, quote}; +use quote::ToTokens; use syn::token::For; use syn::visit_mut::VisitMut; -use syn::{Ident, ImplItem, ItemImpl, Type, parse2}; - -use crate::parse::SimpleType; +use syn::{Ident, ImplItem, ItemImpl, Type, parse_quote, parse2}; pub fn transform_impl_trait( item_impl: &ItemImpl, - consumer_trait_path: &SimpleType, + consumer_trait_path: &IdentWithTypeArgs, provider_type: &Type, context_type: &Type, ) -> syn::Result { @@ -40,16 +39,10 @@ pub fn transform_impl_trait( let mut provider_trait_path = consumer_trait_path.clone(); - match &mut provider_trait_path.generics { - Some(generics) => { - generics - .args - .insert(0, parse2(context_type.to_token_stream())?); - } - None => { - provider_trait_path.generics = Some(parse2(quote! { < #context_type > })?); - } - } + provider_trait_path + .type_args + .make_args() + .insert(0, parse_quote!(#context_type)); out_impl.trait_ = Some(( None, diff --git a/crates/cgp-macro-lib/src/cgp_impl/use_provider.rs b/crates/cgp-macro-lib/src/cgp_impl/use_provider.rs index 7f4d4225..b0c81047 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/use_provider.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/use_provider.rs @@ -1,14 +1,13 @@ +use cgp_macro_core::types::ident::IdentWithTypeArgs; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::token::{Colon, Plus}; use syn::{Type, parse_quote}; -use crate::parse::SimpleType; - pub struct UseProviderSpec { pub context_type: Type, pub provider_type: Type, - pub provider_trait_bounds: Punctuated, + pub provider_trait_bounds: Punctuated, } impl Parse for UseProviderSpec { diff --git a/crates/cgp-macro-lib/src/for_each_replace.rs b/crates/cgp-macro-lib/src/for_each_replace.rs index ccb739b9..6133e13f 100644 --- a/crates/cgp-macro-lib/src/for_each_replace.rs +++ b/crates/cgp-macro-lib/src/for_each_replace.rs @@ -1,5 +1,6 @@ use alloc::vec::Vec; +use cgp_macro_core::types::ident::IdentWithTypeArgs; use proc_macro2::{Group, TokenStream, TokenTree}; use quote::ToTokens; use syn::__private::parse_brackets; @@ -9,7 +10,7 @@ use syn::punctuated::Punctuated; use syn::token::{Comma, Or}; use syn::{Ident, braced}; -use crate::parse::{DelegateKey, SimpleType}; +use crate::parse::DelegateKey; pub struct ReplaceSpecs { pub target_ident: Ident, @@ -19,9 +20,10 @@ pub struct ReplaceSpecs { impl Parse for ReplaceSpecs { fn parse(input: ParseStream) -> syn::Result { - let raw_replacements: Vec> = { + let raw_replacements: Vec> = { let content = parse_brackets(input)?.content; - let types = , Comma>>::parse_terminated(&content)?; + let types = + , Comma>>::parse_terminated(&content)?; types.into_iter().collect() }; @@ -58,7 +60,7 @@ impl Parse for ReplaceSpecs { let replacements = raw_replacements .into_iter() .filter(|replacement| { - let target_ident = &replacement.ty.name; + let target_ident = &replacement.ty.ident; exclude.iter().all(|exclude| exclude != target_ident) }) From 6628353f0f869adc857887ed16165db738cbf271 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 30 May 2026 22:47:48 +0200 Subject: [PATCH 14/46] Replace SimpleType with IdentWitTypeArgs --- .../src/derive_provider/component_name.rs | 7 ++-- .../src/derive_provider/derive.rs | 30 ++++++++--------- .../src/entrypoints/cgp_inherit.rs | 11 +++---- .../src/entrypoints/cgp_preset.rs | 15 +++++---- .../src/parse/check_components.rs | 7 ++-- .../cgp-macro-lib/src/parse/define_preset.rs | 7 ++-- .../parse/delegate_and_check_components.rs | 7 ++-- .../src/parse/delegate_components.rs | 7 ++-- crates/cgp-macro-lib/src/parse/mod.rs | 2 -- crates/cgp-macro-lib/src/parse/simple_type.rs | 33 ------------------- .../src/preset/impl_is_preset.rs | 7 ++-- 11 files changed, 49 insertions(+), 84 deletions(-) delete mode 100644 crates/cgp-macro-lib/src/parse/simple_type.rs diff --git a/crates/cgp-macro-lib/src/derive_provider/component_name.rs b/crates/cgp-macro-lib/src/derive_provider/component_name.rs index 9179695a..01744cbb 100644 --- a/crates/cgp-macro-lib/src/derive_provider/component_name.rs +++ b/crates/cgp-macro-lib/src/derive_provider/component_name.rs @@ -1,9 +1,8 @@ +use cgp_macro_core::types::ident::IdentWithTypeArgs; use quote::ToTokens; use syn::spanned::Spanned; use syn::{Error, Ident, ItemImpl, Type, parse2}; -use crate::parse::SimpleType; - pub fn derive_component_name_from_provider_impl(provider_impl: &ItemImpl) -> syn::Result { let provider_trait = provider_impl.trait_.as_ref().ok_or_else(|| { Error::new( @@ -12,10 +11,10 @@ pub fn derive_component_name_from_provider_impl(provider_impl: &ItemImpl) -> syn ) })?; - let provider_trait: SimpleType = parse2(provider_trait.1.to_token_stream())?; + let provider_trait: IdentWithTypeArgs = parse2(provider_trait.1.to_token_stream())?; let component_ident = Ident::new( - &format!("{}Component", provider_trait.name), + &format!("{}Component", provider_trait.ident), provider_trait.span(), ); diff --git a/crates/cgp-macro-lib/src/derive_provider/derive.rs b/crates/cgp-macro-lib/src/derive_provider/derive.rs index b6507c38..5d20800c 100644 --- a/crates/cgp-macro-lib/src/derive_provider/derive.rs +++ b/crates/cgp-macro-lib/src/derive_provider/derive.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; -use proc_macro2::{Span, TokenStream}; +use cgp_macro_core::types::ident::IdentWithTypeGenerics; +use proc_macro2::Span; use quote::quote; use syn::punctuated::Punctuated; use syn::spanned::Spanned; @@ -11,30 +12,27 @@ use syn::{ }; use crate::derive_provider::replace_provider_in_generics; -use crate::parse::SimpleType; pub fn derive_provider_struct(provider_impl: &ItemImpl) -> syn::Result { let impl_self_type = &provider_impl.self_ty; - let provider_type: SimpleType = syn::parse2(quote!( #impl_self_type ))?; + let provider_type: IdentWithTypeGenerics = syn::parse2(quote!( #impl_self_type ))?; - let provider_name = &provider_type.name; + let provider_name = &provider_type.ident; + let type_generics_params = &provider_type.type_generics.params; - let provider_field = match &provider_type.generics { - Some(generics) => { - let args = &generics.args; - quote! { - #generics - ( pub ::core::marker::PhantomData<( #args )> ) - } + let provider_struct = if type_generics_params.is_empty() { + parse_quote! { + pub struct #provider_name; + } + } else { + parse_quote! { + pub struct #provider_name<#type_generics_params>( + pub ::core::marker::PhantomData<(#type_generics_params)> + ); } - None => TokenStream::new(), }; - let provider_struct = syn::parse2(quote! { - pub struct #provider_name #provider_field; - })?; - Ok(provider_struct) } diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_inherit.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_inherit.rs index 42745075..4d375d6f 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_inherit.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_inherit.rs @@ -1,14 +1,13 @@ use cgp_macro_core::types::generics::TypeGenerics; +use cgp_macro_core::types::ident::IdentWithTypeArgs; use proc_macro2::TokenStream; use quote::quote; use syn::{Ident, ItemImpl, ItemStruct, parse_quote, parse2}; -use crate::parse::SimpleType; - pub fn cgp_inherit(attr: TokenStream, body: TokenStream) -> syn::Result { let context_struct: ItemStruct = parse2(body)?; - let preset: SimpleType = parse2(attr)?; + let preset: IdentWithTypeArgs = parse2(attr)?; let type_generics = TypeGenerics::try_from(&context_struct.generics)?; @@ -27,10 +26,10 @@ pub fn cgp_inherit(attr: TokenStream, body: TokenStream) -> syn::Result, - preset: &SimpleType, + preset: &IdentWithTypeArgs, ) -> syn::Result<(ItemImpl, ItemImpl)> { - let preset_name = &preset.name; - let preset_generics = &preset.generics; + let preset_name = &preset.ident; + let preset_generics = &preset.type_args; let provider_params = match provider_generics { Some(generics) => { diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs index 7c276990..46f32b8d 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs @@ -2,6 +2,7 @@ use std::collections::HashSet; use cgp_macro_core::functions::to_snake_case_str; use cgp_macro_core::types::generics::ImplGenerics; +use cgp_macro_core::types::ident::IdentWithTypeArgs; use cgp_macro_core::types::provider_struct::ProviderStruct; use proc_macro2::{Span, TokenStream}; use quote::{ToTokens, TokenStreamExt, quote}; @@ -10,13 +11,13 @@ use syn::token::{At, Comma}; use syn::{GenericParam, Ident, ItemTrait, TypeParamBound, parse_quote, parse2}; use crate::delegate_components::impl_delegate_components; -use crate::parse::{DefinePreset, DelegateEntry, SimpleType}; +use crate::parse::{DefinePreset, DelegateEntry}; use crate::preset::{define_substitution_macro, impl_components_is_preset}; pub fn define_preset(body: TokenStream) -> syn::Result { let ast: DefinePreset = syn::parse2(body)?; - let delegate_entries: Punctuated, Comma> = ast + let delegate_entries: Punctuated, Comma> = ast .delegate_entries .iter() .map(|entry| entry.entry.clone()) @@ -36,8 +37,8 @@ pub fn define_preset(body: TokenStream) -> syn::Result { }; if let Some(parent) = m_parent { - let parent_ident = &parent.name; - let parent_generics = &parent.generics; + let parent_ident = &parent.ident; + let parent_generics = &parent.type_args; let parent_components_ident = Ident::new( &format!("__{parent_ident}Components__"), @@ -58,7 +59,7 @@ pub fn define_preset(body: TokenStream) -> syn::Result { for entry in ast.delegate_entries.iter() { if entry.is_override.is_some() { for component in entry.entry.keys.iter() { - overrides.push(&component.ty.name); + overrides.push(&component.ty.ident); } } } @@ -194,7 +195,7 @@ pub fn define_preset(body: TokenStream) -> syn::Result { let mut parent_exports = TokenStream::new(); for parent in parent_presets.iter() { - let parent_ident = &parent.parent_type.name; + let parent_ident = &parent.parent_type.ident; parent_exports.append_all(quote! { #[doc(hidden)] #[doc(no_inline)] @@ -224,7 +225,7 @@ pub fn define_preset(body: TokenStream) -> syn::Result { for entry in delegate_entries.iter() { for component in entry.keys.iter() { - let component_name = &component.ty.name; + let component_name = &component.ty.ident; components.insert(component_name.clone()); for param in component.generics.generics.params.iter() { diff --git a/crates/cgp-macro-lib/src/parse/check_components.rs b/crates/cgp-macro-lib/src/parse/check_components.rs index 00bca26b..924d091f 100644 --- a/crates/cgp-macro-lib/src/parse/check_components.rs +++ b/crates/cgp-macro-lib/src/parse/check_components.rs @@ -1,4 +1,5 @@ use cgp_macro_core::types::generics::ImplGenerics; +use cgp_macro_core::types::ident::IdentWithTypeArgs; use proc_macro2::Span; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; @@ -7,8 +8,6 @@ use syn::spanned::Spanned; use syn::token::{Bracket, Colon, Comma, Lt, Pound, Where}; use syn::{Attribute, Ident, Type, WhereClause, braced, bracketed, parse2}; -use crate::parse::SimpleType; - pub struct CheckComponentsSpecs { pub specs: Vec, } @@ -97,10 +96,10 @@ impl Parse for CheckComponents { let trait_name = if let Some(check_trait_name) = m_check_trait_name { check_trait_name } else { - let context_type: SimpleType = parse2(context_type.to_token_stream())?; + let context_type: IdentWithTypeArgs = parse2(context_type.to_token_stream())?; Ident::new( - &format!("__Check{}", context_type.name), + &format!("__Check{}", context_type.ident), context_type.span(), ) }; diff --git a/crates/cgp-macro-lib/src/parse/define_preset.rs b/crates/cgp-macro-lib/src/parse/define_preset.rs index 53df3049..3de9e30d 100644 --- a/crates/cgp-macro-lib/src/parse/define_preset.rs +++ b/crates/cgp-macro-lib/src/parse/define_preset.rs @@ -1,3 +1,4 @@ +use cgp_macro_core::types::ident::IdentWithTypeArgs; use proc_macro2::TokenStream; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; @@ -5,7 +6,7 @@ use syn::punctuated::Punctuated; use syn::token::{At, Colon, Comma, Override, Plus, Pound}; use syn::{Error, Ident, braced, bracketed, parenthesized}; -use crate::parse::{DelegateEntry, SimpleType, TypeSpec}; +use crate::parse::{DelegateEntry, TypeSpec}; pub struct DefinePreset { pub provider_wrapper: Option, @@ -16,7 +17,7 @@ pub struct DefinePreset { pub struct DelegatePresetEntry { pub is_override: Option, - pub entry: DelegateEntry, + pub entry: DelegateEntry, } impl Parse for DefinePreset { @@ -81,7 +82,7 @@ impl Parse for DelegatePresetEntry { #[derive(Clone)] pub struct PresetParent { pub has_expanded: Option, - pub parent_type: SimpleType, + pub parent_type: IdentWithTypeArgs, } impl Parse for PresetParent { diff --git a/crates/cgp-macro-lib/src/parse/delegate_and_check_components.rs b/crates/cgp-macro-lib/src/parse/delegate_and_check_components.rs index ba8e96eb..0c11087d 100644 --- a/crates/cgp-macro-lib/src/parse/delegate_and_check_components.rs +++ b/crates/cgp-macro-lib/src/parse/delegate_and_check_components.rs @@ -1,6 +1,7 @@ use core::iter; use cgp_macro_core::types::generics::ImplGenerics; +use cgp_macro_core::types::ident::IdentWithTypeArgs; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; @@ -8,7 +9,7 @@ use syn::spanned::Spanned; use syn::token::{Bracket, Comma, Lt, Pound}; use syn::{Attribute, Ident, Type, braced, bracketed, parse2}; -use crate::parse::{DelegateMode, DelegateValue, SimpleType}; +use crate::parse::{DelegateMode, DelegateValue}; pub struct DelegateAndCheckSpec { pub impl_generics: ImplGenerics, @@ -45,9 +46,9 @@ impl Parse for DelegateAndCheckSpec { let trait_name = match m_trait_name { Some(ident) => ident, None => { - let context_type: SimpleType = parse2(context_type.to_token_stream())?; + let context_type: IdentWithTypeArgs = parse2(context_type.to_token_stream())?; Ident::new( - &format!("__CanUse{}", context_type.name), + &format!("__CanUse{}", context_type.ident), context_type.span(), ) } diff --git a/crates/cgp-macro-lib/src/parse/delegate_components.rs b/crates/cgp-macro-lib/src/parse/delegate_components.rs index e3c25f4c..736aaf1d 100644 --- a/crates/cgp-macro-lib/src/parse/delegate_components.rs +++ b/crates/cgp-macro-lib/src/parse/delegate_components.rs @@ -2,6 +2,7 @@ use core::iter; use cgp_macro_core::functions::merge_generics; use cgp_macro_core::types::generics::{ImplGenerics, TypeGenerics}; +use cgp_macro_core::types::ident::IdentWithTypeArgs; use proc_macro2::TokenStream; use quote::{ToTokens, TokenStreamExt, quote}; use syn::parse::discouraged::Speculative; @@ -10,7 +11,7 @@ use syn::punctuated::Punctuated; use syn::token::{At, Bracket, Colon, Comma, Gt, Lt, RArrow}; use syn::{Error, Generics, Ident, Token, Type, braced, bracketed, parse_quote}; -use crate::parse::{ComponentPaths, SimpleType}; +use crate::parse::ComponentPaths; #[derive(Clone)] pub struct DelegateEntry { @@ -128,14 +129,14 @@ impl Parse for DelegateEntry { } } -impl Parse for DelegateEntry { +impl Parse for DelegateEntry { fn parse(input: ParseStream) -> syn::Result { let components = if input.peek(Bracket) { let components_body; bracketed!(components_body in input); components_body.parse_terminated(DelegateKey::parse, Token![,])? } else { - let component: DelegateKey = input.parse()?; + let component: DelegateKey = input.parse()?; Punctuated::from_iter(iter::once(component)) }; diff --git a/crates/cgp-macro-lib/src/parse/mod.rs b/crates/cgp-macro-lib/src/parse/mod.rs index 6dd0a2a2..3839cf99 100644 --- a/crates/cgp-macro-lib/src/parse/mod.rs +++ b/crates/cgp-macro-lib/src/parse/mod.rs @@ -6,7 +6,6 @@ mod delegate_components; mod entry; mod is_provider_params; mod path; -mod simple_type; mod type_spec; pub use check_components::*; @@ -17,5 +16,4 @@ pub use delegate_components::*; pub use entry::*; pub use is_provider_params::*; pub use path::*; -pub use simple_type::*; pub use type_spec::*; diff --git a/crates/cgp-macro-lib/src/parse/simple_type.rs b/crates/cgp-macro-lib/src/parse/simple_type.rs deleted file mode 100644 index c53460bc..00000000 --- a/crates/cgp-macro-lib/src/parse/simple_type.rs +++ /dev/null @@ -1,33 +0,0 @@ -use quote::ToTokens; -use syn::parse::{Parse, ParseStream}; -use syn::token::Lt; -use syn::{AngleBracketedGenericArguments, Ident}; - -#[derive(Clone)] -pub struct SimpleType { - pub name: Ident, - pub generics: Option, -} - -impl Parse for SimpleType -where - Generics: Parse, -{ - fn parse(input: ParseStream) -> syn::Result { - let name: Ident = input.parse()?; - let generics = if input.peek(Lt) { - Some(input.parse()?) - } else { - None - }; - - Ok(Self { name, generics }) - } -} - -impl ToTokens for SimpleType { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - self.name.to_tokens(tokens); - self.generics.to_tokens(tokens); - } -} diff --git a/crates/cgp-macro-lib/src/preset/impl_is_preset.rs b/crates/cgp-macro-lib/src/preset/impl_is_preset.rs index ec912b26..72336da1 100644 --- a/crates/cgp-macro-lib/src/preset/impl_is_preset.rs +++ b/crates/cgp-macro-lib/src/preset/impl_is_preset.rs @@ -1,17 +1,18 @@ use alloc::vec::Vec; use cgp_macro_core::types::generics::ImplGenerics; +use cgp_macro_core::types::ident::IdentWithTypeArgs; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{Ident, ItemImpl, Type, parse_quote}; -use crate::parse::{DelegateEntry, DelegateKey, SimpleType}; +use crate::parse::{DelegateEntry, DelegateKey}; pub fn impl_components_is_preset( trait_name: &Ident, preset_type: &Type, preset_generics: &ImplGenerics, - delegate_entries: &Punctuated, Comma>, + delegate_entries: &Punctuated, Comma>, ) -> Vec { delegate_entries .iter() @@ -27,7 +28,7 @@ pub fn impl_component_is_preset( trait_name: &Ident, _preset_type: &Type, _preset_generics: &ImplGenerics, - component: &DelegateKey, + component: &DelegateKey, ) -> ItemImpl { let component_type = &component.ty; From 01ea319f5f1909d09ccd1ff47a5e768ebf16a4a1 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sun, 31 May 2026 13:32:15 +0200 Subject: [PATCH 15/46] Move cgp_impl attributes --- .../src/types/attributes/impl_attributes.rs | 46 +++++++++++++++++++ .../src/types/attributes/mod.rs | 7 +++ .../src/types/attributes}/use_provider.rs | 7 +-- .../src/types/attributes}/use_type.rs | 9 ++-- .../cgp-macro-core/src/types/cgp_impl/mod.rs | 2 + .../src/types/cgp_impl/with_parsed_attrs.rs | 8 ++++ crates/cgp-macro-core/src/types/mod.rs | 1 + crates/cgp-macro-lib/src/cgp_fn/apply_type.rs | 5 +- crates/cgp-macro-lib/src/cgp_fn/attributes.rs | 8 ++-- crates/cgp-macro-lib/src/cgp_fn/item_trait.rs | 5 +- crates/cgp-macro-lib/src/cgp_fn/mod.rs | 2 - crates/cgp-macro-lib/src/cgp_fn/spec.rs | 7 ++- .../src/cgp_fn/substitute_type.rs | 10 ++-- .../src/cgp_fn/type_predicates.rs | 19 ++++---- .../cgp-macro-lib/src/cgp_impl/attributes.rs | 46 ------------------- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 5 +- crates/cgp-macro-lib/src/cgp_impl/mod.rs | 3 -- .../src/cgp_impl/provider_bounds.rs | 5 +- .../src/derive_component/attributes.rs | 6 +-- 19 files changed, 109 insertions(+), 92 deletions(-) create mode 100644 crates/cgp-macro-core/src/types/attributes/impl_attributes.rs create mode 100644 crates/cgp-macro-core/src/types/attributes/mod.rs rename crates/{cgp-macro-lib/src/cgp_impl => cgp-macro-core/src/types/attributes}/use_provider.rs (84%) rename crates/{cgp-macro-lib/src/cgp_fn => cgp-macro-core/src/types/attributes}/use_type.rs (95%) create mode 100644 crates/cgp-macro-core/src/types/cgp_impl/with_parsed_attrs.rs delete mode 100644 crates/cgp-macro-lib/src/cgp_impl/attributes.rs diff --git a/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs b/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs new file mode 100644 index 00000000..6e0b9633 --- /dev/null +++ b/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs @@ -0,0 +1,46 @@ +use syn::Attribute; +use syn::punctuated::Punctuated; +use syn::token::Comma; + +use crate::types::attributes::{UseProviderAttribute, UseTypeAttribute}; +use crate::types::ident::IdentWithTypeArgs; + +#[derive(Default)] +pub struct ImplAttributes { + pub uses: Vec, + pub use_type: Vec, + pub use_provider: Vec, + pub raw_attributes: Vec, +} + +impl ImplAttributes { + pub fn parse(attributes: &Vec) -> syn::Result { + let mut parsed_attributes = ImplAttributes::default(); + + for attribute in attributes { + if let Some(ident) = attribute.path().get_ident() { + if ident == "uses" { + let uses = attribute.parse_args_with( + Punctuated::::parse_terminated, + )?; + parsed_attributes.uses.extend(uses); + } else if ident == "use_type" { + let use_type = attribute + .parse_args_with(Punctuated::::parse_terminated)?; + parsed_attributes.use_type.extend(use_type); + } else if ident == "use_provider" { + let use_provider = attribute.parse_args_with( + Punctuated::::parse_terminated, + )?; + parsed_attributes.use_provider.extend(use_provider); + } else { + parsed_attributes.raw_attributes.push(attribute.clone()); + } + } else { + parsed_attributes.raw_attributes.push(attribute.clone()); + } + } + + Ok(parsed_attributes) + } +} diff --git a/crates/cgp-macro-core/src/types/attributes/mod.rs b/crates/cgp-macro-core/src/types/attributes/mod.rs new file mode 100644 index 00000000..f1d9447d --- /dev/null +++ b/crates/cgp-macro-core/src/types/attributes/mod.rs @@ -0,0 +1,7 @@ +mod impl_attributes; +mod use_provider; +mod use_type; + +pub use impl_attributes::*; +pub use use_provider::*; +pub use use_type::*; diff --git a/crates/cgp-macro-lib/src/cgp_impl/use_provider.rs b/crates/cgp-macro-core/src/types/attributes/use_provider.rs similarity index 84% rename from crates/cgp-macro-lib/src/cgp_impl/use_provider.rs rename to crates/cgp-macro-core/src/types/attributes/use_provider.rs index b0c81047..628aa81c 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/use_provider.rs +++ b/crates/cgp-macro-core/src/types/attributes/use_provider.rs @@ -1,16 +1,17 @@ -use cgp_macro_core::types::ident::IdentWithTypeArgs; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::token::{Colon, Plus}; use syn::{Type, parse_quote}; -pub struct UseProviderSpec { +use crate::types::ident::IdentWithTypeArgs; + +pub struct UseProviderAttribute { pub context_type: Type, pub provider_type: Type, pub provider_trait_bounds: Punctuated, } -impl Parse for UseProviderSpec { +impl Parse for UseProviderAttribute { fn parse(input: ParseStream) -> syn::Result { let context_type = parse_quote!(Self); let provider_type = input.parse()?; diff --git a/crates/cgp-macro-lib/src/cgp_fn/use_type.rs b/crates/cgp-macro-core/src/types/attributes/use_type.rs similarity index 95% rename from crates/cgp-macro-lib/src/cgp_fn/use_type.rs rename to crates/cgp-macro-core/src/types/attributes/use_type.rs index ff0bf132..250ca7aa 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/use_type.rs +++ b/crates/cgp-macro-core/src/types/attributes/use_type.rs @@ -1,9 +1,10 @@ -use cgp_macro_core::types::ident::IdentWithTypeArgs; use syn::parse::{Parse, ParseStream}; use syn::token::{As, At, Brace, Colon, Comma, Eq, Gt, Lt}; use syn::{Ident, Type, braced, parse_quote}; -pub struct UseTypeSpec { +use crate::types::ident::IdentWithTypeArgs; + +pub struct UseTypeAttribute { pub context_type: Type, pub trait_path: IdentWithTypeArgs, pub type_idents: Vec, @@ -15,7 +16,7 @@ pub struct UseTypeIdent { pub equals: Option, } -impl UseTypeSpec { +impl UseTypeAttribute { pub fn replace_ident(&self, ident: &Ident) -> Option { for type_ident in &self.type_idents { if type_ident.alias_ident() == ident { @@ -35,7 +36,7 @@ impl UseTypeIdent { } } -impl Parse for UseTypeSpec { +impl Parse for UseTypeAttribute { fn parse(input: ParseStream) -> syn::Result { let body; diff --git a/crates/cgp-macro-core/src/types/cgp_impl/mod.rs b/crates/cgp-macro-core/src/types/cgp_impl/mod.rs index d05a74f5..9c71de25 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/mod.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/mod.rs @@ -1,5 +1,7 @@ mod args; mod item; +mod with_parsed_attrs; pub use args::*; pub use item::*; +pub use with_parsed_attrs::*; diff --git a/crates/cgp-macro-core/src/types/cgp_impl/with_parsed_attrs.rs b/crates/cgp-macro-core/src/types/cgp_impl/with_parsed_attrs.rs new file mode 100644 index 00000000..a2e201b2 --- /dev/null +++ b/crates/cgp-macro-core/src/types/cgp_impl/with_parsed_attrs.rs @@ -0,0 +1,8 @@ +use syn::ItemImpl; + +use crate::types::cgp_impl::ImplArgs; + +pub struct CgpImplWithParsedAttributes { + pub args: ImplArgs, + pub item_impl: ItemImpl, +} diff --git a/crates/cgp-macro-core/src/types/mod.rs b/crates/cgp-macro-core/src/types/mod.rs index 4674579e..4a44f6f7 100644 --- a/crates/cgp-macro-core/src/types/mod.rs +++ b/crates/cgp-macro-core/src/types/mod.rs @@ -1,3 +1,4 @@ +pub mod attributes; pub mod cgp_impl; pub mod cgp_provider; pub mod delegate_component; diff --git a/crates/cgp-macro-lib/src/cgp_fn/apply_type.rs b/crates/cgp-macro-lib/src/cgp_fn/apply_type.rs index d958f69a..7b9812a9 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/apply_type.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/apply_type.rs @@ -1,11 +1,12 @@ +use cgp_macro_core::types::attributes::UseTypeAttribute; use quote::ToTokens; use syn::{ItemImpl, parse2}; -use crate::cgp_fn::{UseTypeSpec, derive_use_type_predicates, substitute_abstract_types}; +use crate::cgp_fn::{derive_use_type_predicates, substitute_abstract_types}; pub fn apply_use_type_attributes_to_item_impl( item_impl: &ItemImpl, - use_type_specs: &[UseTypeSpec], + use_type_specs: &[UseTypeAttribute], ) -> syn::Result { let mut item_impl: ItemImpl = parse2(substitute_abstract_types( use_type_specs, diff --git a/crates/cgp-macro-lib/src/cgp_fn/attributes.rs b/crates/cgp-macro-lib/src/cgp_fn/attributes.rs index c341e8ca..b6b52e4d 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/attributes.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/attributes.rs @@ -1,10 +1,10 @@ +use cgp_macro_core::types::attributes::{UseProviderAttribute, UseTypeAttribute}; use cgp_macro_core::types::ident::IdentWithTypeArgs; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{Attribute, GenericParam, TypeParamBound, WherePredicate}; -use crate::cgp_fn::{FunctionAttributes, UseTypeSpec}; -use crate::cgp_impl::UseProviderSpec; +use crate::cgp_fn::FunctionAttributes; pub fn parse_function_attributes( attributes: Vec, @@ -31,12 +31,12 @@ pub fn parse_function_attributes( parsed_attributes.uses.extend(uses); } else if ident == "use_type" { let use_type = attribute - .parse_args_with(Punctuated::::parse_terminated)?; + .parse_args_with(Punctuated::::parse_terminated)?; parsed_attributes.use_type.extend(use_type); } else if ident == "use_provider" { let use_provider = attribute - .parse_args_with(Punctuated::::parse_terminated)?; + .parse_args_with(Punctuated::::parse_terminated)?; parsed_attributes.use_provider.extend(use_provider); } else if ident == "impl_generics" { diff --git a/crates/cgp-macro-lib/src/cgp_fn/item_trait.rs b/crates/cgp-macro-lib/src/cgp_fn/item_trait.rs index eb953910..291e2d0b 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_trait.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_trait.rs @@ -1,7 +1,8 @@ +use cgp_macro_core::types::attributes::UseTypeAttribute; use quote::{ToTokens, quote}; use syn::{Generics, Ident, ItemFn, ItemTrait, TraitItemFn, parse_quote, parse2}; -use crate::cgp_fn::{FunctionAttributes, UseTypeSpec, substitute_abstract_types}; +use crate::cgp_fn::{FunctionAttributes, substitute_abstract_types}; pub fn derive_item_trait( trait_ident: &Ident, @@ -44,7 +45,7 @@ pub fn derive_item_trait( pub fn expand_use_type_attributes_on_trait( item_trait: &ItemTrait, - use_type_specs: &[UseTypeSpec], + use_type_specs: &[UseTypeAttribute], ) -> syn::Result { let mut item_trait: ItemTrait = parse2(substitute_abstract_types( use_type_specs, diff --git a/crates/cgp-macro-lib/src/cgp_fn/mod.rs b/crates/cgp-macro-lib/src/cgp_fn/mod.rs index 6845f094..0c5e3966 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/mod.rs @@ -9,7 +9,6 @@ mod parse_implicits; mod spec; mod substitute_type; mod type_predicates; -mod use_type; pub use apply_type::*; pub use attributes::*; @@ -21,4 +20,3 @@ pub use parse_implicits::*; pub use spec::*; pub use substitute_type::*; pub use type_predicates::*; -pub use use_type::*; diff --git a/crates/cgp-macro-lib/src/cgp_fn/spec.rs b/crates/cgp-macro-lib/src/cgp_fn/spec.rs index 9b66afae..0522fef2 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/spec.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/spec.rs @@ -1,9 +1,8 @@ +use cgp_macro_core::types::attributes::{UseProviderAttribute, UseTypeAttribute}; use cgp_macro_core::types::ident::IdentWithTypeArgs; use syn::token::Mut; use syn::{GenericParam, Ident, Type, TypeParamBound, WherePredicate}; -use crate::cgp_fn::UseTypeSpec; -use crate::cgp_impl::UseProviderSpec; use crate::derive_getter::FieldMode; #[derive(Clone, Eq, PartialEq)] @@ -20,7 +19,7 @@ pub struct FunctionAttributes { pub extend: Vec, pub extend_where: Vec, pub uses: Vec, - pub use_type: Vec, - pub use_provider: Vec, + pub use_type: Vec, + pub use_provider: Vec, pub impl_generics: Vec, } diff --git a/crates/cgp-macro-lib/src/cgp_fn/substitute_type.rs b/crates/cgp-macro-lib/src/cgp_fn/substitute_type.rs index 5e3214a5..ec28b696 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/substitute_type.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/substitute_type.rs @@ -1,9 +1,11 @@ +use cgp_macro_core::types::attributes::UseTypeAttribute; use proc_macro2::{Group, TokenStream, TokenTree}; use quote::quote; -use crate::cgp_fn::UseTypeSpec; - -pub fn substitute_abstract_types(type_specs: &[UseTypeSpec], body: TokenStream) -> TokenStream { +pub fn substitute_abstract_types( + type_specs: &[UseTypeAttribute], + body: TokenStream, +) -> TokenStream { let mut out = body; for spec in type_specs.iter().rev() { out = substitute_abstract_type(spec, out); @@ -11,7 +13,7 @@ pub fn substitute_abstract_types(type_specs: &[UseTypeSpec], body: TokenStream) out } -pub fn substitute_abstract_type(type_specs: &UseTypeSpec, body: TokenStream) -> TokenStream { +pub fn substitute_abstract_type(type_specs: &UseTypeAttribute, body: TokenStream) -> TokenStream { let mut out = TokenStream::new(); let mut last_token_was_colon = false; let mut last_two_tokens_was_colon = false; diff --git a/crates/cgp-macro-lib/src/cgp_fn/type_predicates.rs b/crates/cgp-macro-lib/src/cgp_fn/type_predicates.rs index 5dd9c7e7..13b5d718 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/type_predicates.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/type_predicates.rs @@ -1,12 +1,11 @@ +use cgp_macro_core::types::attributes::{UseTypeAttribute, UseTypeIdent}; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{Ident, Type, WherePredicate, parse_quote, parse2}; -use crate::cgp_fn::{UseTypeIdent, UseTypeSpec}; - -pub fn derive_use_type_predicates(specs: &[UseTypeSpec]) -> syn::Result> { +pub fn derive_use_type_predicates(specs: &[UseTypeAttribute]) -> syn::Result> { let mut predicates = Vec::new(); for use_type in specs.iter() { @@ -43,7 +42,7 @@ pub fn derive_use_type_predicates(specs: &[UseTypeSpec]) -> syn::Result syn::Result> { +fn find_type_alias(specs: &[UseTypeAttribute], context_type: &Type) -> syn::Result> { let Ok(context_ident) = parse2::(context_type.to_token_stream()) else { return Ok(None); }; @@ -68,8 +67,8 @@ fn find_type_alias(specs: &[UseTypeSpec], context_type: &Type) -> syn::Result syn::Result> { let mut equalities = Vec::new(); @@ -86,8 +85,8 @@ pub fn find_type_equalities( fn forbid_same_alias( current_ident: &UseTypeIdent, - current_spec: &UseTypeSpec, - specs: &[UseTypeSpec], + current_spec: &UseTypeAttribute, + specs: &[UseTypeAttribute], ) -> syn::Result<()> { for spec in specs.iter() { if core::ptr::eq(spec, current_spec) { @@ -110,8 +109,8 @@ fn forbid_same_alias( fn find_type_equality( current_ident: &UseTypeIdent, - current_spec: &UseTypeSpec, - specs: &[UseTypeSpec], + current_spec: &UseTypeAttribute, + specs: &[UseTypeAttribute], ) -> syn::Result> { if let Some(equal_target) = current_ident.equals.clone() { for spec in specs.iter() { diff --git a/crates/cgp-macro-lib/src/cgp_impl/attributes.rs b/crates/cgp-macro-lib/src/cgp_impl/attributes.rs deleted file mode 100644 index 35128b27..00000000 --- a/crates/cgp-macro-lib/src/cgp_impl/attributes.rs +++ /dev/null @@ -1,46 +0,0 @@ -use core::mem; - -use cgp_macro_core::types::ident::IdentWithTypeArgs; -use syn::Attribute; -use syn::punctuated::Punctuated; -use syn::token::Comma; - -use crate::cgp_fn::UseTypeSpec; -use crate::cgp_impl::use_provider::UseProviderSpec; - -pub fn parse_impl_attributes(attributes: &mut Vec) -> syn::Result { - let mut parsed_attributes = ImplAttributes::default(); - - let in_attributes = mem::take(attributes); - - for attribute in in_attributes.into_iter() { - if let Some(ident) = attribute.path().get_ident() { - if ident == "uses" { - let uses = attribute - .parse_args_with(Punctuated::::parse_terminated)?; - parsed_attributes.uses.extend(uses); - } else if ident == "use_type" { - let use_type = attribute - .parse_args_with(Punctuated::::parse_terminated)?; - parsed_attributes.use_type.extend(use_type); - } else if ident == "use_provider" { - let use_provider = attribute - .parse_args_with(Punctuated::::parse_terminated)?; - parsed_attributes.use_provider.extend(use_provider); - } else { - attributes.push(attribute); - } - } else { - attributes.push(attribute); - } - } - - Ok(parsed_attributes) -} - -#[derive(Default)] -pub struct ImplAttributes { - pub uses: Vec, - pub use_type: Vec, - pub use_provider: Vec, -} diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index 865e79f5..d6cc58ce 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -1,3 +1,4 @@ +use cgp_macro_core::types::attributes::ImplAttributes; use cgp_macro_core::types::cgp_impl::ImplArgs; use proc_macro2::TokenStream; use quote::quote; @@ -7,7 +8,6 @@ use syn::token::Plus; use syn::{Error, ItemImpl, TypeParamBound, parse_quote, parse2}; use crate::cgp_fn::{apply_use_type_attributes_to_item_impl, build_implicit_args_bounds}; -use crate::cgp_impl::attributes::parse_impl_attributes; use crate::cgp_impl::provider_bounds::derive_provider_bounds; use crate::cgp_impl::{derive_provider_impl, implicit_args}; use crate::derive_provider::{ @@ -15,7 +15,8 @@ use crate::derive_provider::{ }; pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result { - let attributes = parse_impl_attributes(&mut item_impl.attrs)?; + let attributes = ImplAttributes::parse(&mut item_impl.attrs)?; + item_impl.attrs = attributes.raw_attributes; let implicit_args = implicit_args::extract_implicit_args_from_impl_items(&mut item_impl.items)?; diff --git a/crates/cgp-macro-lib/src/cgp_impl/mod.rs b/crates/cgp-macro-lib/src/cgp_impl/mod.rs index b0e2e102..a83db139 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/mod.rs @@ -1,13 +1,10 @@ -mod attributes; mod derive; mod implicit_args; mod provider_bounds; mod provider_impl; mod transform; -mod use_provider; pub use derive::*; pub use provider_bounds::*; pub use provider_impl::*; pub use transform::*; -pub use use_provider::*; diff --git a/crates/cgp-macro-lib/src/cgp_impl/provider_bounds.rs b/crates/cgp-macro-lib/src/cgp_impl/provider_bounds.rs index 94a8e870..95011bb1 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/provider_bounds.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/provider_bounds.rs @@ -1,13 +1,12 @@ +use cgp_macro_core::types::attributes::UseProviderAttribute; use quote::quote; use syn::punctuated::Punctuated; use syn::token::Plus; use syn::{Type, TypeParamBound, WherePredicate, parse_quote, parse2}; -use crate::cgp_impl::use_provider::UseProviderSpec; - pub fn derive_provider_bounds( context_type: &Type, - spec: &UseProviderSpec, + spec: &UseProviderAttribute, ) -> syn::Result { let context_type = if spec.context_type == parse_quote! { Self } { context_type diff --git a/crates/cgp-macro-lib/src/derive_component/attributes.rs b/crates/cgp-macro-lib/src/derive_component/attributes.rs index 13d2a8f3..895468d2 100644 --- a/crates/cgp-macro-lib/src/derive_component/attributes.rs +++ b/crates/cgp-macro-lib/src/derive_component/attributes.rs @@ -1,12 +1,12 @@ use core::mem; +use cgp_macro_core::types::attributes::UseTypeAttribute; use syn::parse::Parse; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{Attribute, TypeParamBound}; use crate::attributes::UseNamespaceAttribute; -use crate::cgp_fn::UseTypeSpec; pub fn parse_component_attributes( attributes: &mut Vec, @@ -23,7 +23,7 @@ pub fn parse_component_attributes( parsed_attributes.extend.extend(extend_bound); } else if ident == "use_type" { let use_type_specs = attribute - .parse_args_with(Punctuated::::parse_terminated)?; + .parse_args_with(Punctuated::::parse_terminated)?; for use_type_spec in use_type_specs.iter() { for type_ident in use_type_spec.type_idents.iter() { @@ -54,6 +54,6 @@ pub fn parse_component_attributes( #[derive(Default)] pub struct ComponentAttributes { pub extend: Vec, - pub use_type: Vec, + pub use_type: Vec, pub namespace: Vec, } From f60428c6595ca82d1127b005ff58ca67b1a07789 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sun, 31 May 2026 14:31:05 +0200 Subject: [PATCH 16/46] More refactoring --- crates/cgp-macro-core/src/exports.rs | 1 + .../src/types/attributes/impl_attributes.rs | 43 +++++++------ .../src/types/attributes/use_provider.rs | 4 +- .../cgp-macro-core/src/types/cgp_impl/item.rs | 14 ++++- .../src/types/field/field_name.rs | 30 ++++++++++ .../cgp-macro-core/src/types/field/index.rs | 20 +++++++ crates/cgp-macro-core/src/types/field/mod.rs | 7 +++ .../src/types/{ => field}/symbol.rs | 0 .../src/types/getter/field_mode.rs | 9 +++ .../src/types/getter/get_field_expr.rs | 31 ++++++++++ .../types/getter/get_field_with_mode_expr.rs | 60 +++++++++++++++++++ crates/cgp-macro-core/src/types/getter/mod.rs | 7 +++ .../src/types/implicits/arg_field.rs | 13 ++++ .../src/types/implicits/arg_fields.rs | 5 ++ .../cgp-macro-core/src/types/implicits/mod.rs | 5 ++ crates/cgp-macro-core/src/types/mod.rs | 4 +- .../src/types/path/path_element.rs | 4 +- crates/cgp-macro-lib/src/cgp_fn/bounds.rs | 2 +- crates/cgp-macro-lib/src/cgp_fn/fn_body.rs | 7 ++- crates/cgp-macro-lib/src/cgp_fn/item_impl.rs | 4 +- .../src/cgp_fn/parse_implicits.rs | 2 +- crates/cgp-macro-lib/src/cgp_fn/spec.rs | 14 +---- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 7 ++- .../src/cgp_impl/implicit_args.rs | 3 +- .../src/derive_getter/constraint.rs | 3 +- .../src/derive_getter/getter_field.rs | 11 +--- .../cgp-macro-lib/src/derive_getter/method.rs | 3 +- .../cgp-macro-lib/src/derive_getter/parse.rs | 3 +- .../src/derive_getter/with_provider.rs | 3 +- 29 files changed, 258 insertions(+), 61 deletions(-) create mode 100644 crates/cgp-macro-core/src/types/field/field_name.rs create mode 100644 crates/cgp-macro-core/src/types/field/index.rs create mode 100644 crates/cgp-macro-core/src/types/field/mod.rs rename crates/cgp-macro-core/src/types/{ => field}/symbol.rs (100%) create mode 100644 crates/cgp-macro-core/src/types/getter/field_mode.rs create mode 100644 crates/cgp-macro-core/src/types/getter/get_field_expr.rs create mode 100644 crates/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs create mode 100644 crates/cgp-macro-core/src/types/getter/mod.rs create mode 100644 crates/cgp-macro-core/src/types/implicits/arg_field.rs create mode 100644 crates/cgp-macro-core/src/types/implicits/arg_fields.rs create mode 100644 crates/cgp-macro-core/src/types/implicits/mod.rs diff --git a/crates/cgp-macro-core/src/exports.rs b/crates/cgp-macro-core/src/exports.rs index 36841735..9a69a1ad 100644 --- a/crates/cgp-macro-core/src/exports.rs +++ b/crates/cgp-macro-core/src/exports.rs @@ -5,6 +5,7 @@ export_constructs! { Cons, Chars, Symbol, + Index, PathCons, RedirectLookup, DelegateComponent, diff --git a/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs b/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs index 6e0b9633..22d5c971 100644 --- a/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs +++ b/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs @@ -19,23 +19,32 @@ impl ImplAttributes { for attribute in attributes { if let Some(ident) = attribute.path().get_ident() { - if ident == "uses" { - let uses = attribute.parse_args_with( - Punctuated::::parse_terminated, - )?; - parsed_attributes.uses.extend(uses); - } else if ident == "use_type" { - let use_type = attribute - .parse_args_with(Punctuated::::parse_terminated)?; - parsed_attributes.use_type.extend(use_type); - } else if ident == "use_provider" { - let use_provider = attribute.parse_args_with( - Punctuated::::parse_terminated, - )?; - parsed_attributes.use_provider.extend(use_provider); - } else { - parsed_attributes.raw_attributes.push(attribute.clone()); - } + match ident.to_string().as_ref() { + "uses" => { + let uses = attribute.parse_args_with( + Punctuated::::parse_terminated, + )?; + + parsed_attributes.uses.extend(uses); + } + "use_type" => { + let use_type = attribute.parse_args_with( + Punctuated::::parse_terminated, + )?; + + parsed_attributes.use_type.extend(use_type); + } + "use_provider" => { + let use_provider = attribute.parse_args_with( + Punctuated::::parse_terminated, + )?; + + parsed_attributes.use_provider.extend(use_provider); + } + _ => { + parsed_attributes.raw_attributes.push(attribute.clone()); + } + }; } else { parsed_attributes.raw_attributes.push(attribute.clone()); } diff --git a/crates/cgp-macro-core/src/types/attributes/use_provider.rs b/crates/cgp-macro-core/src/types/attributes/use_provider.rs index 628aa81c..95b8fa16 100644 --- a/crates/cgp-macro-core/src/types/attributes/use_provider.rs +++ b/crates/cgp-macro-core/src/types/attributes/use_provider.rs @@ -8,6 +8,7 @@ use crate::types::ident::IdentWithTypeArgs; pub struct UseProviderAttribute { pub context_type: Type, pub provider_type: Type, + pub colon: Colon, pub provider_trait_bounds: Punctuated, } @@ -16,12 +17,13 @@ impl Parse for UseProviderAttribute { let context_type = parse_quote!(Self); let provider_type = input.parse()?; - let _: Colon = input.parse()?; + let colon: Colon = input.parse()?; let provider_trait_bounds = Punctuated::parse_terminated(input)?; Ok(Self { context_type, provider_type, + colon, provider_trait_bounds, }) } diff --git a/crates/cgp-macro-core/src/types/cgp_impl/item.rs b/crates/cgp-macro-core/src/types/cgp_impl/item.rs index 08c6c660..32d3493b 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/item.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/item.rs @@ -1,8 +1,20 @@ use syn::ItemImpl; -use crate::types::cgp_impl::ImplArgs; +use crate::types::attributes::ImplAttributes; +use crate::types::cgp_impl::{CgpImplWithParsedAttributes, ImplArgs}; pub struct ItemCgpImpl { pub args: ImplArgs, pub item_impl: ItemImpl, } + +impl ItemCgpImpl { + pub fn lower(&self) -> syn::Result { + let mut item_impl = self.item_impl.clone(); + + let attributes = ImplAttributes::parse(&item_impl.attrs)?; + item_impl.attrs = attributes.raw_attributes; + + todo!() + } +} diff --git a/crates/cgp-macro-core/src/types/field/field_name.rs b/crates/cgp-macro-core/src/types/field/field_name.rs new file mode 100644 index 00000000..c4418fb8 --- /dev/null +++ b/crates/cgp-macro-core/src/types/field/field_name.rs @@ -0,0 +1,30 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; + +use crate::types::field::{Index, Symbol}; + +pub enum FieldName { + Ident(Symbol), + Index(Index), +} + +impl From for FieldName { + fn from(value: Symbol) -> Self { + Self::Ident(value) + } +} + +impl From for FieldName { + fn from(value: Index) -> Self { + Self::Index(value) + } +} + +impl ToTokens for FieldName { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Ident(symbol) => symbol.to_tokens(tokens), + Self::Index(index) => index.to_tokens(tokens), + } + } +} diff --git a/crates/cgp-macro-core/src/types/field/index.rs b/crates/cgp-macro-core/src/types/field/index.rs new file mode 100644 index 00000000..d5b4b187 --- /dev/null +++ b/crates/cgp-macro-core/src/types/field/index.rs @@ -0,0 +1,20 @@ +use proc_macro2::{Span, TokenStream}; +use quote::{ToTokens, quote}; +use syn::LitInt; + +use crate::exports::Index as Delta; + +pub struct Index { + pub index: usize, + pub span: Span, +} + +impl ToTokens for Index { + fn to_tokens(&self, tokens: &mut TokenStream) { + let index = LitInt::new(&self.index.to_string(), self.span); + + tokens.extend(quote! { + #Delta<#index> + }); + } +} diff --git a/crates/cgp-macro-core/src/types/field/mod.rs b/crates/cgp-macro-core/src/types/field/mod.rs new file mode 100644 index 00000000..bc01f09a --- /dev/null +++ b/crates/cgp-macro-core/src/types/field/mod.rs @@ -0,0 +1,7 @@ +mod field_name; +mod index; +mod symbol; + +pub use field_name::*; +pub use index::*; +pub use symbol::*; diff --git a/crates/cgp-macro-core/src/types/symbol.rs b/crates/cgp-macro-core/src/types/field/symbol.rs similarity index 100% rename from crates/cgp-macro-core/src/types/symbol.rs rename to crates/cgp-macro-core/src/types/field/symbol.rs diff --git a/crates/cgp-macro-core/src/types/getter/field_mode.rs b/crates/cgp-macro-core/src/types/getter/field_mode.rs new file mode 100644 index 00000000..f2fdaa1a --- /dev/null +++ b/crates/cgp-macro-core/src/types/getter/field_mode.rs @@ -0,0 +1,9 @@ +#[derive(Clone, Eq, PartialEq)] +pub enum FieldMode { + Reference, + OptionRef, + MRef, + Str, + Copy, + Slice, +} diff --git a/crates/cgp-macro-core/src/types/getter/get_field_expr.rs b/crates/cgp-macro-core/src/types/getter/get_field_expr.rs new file mode 100644 index 00000000..97a6e3b8 --- /dev/null +++ b/crates/cgp-macro-core/src/types/getter/get_field_expr.rs @@ -0,0 +1,31 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, quote}; +use syn::Expr; +use syn::token::Mut; + +use crate::types::field::FieldName; + +pub struct GetFieldExpr { + pub receiver: Expr, + pub field_mut: Option, + pub field_name: FieldName, +} + +impl ToTokens for GetFieldExpr { + fn to_tokens(&self, tokens: &mut TokenStream) { + let receiver = &self.receiver; + let field_name = &self.field_name; + + let method = if self.field_mut.is_none() { + quote!(get_field) + } else { + quote!(get_field_mut) + }; + + tokens.extend(quote! { + #receiver.#method( + ::core::marker::PhantomData::<#field_name> + ) + }) + } +} diff --git a/crates/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs b/crates/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs new file mode 100644 index 00000000..3eb02e31 --- /dev/null +++ b/crates/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs @@ -0,0 +1,60 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, quote}; + +use crate::types::getter::{FieldMode, GetFieldExpr}; + +pub struct GetFieldWithModeExpr { + pub get_field: GetFieldExpr, + pub field_mode: FieldMode, +} + +impl ToTokens for GetFieldWithModeExpr { + fn to_tokens(&self, tokens: &mut TokenStream) { + let call_expr = &self.get_field; + + let expr = match self.field_mode { + FieldMode::Reference => { + quote!(#call_expr) + } + FieldMode::OptionRef => { + if call_expr.field_mut.is_none() { + quote! { + #call_expr .as_ref() + } + } else { + quote! { + #call_expr .as_mut() + } + } + } + FieldMode::MRef => { + quote! { + MRef::Ref( #call_expr ) + } + } + FieldMode::Str => { + if call_expr.field_mut.is_none() { + quote! { + #call_expr .as_str() + } + } else { + quote! { + #call_expr .as_mut_str() + } + } + } + FieldMode::Copy => { + quote! { + #call_expr .clone() + } + } + FieldMode::Slice => { + quote! { + #call_expr .as_ref() + } + } + }; + + tokens.extend(expr); + } +} diff --git a/crates/cgp-macro-core/src/types/getter/mod.rs b/crates/cgp-macro-core/src/types/getter/mod.rs new file mode 100644 index 00000000..5d40e8a8 --- /dev/null +++ b/crates/cgp-macro-core/src/types/getter/mod.rs @@ -0,0 +1,7 @@ +mod field_mode; +mod get_field_expr; +mod get_field_with_mode_expr; + +pub use field_mode::*; +pub use get_field_expr::*; +pub use get_field_with_mode_expr::*; diff --git a/crates/cgp-macro-core/src/types/implicits/arg_field.rs b/crates/cgp-macro-core/src/types/implicits/arg_field.rs new file mode 100644 index 00000000..04432720 --- /dev/null +++ b/crates/cgp-macro-core/src/types/implicits/arg_field.rs @@ -0,0 +1,13 @@ +use syn::token::Mut; +use syn::{Ident, Type}; + +use crate::types::getter::FieldMode; + +#[derive(Clone, Eq, PartialEq)] +pub struct ImplicitArgField { + pub field_name: Ident, + pub field_type: Type, + pub field_mut: Option, + pub field_mode: FieldMode, + pub arg_type: Type, +} diff --git a/crates/cgp-macro-core/src/types/implicits/arg_fields.rs b/crates/cgp-macro-core/src/types/implicits/arg_fields.rs new file mode 100644 index 00000000..62aa8205 --- /dev/null +++ b/crates/cgp-macro-core/src/types/implicits/arg_fields.rs @@ -0,0 +1,5 @@ +use crate::types::implicits::ImplicitArgField; + +pub struct ImplicitArgFields { + pub fields: Vec, +} diff --git a/crates/cgp-macro-core/src/types/implicits/mod.rs b/crates/cgp-macro-core/src/types/implicits/mod.rs new file mode 100644 index 00000000..4564e970 --- /dev/null +++ b/crates/cgp-macro-core/src/types/implicits/mod.rs @@ -0,0 +1,5 @@ +mod arg_field; +mod arg_fields; + +pub use arg_field::*; +pub use arg_fields::*; diff --git a/crates/cgp-macro-core/src/types/mod.rs b/crates/cgp-macro-core/src/types/mod.rs index 4a44f6f7..652db583 100644 --- a/crates/cgp-macro-core/src/types/mod.rs +++ b/crates/cgp-macro-core/src/types/mod.rs @@ -2,11 +2,13 @@ pub mod attributes; pub mod cgp_impl; pub mod cgp_provider; pub mod delegate_component; +pub mod field; pub mod generics; +pub mod getter; pub mod ident; +pub mod implicits; pub mod keyword; pub mod keywords; pub mod namespace; pub mod path; pub mod provider_struct; -pub mod symbol; diff --git a/crates/cgp-macro-core/src/types/path/path_element.rs b/crates/cgp-macro-core/src/types/path/path_element.rs index 2e5d8afc..75936d08 100644 --- a/crates/cgp-macro-core/src/types/path/path_element.rs +++ b/crates/cgp-macro-core/src/types/path/path_element.rs @@ -4,7 +4,7 @@ use syn::parse::{Parse, ParseStream}; use syn::{Ident, Type, parse2}; use crate::traits::ToType; -use crate::types::symbol::Symbol; +use crate::types::field::Symbol; #[derive(Debug, Clone)] pub enum PathElement { @@ -23,7 +23,7 @@ impl Parse for PathElement { && path_char.is_ascii_lowercase() && !is_primitive_type(&path_str) { - Self::Symbol(Symbol { ident: path_ident }) + Self::Symbol(Symbol::new(path_ident)) } else { Self::Type(ty) } diff --git a/crates/cgp-macro-lib/src/cgp_fn/bounds.rs b/crates/cgp-macro-lib/src/cgp_fn/bounds.rs index 17b90993..6c4f7f35 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/bounds.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/bounds.rs @@ -1,9 +1,9 @@ +use cgp_macro_core::types::implicits::ImplicitArgField; use quote::ToTokens; use syn::TypeParamBound; use syn::punctuated::Punctuated; use syn::token::Plus; -use crate::cgp_fn::ImplicitArgField; use crate::derive_getter::derive_getter_constraint; use crate::symbol::symbol_from_string; diff --git a/crates/cgp-macro-lib/src/cgp_fn/fn_body.rs b/crates/cgp-macro-lib/src/cgp_fn/fn_body.rs index 20684e17..4ecee587 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/fn_body.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/fn_body.rs @@ -1,14 +1,15 @@ +use cgp_macro_core::types::field::Symbol; +use cgp_macro_core::types::implicits::ImplicitArgField; use quote::quote; use syn::{Block, parse2}; -use crate::cgp_fn::ImplicitArgField; use crate::derive_getter::extend_call_expr; -use crate::symbol::symbol_from_string; pub fn inject_implicit_args(args: &[ImplicitArgField], body: &mut Block) -> syn::Result<()> { for arg in args.iter().rev() { inject_implicit_arg(arg, body)?; } + Ok(()) } @@ -16,7 +17,7 @@ pub fn inject_implicit_arg(arg: &ImplicitArgField, body: &mut Block) -> syn::Res let field_name = &arg.field_name; let arg_type = &arg.arg_type; - let field_symbol = symbol_from_string(&field_name.to_string())?; + let field_symbol = Symbol::new(field_name.clone()); let call_expr = if arg.field_mut.is_none() { quote! { diff --git a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs index d17b80f0..b1adf82e 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs @@ -1,11 +1,11 @@ +use cgp_macro_core::types::implicits::ImplicitArgField; use quote::quote; use syn::punctuated::Punctuated; use syn::token::Plus; use syn::{Generics, Ident, ItemFn, ItemImpl, TypeParamBound, parse_quote, parse2}; use crate::cgp_fn::{ - FunctionAttributes, ImplicitArgField, apply_use_type_attributes_to_item_impl, - build_implicit_args_bounds, + FunctionAttributes, apply_use_type_attributes_to_item_impl, build_implicit_args_bounds, }; use crate::cgp_impl::derive_provider_bounds; diff --git a/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs b/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs index e195ba9b..626c3384 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs @@ -1,11 +1,11 @@ use std::mem; +use cgp_macro_core::types::implicits::ImplicitArgField; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::visit::{self, Visit}; use syn::{Attribute, FnArg, Meta, Pat, PatIdent, PatType, Receiver}; -use crate::cgp_fn::ImplicitArgField; use crate::derive_getter::parse_field_type; pub fn extract_and_parse_implicit_args( diff --git a/crates/cgp-macro-lib/src/cgp_fn/spec.rs b/crates/cgp-macro-lib/src/cgp_fn/spec.rs index 0522fef2..8c1cf8c8 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/spec.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/spec.rs @@ -1,18 +1,6 @@ use cgp_macro_core::types::attributes::{UseProviderAttribute, UseTypeAttribute}; use cgp_macro_core::types::ident::IdentWithTypeArgs; -use syn::token::Mut; -use syn::{GenericParam, Ident, Type, TypeParamBound, WherePredicate}; - -use crate::derive_getter::FieldMode; - -#[derive(Clone, Eq, PartialEq)] -pub struct ImplicitArgField { - pub field_name: Ident, - pub field_type: Type, - pub field_mut: Option, - pub field_mode: FieldMode, - pub arg_type: Type, -} +use syn::{GenericParam, TypeParamBound, WherePredicate}; #[derive(Default)] pub struct FunctionAttributes { diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index d6cc58ce..2f79319b 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -8,17 +8,18 @@ use syn::token::Plus; use syn::{Error, ItemImpl, TypeParamBound, parse_quote, parse2}; use crate::cgp_fn::{apply_use_type_attributes_to_item_impl, build_implicit_args_bounds}; +use crate::cgp_impl::derive_provider_impl; +use crate::cgp_impl::implicit_args::extract_implicit_args_from_impl_items; use crate::cgp_impl::provider_bounds::derive_provider_bounds; -use crate::cgp_impl::{derive_provider_impl, implicit_args}; use crate::derive_provider::{ derive_component_name_from_provider_impl, derive_is_provider_for, derive_provider_struct, }; pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result { - let attributes = ImplAttributes::parse(&mut item_impl.attrs)?; + let attributes = ImplAttributes::parse(&item_impl.attrs)?; item_impl.attrs = attributes.raw_attributes; - let implicit_args = implicit_args::extract_implicit_args_from_impl_items(&mut item_impl.items)?; + let implicit_args = extract_implicit_args_from_impl_items(&mut item_impl.items)?; if !implicit_args.is_empty() { let where_clause = item_impl.generics.make_where_clause(); diff --git a/crates/cgp-macro-lib/src/cgp_impl/implicit_args.rs b/crates/cgp-macro-lib/src/cgp_impl/implicit_args.rs index 8f351bdc..8c3fa6d9 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/implicit_args.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/implicit_args.rs @@ -1,6 +1,7 @@ +use cgp_macro_core::types::implicits::ImplicitArgField; use syn::ImplItem; -use crate::cgp_fn::{ImplicitArgField, extract_and_parse_implicit_args, inject_implicit_args}; +use crate::cgp_fn::{extract_and_parse_implicit_args, inject_implicit_args}; pub fn extract_implicit_args_from_impl_items( impl_items: &mut [ImplItem], diff --git a/crates/cgp-macro-lib/src/derive_getter/constraint.rs b/crates/cgp-macro-lib/src/derive_getter/constraint.rs index 6c28596c..670acd22 100644 --- a/crates/cgp-macro-lib/src/derive_getter/constraint.rs +++ b/crates/cgp-macro-lib/src/derive_getter/constraint.rs @@ -1,10 +1,9 @@ +use cgp_macro_core::types::getter::FieldMode; use proc_macro2::TokenStream; use quote::quote; use syn::token::Mut; use syn::{Ident, Type, TypeParamBound, parse_quote, parse2}; -use crate::derive_getter::FieldMode; - pub fn derive_getter_constraint( field_type: &Type, field_mut: &Option, diff --git a/crates/cgp-macro-lib/src/derive_getter/getter_field.rs b/crates/cgp-macro-lib/src/derive_getter/getter_field.rs index d300d81c..e4758654 100644 --- a/crates/cgp-macro-lib/src/derive_getter/getter_field.rs +++ b/crates/cgp-macro-lib/src/derive_getter/getter_field.rs @@ -1,3 +1,4 @@ +use cgp_macro_core::types::getter::FieldMode; use syn::token::Mut; use syn::{Ident, Type}; @@ -11,16 +12,6 @@ pub struct GetterField { pub receiver_mode: ReceiverMode, } -#[derive(Clone, Eq, PartialEq)] -pub enum FieldMode { - Reference, - OptionRef, - MRef, - Str, - Copy, - Slice, -} - pub enum ReceiverMode { SelfReceiver, Type(Box), diff --git a/crates/cgp-macro-lib/src/derive_getter/method.rs b/crates/cgp-macro-lib/src/derive_getter/method.rs index 0ec82fce..23b804c4 100644 --- a/crates/cgp-macro-lib/src/derive_getter/method.rs +++ b/crates/cgp-macro-lib/src/derive_getter/method.rs @@ -1,9 +1,10 @@ +use cgp_macro_core::types::getter::FieldMode; use proc_macro2::TokenStream; use quote::quote; use syn::Ident; use syn::token::Mut; -use crate::derive_getter::{FieldMode, GetterField}; +use crate::derive_getter::GetterField; pub enum ContextArg { SelfArg, diff --git a/crates/cgp-macro-lib/src/derive_getter/parse.rs b/crates/cgp-macro-lib/src/derive_getter/parse.rs index 5b04f6db..aad8ec54 100644 --- a/crates/cgp-macro-lib/src/derive_getter/parse.rs +++ b/crates/cgp-macro-lib/src/derive_getter/parse.rs @@ -1,5 +1,6 @@ use alloc::vec::Vec; +use cgp_macro_core::types::getter::FieldMode; use cgp_macro_core::visitors::ReplaceSelfTypeVisitor; use quote::{ToTokens, quote}; use syn::punctuated::Punctuated; @@ -11,8 +12,8 @@ use syn::{ Signature, TraitItem, TraitItemFn, TraitItemType, Type, TypePath, parse_quote, parse2, }; +use crate::derive_getter::ReceiverMode; use crate::derive_getter::getter_field::GetterField; -use crate::derive_getter::{FieldMode, ReceiverMode}; pub fn parse_getter_fields( context_type: &Ident, diff --git a/crates/cgp-macro-lib/src/derive_getter/with_provider.rs b/crates/cgp-macro-lib/src/derive_getter/with_provider.rs index 6f470d6a..9c5ec55c 100644 --- a/crates/cgp-macro-lib/src/derive_getter/with_provider.rs +++ b/crates/cgp-macro-lib/src/derive_getter/with_provider.rs @@ -1,9 +1,10 @@ +use cgp_macro_core::types::getter::FieldMode; use proc_macro2::{Span, TokenStream}; use quote::{ToTokens, quote}; use syn::{Generics, Ident, ItemImpl, ItemTrait, TraitItemType, parse_quote, parse2}; use crate::derive_getter::getter_field::GetterField; -use crate::derive_getter::{ContextArg, FieldMode, ReceiverMode, derive_getter_method}; +use crate::derive_getter::{ContextArg, ReceiverMode, derive_getter_method}; use crate::parse::ComponentSpec; use crate::type_component::get_bounds_and_replace_self_assoc_type; From 5670604ec1ef269d977c935bc0441b8add5ab67b Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sun, 31 May 2026 14:48:47 +0200 Subject: [PATCH 17/46] Refactor prepend_to_block --- .../src/types/field/field_name.rs | 7 ++++ .../src/types/implicits/arg_field.rs | 26 +++++++++++- .../src/types/implicits/arg_fields.rs | 24 +++++++++++ crates/cgp-macro-lib/src/cgp_fn/derive.rs | 5 +-- crates/cgp-macro-lib/src/cgp_fn/fn_body.rs | 41 ------------------- crates/cgp-macro-lib/src/cgp_fn/mod.rs | 2 - .../src/cgp_fn/parse_implicits.rs | 8 ++-- .../src/cgp_impl/implicit_args.rs | 6 +-- 8 files changed, 64 insertions(+), 55 deletions(-) delete mode 100644 crates/cgp-macro-lib/src/cgp_fn/fn_body.rs diff --git a/crates/cgp-macro-core/src/types/field/field_name.rs b/crates/cgp-macro-core/src/types/field/field_name.rs index c4418fb8..5e8ea365 100644 --- a/crates/cgp-macro-core/src/types/field/field_name.rs +++ b/crates/cgp-macro-core/src/types/field/field_name.rs @@ -1,5 +1,6 @@ use proc_macro2::TokenStream; use quote::ToTokens; +use syn::Ident; use crate::types::field::{Index, Symbol}; @@ -8,6 +9,12 @@ pub enum FieldName { Index(Index), } +impl From for FieldName { + fn from(value: Ident) -> Self { + Self::Ident(Symbol::new(value)) + } +} + impl From for FieldName { fn from(value: Symbol) -> Self { Self::Ident(value) diff --git a/crates/cgp-macro-core/src/types/implicits/arg_field.rs b/crates/cgp-macro-core/src/types/implicits/arg_field.rs index 04432720..4b871c3c 100644 --- a/crates/cgp-macro-core/src/types/implicits/arg_field.rs +++ b/crates/cgp-macro-core/src/types/implicits/arg_field.rs @@ -1,7 +1,7 @@ use syn::token::Mut; -use syn::{Ident, Type}; +use syn::{Ident, Stmt, Type, parse_quote}; -use crate::types::getter::FieldMode; +use crate::types::getter::{FieldMode, GetFieldExpr, GetFieldWithModeExpr}; #[derive(Clone, Eq, PartialEq)] pub struct ImplicitArgField { @@ -11,3 +11,25 @@ pub struct ImplicitArgField { pub field_mode: FieldMode, pub arg_type: Type, } + +impl ImplicitArgField { + pub fn to_statement(&self) -> syn::Result { + let field_name = &self.field_name; + let arg_type = &self.arg_type; + + let get_field_expr = GetFieldWithModeExpr { + field_mode: self.field_mode.clone(), + get_field: GetFieldExpr { + receiver: parse_quote!(self), + field_mut: self.field_mut, + field_name: self.field_name.clone().into(), + }, + }; + + let statement = parse_quote! { + let #field_name: #arg_type = #get_field_expr; + }; + + Ok(statement) + } +} diff --git a/crates/cgp-macro-core/src/types/implicits/arg_fields.rs b/crates/cgp-macro-core/src/types/implicits/arg_fields.rs index 62aa8205..789d8d56 100644 --- a/crates/cgp-macro-core/src/types/implicits/arg_fields.rs +++ b/crates/cgp-macro-core/src/types/implicits/arg_fields.rs @@ -1,5 +1,29 @@ +use syn::Block; + use crate::types::implicits::ImplicitArgField; +#[derive(Default)] pub struct ImplicitArgFields { pub fields: Vec, } + +impl ImplicitArgFields { + pub fn new(fields: Vec) -> Self { + Self { fields } + } +} + +impl ImplicitArgFields { + pub fn prepend_to_block(&self, block: &mut Block) -> syn::Result<()> { + let block_statements = core::mem::take(&mut block.stmts); + + for field in &self.fields { + let statement = field.to_statement()?; + block.stmts.push(statement); + } + + block.stmts.extend(block_statements); + + Ok(()) + } +} diff --git a/crates/cgp-macro-lib/src/cgp_fn/derive.rs b/crates/cgp-macro-lib/src/cgp_fn/derive.rs index 6850c04f..6dba3c55 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/derive.rs @@ -4,7 +4,6 @@ use proc_macro2::TokenStream; use quote::quote; use syn::{Ident, ItemFn, Visibility}; -use crate::cgp_fn::fn_body::inject_implicit_args; use crate::cgp_fn::item_impl::derive_item_impl; use crate::cgp_fn::item_trait::derive_item_trait; use crate::cgp_fn::{extract_and_parse_implicit_args, parse_function_attributes}; @@ -18,7 +17,7 @@ pub fn derive_cgp_fn(trait_ident: &Ident, mut item_fn: ItemFn) -> syn::Result syn::Result syn::Result<()> { - for arg in args.iter().rev() { - inject_implicit_arg(arg, body)?; - } - - Ok(()) -} - -pub fn inject_implicit_arg(arg: &ImplicitArgField, body: &mut Block) -> syn::Result<()> { - let field_name = &arg.field_name; - let arg_type = &arg.arg_type; - - let field_symbol = Symbol::new(field_name.clone()); - - let call_expr = if arg.field_mut.is_none() { - quote! { - self.get_field(::core::marker::PhantomData::< #field_symbol >) - } - } else { - quote! { - self.get_field_mut(::core::marker::PhantomData::< #field_symbol >) - } - }; - - let call_expr = extend_call_expr(call_expr, &arg.field_mode, &arg.field_mut); - - let statement = parse2(quote! { - let #field_name: #arg_type = #call_expr; - })?; - - body.stmts.insert(0, statement); - - Ok(()) -} diff --git a/crates/cgp-macro-lib/src/cgp_fn/mod.rs b/crates/cgp-macro-lib/src/cgp_fn/mod.rs index 0c5e3966..a7c9d714 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/mod.rs @@ -2,7 +2,6 @@ mod apply_type; mod attributes; mod bounds; mod derive; -mod fn_body; mod item_impl; mod item_trait; mod parse_implicits; @@ -14,7 +13,6 @@ pub use apply_type::*; pub use attributes::*; pub use bounds::*; pub use derive::*; -pub use fn_body::*; pub use item_trait::*; pub use parse_implicits::*; pub use spec::*; diff --git a/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs b/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs index 626c3384..a46a13b7 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs @@ -1,6 +1,6 @@ use std::mem; -use cgp_macro_core::types::implicits::ImplicitArgField; +use cgp_macro_core::types::implicits::{ImplicitArgField, ImplicitArgFields}; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::visit::{self, Visit}; @@ -10,11 +10,11 @@ use crate::derive_getter::parse_field_type; pub fn extract_and_parse_implicit_args( args: &mut Punctuated, -) -> syn::Result> { +) -> syn::Result { let implicit_fn_args = extract_implicit_args(args); if implicit_fn_args.is_empty() { - return Ok(Vec::new()); + return Ok(ImplicitArgFields::default()); } let Some(FnArg::Receiver(receiver)) = args.first() else { @@ -38,7 +38,7 @@ pub fn extract_and_parse_implicit_args( implicit_args.push(spec); } - Ok(implicit_args) + Ok(ImplicitArgFields::new(implicit_args)) } pub fn parse_implicit_arg(receiver: &Receiver, arg: &PatType) -> syn::Result { diff --git a/crates/cgp-macro-lib/src/cgp_impl/implicit_args.rs b/crates/cgp-macro-lib/src/cgp_impl/implicit_args.rs index 8c3fa6d9..b1356b92 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/implicit_args.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/implicit_args.rs @@ -1,7 +1,7 @@ use cgp_macro_core::types::implicits::ImplicitArgField; use syn::ImplItem; -use crate::cgp_fn::{extract_and_parse_implicit_args, inject_implicit_args}; +use crate::cgp_fn::extract_and_parse_implicit_args; pub fn extract_implicit_args_from_impl_items( impl_items: &mut [ImplItem], @@ -11,9 +11,9 @@ pub fn extract_implicit_args_from_impl_items( for item in impl_items { if let ImplItem::Fn(method) = item { let implicit_args = extract_and_parse_implicit_args(&mut method.sig.inputs)?; - inject_implicit_args(&implicit_args, &mut method.block)?; + implicit_args.prepend_to_block(&mut method.block)?; - for implicit_arg in implicit_args { + for implicit_arg in implicit_args.fields { if !all_implicit_args.contains(&implicit_arg) { all_implicit_args.push(implicit_arg); } From 965e873d7854643a9f6111ed5e2c578174723c58 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sun, 31 May 2026 23:05:27 +0200 Subject: [PATCH 18/46] Accept tag Type in derive_getter_constraints --- crates/cgp-macro-lib/src/cgp_fn/bounds.rs | 10 +++++----- crates/cgp-macro-lib/src/derive_getter/blanket.rs | 13 ++++++------- .../cgp-macro-lib/src/derive_getter/constraint.rs | 9 ++++----- crates/cgp-macro-lib/src/derive_getter/use_field.rs | 8 ++++---- .../cgp-macro-lib/src/derive_getter/use_fields.rs | 13 ++++++------- crates/cgp-runtime/Cargo.toml | 5 +---- crates/cgp-runtime/src/traits/has_runtime.rs | 2 +- crates/cgp-runtime/src/traits/has_runtime_type.rs | 2 +- 8 files changed, 28 insertions(+), 34 deletions(-) diff --git a/crates/cgp-macro-lib/src/cgp_fn/bounds.rs b/crates/cgp-macro-lib/src/cgp_fn/bounds.rs index 6c4f7f35..3cf2d49b 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/bounds.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/bounds.rs @@ -1,11 +1,10 @@ +use cgp_macro_core::types::field::FieldName; use cgp_macro_core::types::implicits::ImplicitArgField; -use quote::ToTokens; -use syn::TypeParamBound; use syn::punctuated::Punctuated; use syn::token::Plus; +use syn::{TypeParamBound, parse_quote}; use crate::derive_getter::derive_getter_constraint; -use crate::symbol::symbol_from_string; pub fn build_implicit_args_bounds( implicit_args: &[ImplicitArgField], @@ -13,13 +12,14 @@ pub fn build_implicit_args_bounds( let mut constraints: Punctuated = Punctuated::new(); for arg in implicit_args { - let field_symbol = symbol_from_string(&arg.field_name.to_string())?; + let field_name = FieldName::from(arg.field_name.clone()); + let tag_type = parse_quote!(#field_name); let constraint = derive_getter_constraint( &arg.field_type, &arg.field_mut, &arg.field_mode, - field_symbol.to_token_stream(), + &tag_type, &None, )?; diff --git a/crates/cgp-macro-lib/src/derive_getter/blanket.rs b/crates/cgp-macro-lib/src/derive_getter/blanket.rs index 730a643e..c690e0aa 100644 --- a/crates/cgp-macro-lib/src/derive_getter/blanket.rs +++ b/crates/cgp-macro-lib/src/derive_getter/blanket.rs @@ -1,14 +1,12 @@ -use alloc::string::ToString; - +use cgp_macro_core::types::field::FieldName; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; -use syn::{Ident, ItemImpl, ItemTrait, TraitItemType, parse2}; +use syn::{Ident, ItemImpl, ItemTrait, TraitItemType, parse_quote, parse2}; use crate::derive_getter::getter_field::GetterField; use crate::derive_getter::{ ContextArg, ReceiverMode, derive_getter_constraint, derive_getter_method, }; -use crate::symbol::symbol_from_string; use crate::type_component::get_bounds_and_replace_self_assoc_type; pub fn derive_blanket_impl( @@ -64,12 +62,13 @@ pub fn derive_blanket_impl( ), }; - let field_symbol = symbol_from_string(&field.field_name.to_string())?; + let field_name = FieldName::from(field.field_name.clone()); + let tag_type = parse_quote!(#field_name); let method = derive_getter_method( &context_arg, field, - Some(quote! { ::< #field_symbol > }), + Some(quote! { ::< #field_name > }), None, ); @@ -79,7 +78,7 @@ pub fn derive_blanket_impl( &field.field_type, &field.receiver_mut, &field.field_mode, - quote! { #field_symbol }, + &tag_type, &field_assoc_type.as_ref().map(|item| item.ident.clone()), )?; diff --git a/crates/cgp-macro-lib/src/derive_getter/constraint.rs b/crates/cgp-macro-lib/src/derive_getter/constraint.rs index 670acd22..90ec3fa8 100644 --- a/crates/cgp-macro-lib/src/derive_getter/constraint.rs +++ b/crates/cgp-macro-lib/src/derive_getter/constraint.rs @@ -1,5 +1,4 @@ use cgp_macro_core::types::getter::FieldMode; -use proc_macro2::TokenStream; use quote::quote; use syn::token::Mut; use syn::{Ident, Type, TypeParamBound, parse_quote, parse2}; @@ -8,7 +7,7 @@ pub fn derive_getter_constraint( field_type: &Type, field_mut: &Option, field_mode: &FieldMode, - field_symbol: TokenStream, + tag_type: &Type, field_assoc_type: &Option, ) -> syn::Result { let field_type = match field_assoc_type { @@ -19,16 +18,16 @@ pub fn derive_getter_constraint( let constraint = if field_mut.is_none() { if let FieldMode::Slice = field_mode { quote! { - HasField< #field_symbol, Value: AsRef< [ #field_type ] > + 'static > + HasField< #tag_type, Value: AsRef< [ #field_type ] > + 'static > } } else { quote! { - HasField< #field_symbol, Value = #field_type > + HasField< #tag_type, Value = #field_type > } } } else { quote! { - HasFieldMut< #field_symbol, Value = #field_type > + HasFieldMut< #tag_type, Value = #field_type > } }; diff --git a/crates/cgp-macro-lib/src/derive_getter/use_field.rs b/crates/cgp-macro-lib/src/derive_getter/use_field.rs index cddc1977..cb34dae2 100644 --- a/crates/cgp-macro-lib/src/derive_getter/use_field.rs +++ b/crates/cgp-macro-lib/src/derive_getter/use_field.rs @@ -2,7 +2,7 @@ use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::punctuated::Punctuated; use syn::token::Plus; -use syn::{Generics, ItemImpl, ItemTrait, TraitItemType, TypeParamBound, parse2}; +use syn::{Generics, ItemImpl, ItemTrait, TraitItemType, TypeParamBound, parse_quote, parse2}; use crate::derive_getter::getter_field::GetterField; use crate::derive_getter::{ @@ -27,7 +27,7 @@ pub fn derive_use_field_impl( let mut field_constraints: Punctuated = Punctuated::default(); - let tag_type = quote! { __Tag__ }; + let tag_type = parse_quote! { __Tag__ }; let mut items = TokenStream::new(); @@ -65,7 +65,7 @@ pub fn derive_use_field_impl( &field.field_type, &field.receiver_mut, &field.field_mode, - quote! { #tag_type }, + &tag_type, &field_assoc_type.as_ref().map(|item| item.ident.clone()), )?; @@ -81,7 +81,7 @@ pub fn derive_use_field_impl( let impl_generics = { let mut generics: Generics = parse2(impl_generics.to_token_stream())?; - generics.params.push(parse2(tag_type.clone())?); + generics.params.push(parse_quote!(#tag_type)); generics }; diff --git a/crates/cgp-macro-lib/src/derive_getter/use_fields.rs b/crates/cgp-macro-lib/src/derive_getter/use_fields.rs index 73f6849c..25c25ec5 100644 --- a/crates/cgp-macro-lib/src/derive_getter/use_fields.rs +++ b/crates/cgp-macro-lib/src/derive_getter/use_fields.rs @@ -1,15 +1,13 @@ -use alloc::string::ToString; - +use cgp_macro_core::types::field::Symbol; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; -use syn::{ItemImpl, ItemTrait, TraitItemType, parse2}; +use syn::{ItemImpl, ItemTrait, TraitItemType, parse_quote, parse2}; use crate::derive_getter::getter_field::GetterField; use crate::derive_getter::{ ContextArg, ReceiverMode, derive_getter_constraint, derive_getter_method, }; use crate::parse::ComponentSpec; -use crate::symbol::symbol_from_string; use crate::type_component::get_bounds_and_replace_self_assoc_type; pub fn derive_use_fields_impl( @@ -55,12 +53,13 @@ pub fn derive_use_fields_impl( ReceiverMode::Type(ty) => ty.to_token_stream(), }; - let field_symbol = symbol_from_string(&field.field_name.to_string())?; + let field_name = Symbol::new(field.field_name.clone()); + let tag_type = parse_quote!(#field_name); let method = derive_getter_method( &ContextArg::Ident(receiver_type.clone()), field, - Some(quote! { ::< #field_symbol > }), + Some(quote! { ::< #field_name > }), None, ); @@ -70,7 +69,7 @@ pub fn derive_use_fields_impl( &field.field_type, &field.receiver_mut, &field.field_mode, - quote! { #field_symbol }, + &tag_type, &field_assoc_type.as_ref().map(|item| item.ident.clone()), )?; diff --git a/crates/cgp-runtime/Cargo.toml b/crates/cgp-runtime/Cargo.toml index 5c00a985..da3894bd 100644 --- a/crates/cgp-runtime/Cargo.toml +++ b/crates/cgp-runtime/Cargo.toml @@ -7,9 +7,6 @@ repository = { workspace = true } authors = { workspace = true } rust-version = { workspace = true } keywords = { workspace = true } -description = """ - Context-generic programming core component traits -""" [dependencies] -cgp-core = { workspace = true } +cgp = { version = "0.7.0", path = "../cgp-core", package = "cgp-core" } diff --git a/crates/cgp-runtime/src/traits/has_runtime.rs b/crates/cgp-runtime/src/traits/has_runtime.rs index 7a12f6f8..35b8c537 100644 --- a/crates/cgp-runtime/src/traits/has_runtime.rs +++ b/crates/cgp-runtime/src/traits/has_runtime.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use crate::HasRuntimeType; diff --git a/crates/cgp-runtime/src/traits/has_runtime_type.rs b/crates/cgp-runtime/src/traits/has_runtime_type.rs index 10cd1fc0..446392a8 100644 --- a/crates/cgp-runtime/src/traits/has_runtime_type.rs +++ b/crates/cgp-runtime/src/traits/has_runtime_type.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; #[cgp_type] pub trait HasRuntimeType { From d05ce70ec2253344d757c5bd9fc82f4ed82da697 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sun, 31 May 2026 23:09:31 +0200 Subject: [PATCH 19/46] Remove field_assoc_type param from derive_getter_constraint --- crates/cgp-macro-lib/src/cgp_fn/bounds.rs | 9 ++------- crates/cgp-macro-lib/src/derive_getter/blanket.rs | 10 ++++++++-- crates/cgp-macro-lib/src/derive_getter/constraint.rs | 8 +------- crates/cgp-macro-lib/src/derive_getter/use_field.rs | 10 ++++++++-- crates/cgp-macro-lib/src/derive_getter/use_fields.rs | 10 ++++++++-- 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/crates/cgp-macro-lib/src/cgp_fn/bounds.rs b/crates/cgp-macro-lib/src/cgp_fn/bounds.rs index 3cf2d49b..d7e7c582 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/bounds.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/bounds.rs @@ -15,13 +15,8 @@ pub fn build_implicit_args_bounds( let field_name = FieldName::from(arg.field_name.clone()); let tag_type = parse_quote!(#field_name); - let constraint = derive_getter_constraint( - &arg.field_type, - &arg.field_mut, - &arg.field_mode, - &tag_type, - &None, - )?; + let constraint = + derive_getter_constraint(&arg.field_type, &arg.field_mut, &arg.field_mode, &tag_type)?; constraints.push(constraint); } diff --git a/crates/cgp-macro-lib/src/derive_getter/blanket.rs b/crates/cgp-macro-lib/src/derive_getter/blanket.rs index c690e0aa..fd7f8862 100644 --- a/crates/cgp-macro-lib/src/derive_getter/blanket.rs +++ b/crates/cgp-macro-lib/src/derive_getter/blanket.rs @@ -74,12 +74,18 @@ pub fn derive_blanket_impl( items.extend(method); + let field_type = if let Some(trait_item) = &field_assoc_type { + let trait_item_ident = &trait_item.ident; + parse_quote!(#trait_item_ident) + } else { + field.field_type.clone() + }; + let constraint = derive_getter_constraint( - &field.field_type, + &field_type, &field.receiver_mut, &field.field_mode, &tag_type, - &field_assoc_type.as_ref().map(|item| item.ident.clone()), )?; where_clause.predicates.push(parse2(quote! { diff --git a/crates/cgp-macro-lib/src/derive_getter/constraint.rs b/crates/cgp-macro-lib/src/derive_getter/constraint.rs index 90ec3fa8..71e6185e 100644 --- a/crates/cgp-macro-lib/src/derive_getter/constraint.rs +++ b/crates/cgp-macro-lib/src/derive_getter/constraint.rs @@ -1,20 +1,14 @@ use cgp_macro_core::types::getter::FieldMode; use quote::quote; use syn::token::Mut; -use syn::{Ident, Type, TypeParamBound, parse_quote, parse2}; +use syn::{Type, TypeParamBound, parse2}; pub fn derive_getter_constraint( field_type: &Type, field_mut: &Option, field_mode: &FieldMode, tag_type: &Type, - field_assoc_type: &Option, ) -> syn::Result { - let field_type = match field_assoc_type { - Some(field_assoc_type) => parse_quote! { #field_assoc_type }, - None => field_type.clone(), - }; - let constraint = if field_mut.is_none() { if let FieldMode::Slice = field_mode { quote! { diff --git a/crates/cgp-macro-lib/src/derive_getter/use_field.rs b/crates/cgp-macro-lib/src/derive_getter/use_field.rs index cb34dae2..a6b797ed 100644 --- a/crates/cgp-macro-lib/src/derive_getter/use_field.rs +++ b/crates/cgp-macro-lib/src/derive_getter/use_field.rs @@ -61,12 +61,18 @@ pub fn derive_use_field_impl( None, )); + let field_type = if let Some(trait_item) = &field_assoc_type { + let trait_item_ident = &trait_item.ident; + parse_quote!(#trait_item_ident) + } else { + field.field_type.clone() + }; + let constraint = derive_getter_constraint( - &field.field_type, + &field_type, &field.receiver_mut, &field.field_mode, &tag_type, - &field_assoc_type.as_ref().map(|item| item.ident.clone()), )?; field_constraints.push(constraint); diff --git a/crates/cgp-macro-lib/src/derive_getter/use_fields.rs b/crates/cgp-macro-lib/src/derive_getter/use_fields.rs index 25c25ec5..b457f2f8 100644 --- a/crates/cgp-macro-lib/src/derive_getter/use_fields.rs +++ b/crates/cgp-macro-lib/src/derive_getter/use_fields.rs @@ -65,12 +65,18 @@ pub fn derive_use_fields_impl( items.extend(method); + let field_type = if let Some(trait_item) = &field_assoc_type { + let trait_item_ident = &trait_item.ident; + parse_quote!(#trait_item_ident) + } else { + field.field_type.clone() + }; + let constraint = derive_getter_constraint( - &field.field_type, + &field_type, &field.receiver_mut, &field.field_mode, &tag_type, - &field_assoc_type.as_ref().map(|item| item.ident.clone()), )?; where_clause From 6e1e124e676f762fd3b2a25b0e79a4128a5c5657 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 3 Jun 2026 21:38:38 +0200 Subject: [PATCH 20/46] Replace derive_getter_constraint with HasFieldBound --- .../src/types/field/has_field_bound.rs | 42 +++++++++++++++++++ crates/cgp-macro-core/src/types/field/mod.rs | 2 + .../src/types/implicits/arg_field.rs | 13 ++++++ crates/cgp-macro-lib/src/cgp_fn/bounds.rs | 12 +----- .../src/derive_getter/blanket.rs | 18 ++++---- .../src/derive_getter/constraint.rs | 29 ------------- crates/cgp-macro-lib/src/derive_getter/mod.rs | 2 - .../src/derive_getter/use_field.rs | 25 +++++------ .../src/derive_getter/use_fields.rs | 22 +++++----- 9 files changed, 90 insertions(+), 75 deletions(-) create mode 100644 crates/cgp-macro-core/src/types/field/has_field_bound.rs delete mode 100644 crates/cgp-macro-lib/src/derive_getter/constraint.rs diff --git a/crates/cgp-macro-core/src/types/field/has_field_bound.rs b/crates/cgp-macro-core/src/types/field/has_field_bound.rs new file mode 100644 index 00000000..6d9872c6 --- /dev/null +++ b/crates/cgp-macro-core/src/types/field/has_field_bound.rs @@ -0,0 +1,42 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, quote}; +use syn::Type; +use syn::token::Mut; + +use crate::types::getter::FieldMode; + +pub struct HasFieldBound { + pub field_type: Type, + pub field_mut: Option, + pub field_mode: FieldMode, + pub tag_type: Type, +} + +impl ToTokens for HasFieldBound { + fn to_tokens(&self, tokens: &mut TokenStream) { + let Self { + field_type, + field_mut, + field_mode, + tag_type, + } = self; + + let output = if field_mut.is_none() { + if let FieldMode::Slice = field_mode { + quote! { + HasField< #tag_type, Value: AsRef< [ #field_type ] > + 'static > + } + } else { + quote! { + HasField< #tag_type, Value = #field_type > + } + } + } else { + quote! { + HasFieldMut< #tag_type, Value = #field_type > + } + }; + + tokens.extend(output); + } +} diff --git a/crates/cgp-macro-core/src/types/field/mod.rs b/crates/cgp-macro-core/src/types/field/mod.rs index bc01f09a..acb83f01 100644 --- a/crates/cgp-macro-core/src/types/field/mod.rs +++ b/crates/cgp-macro-core/src/types/field/mod.rs @@ -1,7 +1,9 @@ mod field_name; +mod has_field_bound; mod index; mod symbol; pub use field_name::*; +pub use has_field_bound::*; pub use index::*; pub use symbol::*; diff --git a/crates/cgp-macro-core/src/types/implicits/arg_field.rs b/crates/cgp-macro-core/src/types/implicits/arg_field.rs index 4b871c3c..3428b0f2 100644 --- a/crates/cgp-macro-core/src/types/implicits/arg_field.rs +++ b/crates/cgp-macro-core/src/types/implicits/arg_field.rs @@ -1,6 +1,7 @@ use syn::token::Mut; use syn::{Ident, Stmt, Type, parse_quote}; +use crate::types::field::{FieldName, HasFieldBound}; use crate::types::getter::{FieldMode, GetFieldExpr, GetFieldWithModeExpr}; #[derive(Clone, Eq, PartialEq)] @@ -13,6 +14,18 @@ pub struct ImplicitArgField { } impl ImplicitArgField { + pub fn to_has_field_bound(&self) -> syn::Result { + let field_name = FieldName::from(self.field_name.clone()); + let tag_type = parse_quote!(#field_name); + + Ok(HasFieldBound { + field_type: self.field_type.clone(), + field_mut: self.field_mut.clone(), + field_mode: self.field_mode.clone(), + tag_type, + }) + } + pub fn to_statement(&self) -> syn::Result { let field_name = &self.field_name; let arg_type = &self.arg_type; diff --git a/crates/cgp-macro-lib/src/cgp_fn/bounds.rs b/crates/cgp-macro-lib/src/cgp_fn/bounds.rs index d7e7c582..6ea44037 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/bounds.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/bounds.rs @@ -1,24 +1,16 @@ -use cgp_macro_core::types::field::FieldName; use cgp_macro_core::types::implicits::ImplicitArgField; use syn::punctuated::Punctuated; use syn::token::Plus; use syn::{TypeParamBound, parse_quote}; -use crate::derive_getter::derive_getter_constraint; - pub fn build_implicit_args_bounds( implicit_args: &[ImplicitArgField], ) -> syn::Result> { let mut constraints: Punctuated = Punctuated::new(); for arg in implicit_args { - let field_name = FieldName::from(arg.field_name.clone()); - let tag_type = parse_quote!(#field_name); - - let constraint = - derive_getter_constraint(&arg.field_type, &arg.field_mut, &arg.field_mode, &tag_type)?; - - constraints.push(constraint); + let constraint = arg.to_has_field_bound()?; + constraints.push(parse_quote!(#constraint)); } Ok(constraints) diff --git a/crates/cgp-macro-lib/src/derive_getter/blanket.rs b/crates/cgp-macro-lib/src/derive_getter/blanket.rs index fd7f8862..a418c809 100644 --- a/crates/cgp-macro-lib/src/derive_getter/blanket.rs +++ b/crates/cgp-macro-lib/src/derive_getter/blanket.rs @@ -1,12 +1,10 @@ -use cgp_macro_core::types::field::FieldName; +use cgp_macro_core::types::field::{FieldName, HasFieldBound}; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::{Ident, ItemImpl, ItemTrait, TraitItemType, parse_quote, parse2}; use crate::derive_getter::getter_field::GetterField; -use crate::derive_getter::{ - ContextArg, ReceiverMode, derive_getter_constraint, derive_getter_method, -}; +use crate::derive_getter::{ContextArg, ReceiverMode, derive_getter_method}; use crate::type_component::get_bounds_and_replace_self_assoc_type; pub fn derive_blanket_impl( @@ -81,12 +79,12 @@ pub fn derive_blanket_impl( field.field_type.clone() }; - let constraint = derive_getter_constraint( - &field_type, - &field.receiver_mut, - &field.field_mode, - &tag_type, - )?; + let constraint = HasFieldBound { + field_type, + field_mut: field.receiver_mut.clone(), + field_mode: field.field_mode.clone(), + tag_type, + }; where_clause.predicates.push(parse2(quote! { #receiver_type: #constraint diff --git a/crates/cgp-macro-lib/src/derive_getter/constraint.rs b/crates/cgp-macro-lib/src/derive_getter/constraint.rs deleted file mode 100644 index 71e6185e..00000000 --- a/crates/cgp-macro-lib/src/derive_getter/constraint.rs +++ /dev/null @@ -1,29 +0,0 @@ -use cgp_macro_core::types::getter::FieldMode; -use quote::quote; -use syn::token::Mut; -use syn::{Type, TypeParamBound, parse2}; - -pub fn derive_getter_constraint( - field_type: &Type, - field_mut: &Option, - field_mode: &FieldMode, - tag_type: &Type, -) -> syn::Result { - let constraint = if field_mut.is_none() { - if let FieldMode::Slice = field_mode { - quote! { - HasField< #tag_type, Value: AsRef< [ #field_type ] > + 'static > - } - } else { - quote! { - HasField< #tag_type, Value = #field_type > - } - } - } else { - quote! { - HasFieldMut< #tag_type, Value = #field_type > - } - }; - - parse2(constraint) -} diff --git a/crates/cgp-macro-lib/src/derive_getter/mod.rs b/crates/cgp-macro-lib/src/derive_getter/mod.rs index 8d02d5ab..8b66cfa1 100644 --- a/crates/cgp-macro-lib/src/derive_getter/mod.rs +++ b/crates/cgp-macro-lib/src/derive_getter/mod.rs @@ -1,5 +1,4 @@ mod blanket; -mod constraint; mod getter_field; mod method; mod parse; @@ -8,7 +7,6 @@ mod use_fields; mod with_provider; pub use blanket::*; -pub use constraint::*; pub use getter_field::*; pub use method::*; pub use parse::*; diff --git a/crates/cgp-macro-lib/src/derive_getter/use_field.rs b/crates/cgp-macro-lib/src/derive_getter/use_field.rs index a6b797ed..cad88f85 100644 --- a/crates/cgp-macro-lib/src/derive_getter/use_field.rs +++ b/crates/cgp-macro-lib/src/derive_getter/use_field.rs @@ -1,13 +1,14 @@ +use cgp_macro_core::types::field::HasFieldBound; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::punctuated::Punctuated; use syn::token::Plus; -use syn::{Generics, ItemImpl, ItemTrait, TraitItemType, TypeParamBound, parse_quote, parse2}; +use syn::{ + Generics, ItemImpl, ItemTrait, TraitItemType, Type, TypeParamBound, parse_quote, parse2, +}; use crate::derive_getter::getter_field::GetterField; -use crate::derive_getter::{ - ContextArg, ReceiverMode, derive_getter_constraint, derive_getter_method, -}; +use crate::derive_getter::{ContextArg, ReceiverMode, derive_getter_method}; use crate::parse::ComponentSpec; use crate::type_component::get_bounds_and_replace_self_assoc_type; @@ -27,7 +28,7 @@ pub fn derive_use_field_impl( let mut field_constraints: Punctuated = Punctuated::default(); - let tag_type = parse_quote! { __Tag__ }; + let tag_type: Type = parse_quote! { __Tag__ }; let mut items = TokenStream::new(); @@ -68,14 +69,14 @@ pub fn derive_use_field_impl( field.field_type.clone() }; - let constraint = derive_getter_constraint( - &field_type, - &field.receiver_mut, - &field.field_mode, - &tag_type, - )?; + let constraint = HasFieldBound { + field_type, + field_mut: field.receiver_mut.clone(), + field_mode: field.field_mode.clone(), + tag_type: tag_type.clone(), + }; - field_constraints.push(constraint); + field_constraints.push(parse_quote!(#constraint)); let mut where_clause = provider_generics.make_where_clause().clone(); where_clause diff --git a/crates/cgp-macro-lib/src/derive_getter/use_fields.rs b/crates/cgp-macro-lib/src/derive_getter/use_fields.rs index b457f2f8..a2aa03a4 100644 --- a/crates/cgp-macro-lib/src/derive_getter/use_fields.rs +++ b/crates/cgp-macro-lib/src/derive_getter/use_fields.rs @@ -1,12 +1,10 @@ -use cgp_macro_core::types::field::Symbol; +use cgp_macro_core::types::field::{HasFieldBound, Symbol}; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; -use syn::{ItemImpl, ItemTrait, TraitItemType, parse_quote, parse2}; +use syn::{ItemImpl, ItemTrait, TraitItemType, Type, parse_quote, parse2}; use crate::derive_getter::getter_field::GetterField; -use crate::derive_getter::{ - ContextArg, ReceiverMode, derive_getter_constraint, derive_getter_method, -}; +use crate::derive_getter::{ContextArg, ReceiverMode, derive_getter_method}; use crate::parse::ComponentSpec; use crate::type_component::get_bounds_and_replace_self_assoc_type; @@ -54,7 +52,7 @@ pub fn derive_use_fields_impl( }; let field_name = Symbol::new(field.field_name.clone()); - let tag_type = parse_quote!(#field_name); + let tag_type: Type = parse_quote!(#field_name); let method = derive_getter_method( &ContextArg::Ident(receiver_type.clone()), @@ -72,12 +70,12 @@ pub fn derive_use_fields_impl( field.field_type.clone() }; - let constraint = derive_getter_constraint( - &field_type, - &field.receiver_mut, - &field.field_mode, - &tag_type, - )?; + let constraint = HasFieldBound { + field_type, + field_mut: field.receiver_mut.clone(), + field_mode: field.field_mode.clone(), + tag_type: tag_type.clone(), + }; where_clause .predicates From b7e4caf6afe9e4958e8c591f03e1d1ffe65eeeb7 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 3 Jun 2026 21:40:29 +0200 Subject: [PATCH 21/46] Use fully qualified HasField --- crates/cgp-macro-core/src/exports.rs | 2 ++ crates/cgp-macro-core/src/types/field/has_field_bound.rs | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/cgp-macro-core/src/exports.rs b/crates/cgp-macro-core/src/exports.rs index 9a69a1ad..292ecb57 100644 --- a/crates/cgp-macro-core/src/exports.rs +++ b/crates/cgp-macro-core/src/exports.rs @@ -10,4 +10,6 @@ export_constructs! { RedirectLookup, DelegateComponent, IsProviderFor, + HasField, + HasFieldMut, } diff --git a/crates/cgp-macro-core/src/types/field/has_field_bound.rs b/crates/cgp-macro-core/src/types/field/has_field_bound.rs index 6d9872c6..7c62fa4a 100644 --- a/crates/cgp-macro-core/src/types/field/has_field_bound.rs +++ b/crates/cgp-macro-core/src/types/field/has_field_bound.rs @@ -3,6 +3,7 @@ use quote::{ToTokens, quote}; use syn::Type; use syn::token::Mut; +use crate::exports::{HasField, HasFieldMut}; use crate::types::getter::FieldMode; pub struct HasFieldBound { @@ -24,16 +25,16 @@ impl ToTokens for HasFieldBound { let output = if field_mut.is_none() { if let FieldMode::Slice = field_mode { quote! { - HasField< #tag_type, Value: AsRef< [ #field_type ] > + 'static > + #HasField< #tag_type, Value: AsRef< [ #field_type ] > + 'static > } } else { quote! { - HasField< #tag_type, Value = #field_type > + #HasField< #tag_type, Value = #field_type > } } } else { quote! { - HasFieldMut< #tag_type, Value = #field_type > + #HasFieldMut< #tag_type, Value = #field_type > } }; From 12f9b220c9d3c3050a858ca0c6685a071e03667a Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 3 Jun 2026 21:47:31 +0200 Subject: [PATCH 22/46] Add to_type_param_bounds method --- .../src/types/implicits/arg_fields.rs | 15 ++++++++++++++- crates/cgp-macro-lib/src/cgp_fn/bounds.rs | 17 ----------------- crates/cgp-macro-lib/src/cgp_fn/derive.rs | 2 +- crates/cgp-macro-lib/src/cgp_fn/item_impl.rs | 12 +++++------- crates/cgp-macro-lib/src/cgp_fn/mod.rs | 2 -- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 6 +++--- .../cgp-macro-lib/src/cgp_impl/implicit_args.rs | 12 ++++++------ 7 files changed, 29 insertions(+), 37 deletions(-) delete mode 100644 crates/cgp-macro-lib/src/cgp_fn/bounds.rs diff --git a/crates/cgp-macro-core/src/types/implicits/arg_fields.rs b/crates/cgp-macro-core/src/types/implicits/arg_fields.rs index 789d8d56..52bd4ab9 100644 --- a/crates/cgp-macro-core/src/types/implicits/arg_fields.rs +++ b/crates/cgp-macro-core/src/types/implicits/arg_fields.rs @@ -1,4 +1,6 @@ -use syn::Block; +use syn::punctuated::Punctuated; +use syn::token::Plus; +use syn::{Block, TypeParamBound, parse_quote}; use crate::types::implicits::ImplicitArgField; @@ -14,6 +16,17 @@ impl ImplicitArgFields { } impl ImplicitArgFields { + pub fn to_type_param_bounds(&self) -> syn::Result> { + let mut constraints: Punctuated = Punctuated::new(); + + for field in &self.fields { + let constraint = field.to_has_field_bound()?; + constraints.push(parse_quote!(#constraint)); + } + + Ok(constraints) + } + pub fn prepend_to_block(&self, block: &mut Block) -> syn::Result<()> { let block_statements = core::mem::take(&mut block.stmts); diff --git a/crates/cgp-macro-lib/src/cgp_fn/bounds.rs b/crates/cgp-macro-lib/src/cgp_fn/bounds.rs deleted file mode 100644 index 6ea44037..00000000 --- a/crates/cgp-macro-lib/src/cgp_fn/bounds.rs +++ /dev/null @@ -1,17 +0,0 @@ -use cgp_macro_core::types::implicits::ImplicitArgField; -use syn::punctuated::Punctuated; -use syn::token::Plus; -use syn::{TypeParamBound, parse_quote}; - -pub fn build_implicit_args_bounds( - implicit_args: &[ImplicitArgField], -) -> syn::Result> { - let mut constraints: Punctuated = Punctuated::new(); - - for arg in implicit_args { - let constraint = arg.to_has_field_bound()?; - constraints.push(parse_quote!(#constraint)); - } - - Ok(constraints) -} diff --git a/crates/cgp-macro-lib/src/cgp_fn/derive.rs b/crates/cgp-macro-lib/src/cgp_fn/derive.rs index 6dba3c55..33477329 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/derive.rs @@ -27,7 +27,7 @@ pub fn derive_cgp_fn(trait_ident: &Ident, mut item_fn: ItemFn) -> syn::Result syn::Result { @@ -62,9 +60,9 @@ pub fn derive_item_impl( .extend(attributes.extend_where.clone()); } - if !implicit_args.is_empty() { + if !implicit_args.fields.is_empty() { let where_clause = item_impl.generics.make_where_clause(); - let bounds = build_implicit_args_bounds(implicit_args)?; + let bounds = implicit_args.to_type_param_bounds()?; where_clause.predicates.push(parse2(quote! { Self: #bounds diff --git a/crates/cgp-macro-lib/src/cgp_fn/mod.rs b/crates/cgp-macro-lib/src/cgp_fn/mod.rs index a7c9d714..9882de91 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/mod.rs @@ -1,6 +1,5 @@ mod apply_type; mod attributes; -mod bounds; mod derive; mod item_impl; mod item_trait; @@ -11,7 +10,6 @@ mod type_predicates; pub use apply_type::*; pub use attributes::*; -pub use bounds::*; pub use derive::*; pub use item_trait::*; pub use parse_implicits::*; diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index 2f79319b..39061860 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -7,7 +7,7 @@ use syn::spanned::Spanned; use syn::token::Plus; use syn::{Error, ItemImpl, TypeParamBound, parse_quote, parse2}; -use crate::cgp_fn::{apply_use_type_attributes_to_item_impl, build_implicit_args_bounds}; +use crate::cgp_fn::apply_use_type_attributes_to_item_impl; use crate::cgp_impl::derive_provider_impl; use crate::cgp_impl::implicit_args::extract_implicit_args_from_impl_items; use crate::cgp_impl::provider_bounds::derive_provider_bounds; @@ -21,9 +21,9 @@ pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result syn::Result> { - let mut all_implicit_args = Vec::new(); +) -> syn::Result { + let mut all_fields = Vec::new(); for item in impl_items { if let ImplItem::Fn(method) = item { @@ -14,12 +14,12 @@ pub fn extract_implicit_args_from_impl_items( implicit_args.prepend_to_block(&mut method.block)?; for implicit_arg in implicit_args.fields { - if !all_implicit_args.contains(&implicit_arg) { - all_implicit_args.push(implicit_arg); + if !all_fields.contains(&implicit_arg) { + all_fields.push(implicit_arg); } } } } - Ok(all_implicit_args) + Ok(ImplicitArgFields { fields: all_fields }) } From 5c906f301d34b0594b3ccf00f45efc75357df7dd Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 3 Jun 2026 21:57:57 +0200 Subject: [PATCH 23/46] Move parse_field_type --- .../cgp-macro-core/src/functions/field/mod.rs | 3 + .../src/functions/field/parse.rs | 108 ++++++++++++++++++ .../{ => generics}/merge_generics.rs | 0 .../src/functions/generics/mod.rs | 3 + crates/cgp-macro-core/src/functions/mod.rs | 6 +- .../src/cgp_fn/parse_implicits.rs | 3 +- .../cgp-macro-lib/src/derive_getter/parse.rs | 105 +---------------- 7 files changed, 121 insertions(+), 107 deletions(-) create mode 100644 crates/cgp-macro-core/src/functions/field/mod.rs create mode 100644 crates/cgp-macro-core/src/functions/field/parse.rs rename crates/cgp-macro-core/src/functions/{ => generics}/merge_generics.rs (100%) create mode 100644 crates/cgp-macro-core/src/functions/generics/mod.rs diff --git a/crates/cgp-macro-core/src/functions/field/mod.rs b/crates/cgp-macro-core/src/functions/field/mod.rs new file mode 100644 index 00000000..4f42021d --- /dev/null +++ b/crates/cgp-macro-core/src/functions/field/mod.rs @@ -0,0 +1,3 @@ +mod parse; + +pub use parse::*; diff --git a/crates/cgp-macro-core/src/functions/field/parse.rs b/crates/cgp-macro-core/src/functions/field/parse.rs new file mode 100644 index 00000000..3064918d --- /dev/null +++ b/crates/cgp-macro-core/src/functions/field/parse.rs @@ -0,0 +1,108 @@ +use quote::{ToTokens, quote}; +use syn::spanned::Spanned; +use syn::token::Mut; +use syn::{ + Error, GenericArgument, PathArguments, PathSegment, Type, TypePath, parse_quote, parse2, +}; + +use crate::types::getter::FieldMode; + +pub fn parse_field_type( + return_type: &Type, + receiver_mut: &Option, +) -> syn::Result<(Type, FieldMode)> { + match &return_type { + Type::Reference(type_ref) => { + if type_ref.mutability.is_some() && receiver_mut.is_none() { + return Err(Error::new( + type_ref.span(), + format!( + "&mut self is required for mutable field reference `{}`", + type_ref.to_token_stream() + ), + )); + } + + if type_ref.elem.as_ref() == &parse_quote! { str } { + // Special case to handle &str as String field + + let field_type: Type = parse_quote! { String }; + + Ok((field_type, FieldMode::Str)) + } else if let (Type::Slice(slice), None) = (type_ref.elem.as_ref(), receiver_mut) { + let field_type = slice.elem.as_ref().clone(); + + Ok((field_type, FieldMode::Slice)) + } else { + let field_type = type_ref.elem.as_ref().clone(); + + Ok((field_type, FieldMode::Reference)) + } + } + Type::Path(type_path) => { + if let Some(field_type) = try_parse_option_ref(type_path) { + Ok(( + parse2(quote! { Option< #field_type > })?, + FieldMode::OptionRef, + )) + } else if let (Some(field_type), None) = (try_parse_mref(type_path), receiver_mut) { + Ok((field_type.clone(), FieldMode::MRef)) + } else { + Ok((return_type.clone(), FieldMode::Copy)) + } + } + _ => Err(Error::new( + return_type.span(), + "return type must be a reference", + )), + } +} + +fn try_parse_option_ref(type_path: &TypePath) -> Option<&Type> { + let segment = parse_single_segment_type_path(type_path).ok()?; + + if segment.ident == "Option" + && let PathArguments::AngleBracketed(args) = &segment.arguments + { + let [arg] = Vec::from_iter(args.args.iter()).try_into().ok()?; + + if let GenericArgument::Type(Type::Reference(type_ref)) = arg { + return Some(type_ref.elem.as_ref()); + } + } + + None +} + +pub fn parse_single_segment_type_path(type_path: &TypePath) -> syn::Result<&PathSegment> { + let [segment]: [&PathSegment; 1] = type_path + .path + .segments + .iter() + .collect::>() + .try_into() + .map_err(|_| { + Error::new( + type_path.span(), + "type path must contain exactly one path segment", + ) + })?; + + Ok(segment) +} + +fn try_parse_mref(type_path: &TypePath) -> Option<&Type> { + let segment = parse_single_segment_type_path(type_path).ok()?; + + if segment.ident == "MRef" + && let PathArguments::AngleBracketed(args) = &segment.arguments + { + let [arg1, arg2] = Vec::from_iter(args.args.iter()).try_into().ok()?; + + if let (GenericArgument::Lifetime(_), GenericArgument::Type(ty)) = (arg1, arg2) { + return Some(ty); + } + } + + None +} diff --git a/crates/cgp-macro-core/src/functions/merge_generics.rs b/crates/cgp-macro-core/src/functions/generics/merge_generics.rs similarity index 100% rename from crates/cgp-macro-core/src/functions/merge_generics.rs rename to crates/cgp-macro-core/src/functions/generics/merge_generics.rs diff --git a/crates/cgp-macro-core/src/functions/generics/mod.rs b/crates/cgp-macro-core/src/functions/generics/mod.rs new file mode 100644 index 00000000..f5b39fc2 --- /dev/null +++ b/crates/cgp-macro-core/src/functions/generics/mod.rs @@ -0,0 +1,3 @@ +mod merge_generics; + +pub use merge_generics::*; diff --git a/crates/cgp-macro-core/src/functions/mod.rs b/crates/cgp-macro-core/src/functions/mod.rs index 51e0278e..5870694a 100644 --- a/crates/cgp-macro-core/src/functions/mod.rs +++ b/crates/cgp-macro-core/src/functions/mod.rs @@ -1,5 +1,7 @@ -mod merge_generics; +mod field; +mod generics; mod snake_case; -pub use merge_generics::*; +pub use field::*; +pub use generics::*; pub use snake_case::*; diff --git a/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs b/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs index a46a13b7..2d4cb5c6 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs @@ -1,13 +1,12 @@ use std::mem; +use cgp_macro_core::functions::parse_field_type; use cgp_macro_core::types::implicits::{ImplicitArgField, ImplicitArgFields}; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::visit::{self, Visit}; use syn::{Attribute, FnArg, Meta, Pat, PatIdent, PatType, Receiver}; -use crate::derive_getter::parse_field_type; - pub fn extract_and_parse_implicit_args( args: &mut Punctuated, ) -> syn::Result { diff --git a/crates/cgp-macro-lib/src/derive_getter/parse.rs b/crates/cgp-macro-lib/src/derive_getter/parse.rs index aad8ec54..76aab53b 100644 --- a/crates/cgp-macro-lib/src/derive_getter/parse.rs +++ b/crates/cgp-macro-lib/src/derive_getter/parse.rs @@ -1,15 +1,14 @@ use alloc::vec::Vec; -use cgp_macro_core::types::getter::FieldMode; +use cgp_macro_core::functions::{parse_field_type, parse_single_segment_type_path}; use cgp_macro_core::visitors::ReplaceSelfTypeVisitor; -use quote::{ToTokens, quote}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::token::{Comma, Mut}; use syn::visit_mut::VisitMut; use syn::{ Error, FnArg, GenericArgument, Ident, ItemTrait, PathArguments, PathSegment, ReturnType, - Signature, TraitItem, TraitItemFn, TraitItemType, Type, TypePath, parse_quote, parse2, + Signature, TraitItem, TraitItemFn, TraitItemType, Type, parse_quote, }; use crate::derive_getter::ReceiverMode; @@ -272,74 +271,6 @@ fn parse_return_type( } } -pub fn parse_field_type( - return_type: &Type, - receiver_mut: &Option, -) -> syn::Result<(Type, FieldMode)> { - match &return_type { - Type::Reference(type_ref) => { - if type_ref.mutability.is_some() && receiver_mut.is_none() { - return Err(Error::new( - type_ref.span(), - format!( - "&mut self is required for mutable field reference `{}`", - type_ref.to_token_stream() - ), - )); - } - - if type_ref.elem.as_ref() == &parse_quote! { str } { - // Special case to handle &str as String field - - let field_type: Type = parse_quote! { String }; - - Ok((field_type, FieldMode::Str)) - } else if let (Type::Slice(slice), None) = (type_ref.elem.as_ref(), receiver_mut) { - let field_type = slice.elem.as_ref().clone(); - - Ok((field_type, FieldMode::Slice)) - } else { - let field_type = type_ref.elem.as_ref().clone(); - - Ok((field_type, FieldMode::Reference)) - } - } - Type::Path(type_path) => { - if let Some(field_type) = try_parse_option_ref(type_path) { - Ok(( - parse2(quote! { Option< #field_type > })?, - FieldMode::OptionRef, - )) - } else if let (Some(field_type), None) = (try_parse_mref(type_path), receiver_mut) { - Ok((field_type.clone(), FieldMode::MRef)) - } else { - Ok((return_type.clone(), FieldMode::Copy)) - } - } - _ => Err(Error::new( - return_type.span(), - "return type must be a reference", - )), - } -} - -fn parse_single_segment_type_path(type_path: &TypePath) -> syn::Result<&PathSegment> { - let [segment]: [&PathSegment; 1] = type_path - .path - .segments - .iter() - .collect::>() - .try_into() - .map_err(|_| { - Error::new( - type_path.span(), - "type path must contain exactly one path segment", - ) - })?; - - Ok(segment) -} - fn try_parse_phantom_arg_type_path(segment: &PathSegment) -> Option { if segment.ident == "PhantomData" && let PathArguments::AngleBracketed(args) = &segment.arguments @@ -350,35 +281,3 @@ fn try_parse_phantom_arg_type_path(segment: &PathSegment) -> Option { None } - -fn try_parse_option_ref(type_path: &TypePath) -> Option<&Type> { - let segment = parse_single_segment_type_path(type_path).ok()?; - - if segment.ident == "Option" - && let PathArguments::AngleBracketed(args) = &segment.arguments - { - let [arg] = Vec::from_iter(args.args.iter()).try_into().ok()?; - - if let GenericArgument::Type(Type::Reference(type_ref)) = arg { - return Some(type_ref.elem.as_ref()); - } - } - - None -} - -fn try_parse_mref(type_path: &TypePath) -> Option<&Type> { - let segment = parse_single_segment_type_path(type_path).ok()?; - - if segment.ident == "MRef" - && let PathArguments::AngleBracketed(args) = &segment.arguments - { - let [arg1, arg2] = Vec::from_iter(args.args.iter()).try_into().ok()?; - - if let (GenericArgument::Lifetime(_), GenericArgument::Type(ty)) = (arg1, arg2) { - return Some(ty); - } - } - - None -} From 82d50bf1ce7f0602d672312311112b9bcfb8f855 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 3 Jun 2026 22:02:33 +0200 Subject: [PATCH 24/46] Move implicit functions --- .../src/functions/implicits/extract.rs} | 4 ++-- crates/cgp-macro-core/src/functions/implicits/mod.rs | 5 +++++ .../src/functions/implicits/parse.rs} | 5 +++-- crates/cgp-macro-core/src/functions/mod.rs | 2 ++ crates/cgp-macro-lib/src/cgp_fn/derive.rs | 3 ++- crates/cgp-macro-lib/src/cgp_fn/mod.rs | 2 -- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 2 +- crates/cgp-macro-lib/src/cgp_impl/mod.rs | 1 - 8 files changed, 15 insertions(+), 9 deletions(-) rename crates/{cgp-macro-lib/src/cgp_impl/implicit_args.rs => cgp-macro-core/src/functions/implicits/extract.rs} (85%) create mode 100644 crates/cgp-macro-core/src/functions/implicits/mod.rs rename crates/{cgp-macro-lib/src/cgp_fn/parse_implicits.rs => cgp-macro-core/src/functions/implicits/parse.rs} (96%) diff --git a/crates/cgp-macro-lib/src/cgp_impl/implicit_args.rs b/crates/cgp-macro-core/src/functions/implicits/extract.rs similarity index 85% rename from crates/cgp-macro-lib/src/cgp_impl/implicit_args.rs rename to crates/cgp-macro-core/src/functions/implicits/extract.rs index 8de70cca..7527fd38 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/implicit_args.rs +++ b/crates/cgp-macro-core/src/functions/implicits/extract.rs @@ -1,7 +1,7 @@ -use cgp_macro_core::types::implicits::ImplicitArgFields; use syn::ImplItem; -use crate::cgp_fn::extract_and_parse_implicit_args; +use crate::functions::extract_and_parse_implicit_args; +use crate::types::implicits::ImplicitArgFields; pub fn extract_implicit_args_from_impl_items( impl_items: &mut [ImplItem], diff --git a/crates/cgp-macro-core/src/functions/implicits/mod.rs b/crates/cgp-macro-core/src/functions/implicits/mod.rs new file mode 100644 index 00000000..ab19c84d --- /dev/null +++ b/crates/cgp-macro-core/src/functions/implicits/mod.rs @@ -0,0 +1,5 @@ +mod extract; +mod parse; + +pub use extract::*; +pub use parse::*; diff --git a/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs b/crates/cgp-macro-core/src/functions/implicits/parse.rs similarity index 96% rename from crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs rename to crates/cgp-macro-core/src/functions/implicits/parse.rs index 2d4cb5c6..d62b3e25 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/parse_implicits.rs +++ b/crates/cgp-macro-core/src/functions/implicits/parse.rs @@ -1,12 +1,13 @@ use std::mem; -use cgp_macro_core::functions::parse_field_type; -use cgp_macro_core::types::implicits::{ImplicitArgField, ImplicitArgFields}; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::visit::{self, Visit}; use syn::{Attribute, FnArg, Meta, Pat, PatIdent, PatType, Receiver}; +use crate::functions::parse_field_type; +use crate::types::implicits::{ImplicitArgField, ImplicitArgFields}; + pub fn extract_and_parse_implicit_args( args: &mut Punctuated, ) -> syn::Result { diff --git a/crates/cgp-macro-core/src/functions/mod.rs b/crates/cgp-macro-core/src/functions/mod.rs index 5870694a..1de543ee 100644 --- a/crates/cgp-macro-core/src/functions/mod.rs +++ b/crates/cgp-macro-core/src/functions/mod.rs @@ -1,7 +1,9 @@ mod field; mod generics; +mod implicits; mod snake_case; pub use field::*; pub use generics::*; +pub use implicits::*; pub use snake_case::*; diff --git a/crates/cgp-macro-lib/src/cgp_fn/derive.rs b/crates/cgp-macro-lib/src/cgp_fn/derive.rs index 33477329..82ab9426 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/derive.rs @@ -1,12 +1,13 @@ use core::mem; +use cgp_macro_core::functions::extract_and_parse_implicit_args; use proc_macro2::TokenStream; use quote::quote; use syn::{Ident, ItemFn, Visibility}; use crate::cgp_fn::item_impl::derive_item_impl; use crate::cgp_fn::item_trait::derive_item_trait; -use crate::cgp_fn::{extract_and_parse_implicit_args, parse_function_attributes}; +use crate::cgp_fn::parse_function_attributes; pub fn derive_cgp_fn(trait_ident: &Ident, mut item_fn: ItemFn) -> syn::Result { let visibility = item_fn.vis.clone(); diff --git a/crates/cgp-macro-lib/src/cgp_fn/mod.rs b/crates/cgp-macro-lib/src/cgp_fn/mod.rs index 9882de91..2ab8bbbd 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/mod.rs @@ -3,7 +3,6 @@ mod attributes; mod derive; mod item_impl; mod item_trait; -mod parse_implicits; mod spec; mod substitute_type; mod type_predicates; @@ -12,7 +11,6 @@ pub use apply_type::*; pub use attributes::*; pub use derive::*; pub use item_trait::*; -pub use parse_implicits::*; pub use spec::*; pub use substitute_type::*; pub use type_predicates::*; diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index 39061860..038540a0 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -1,3 +1,4 @@ +use cgp_macro_core::functions::extract_implicit_args_from_impl_items; use cgp_macro_core::types::attributes::ImplAttributes; use cgp_macro_core::types::cgp_impl::ImplArgs; use proc_macro2::TokenStream; @@ -9,7 +10,6 @@ use syn::{Error, ItemImpl, TypeParamBound, parse_quote, parse2}; use crate::cgp_fn::apply_use_type_attributes_to_item_impl; use crate::cgp_impl::derive_provider_impl; -use crate::cgp_impl::implicit_args::extract_implicit_args_from_impl_items; use crate::cgp_impl::provider_bounds::derive_provider_bounds; use crate::derive_provider::{ derive_component_name_from_provider_impl, derive_is_provider_for, derive_provider_struct, diff --git a/crates/cgp-macro-lib/src/cgp_impl/mod.rs b/crates/cgp-macro-lib/src/cgp_impl/mod.rs index a83db139..50ac6b4e 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/mod.rs @@ -1,5 +1,4 @@ mod derive; -mod implicit_args; mod provider_bounds; mod provider_impl; mod transform; From ddf3df99b922314a431c1bd54dd8735703aad7c6 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 3 Jun 2026 23:40:57 +0200 Subject: [PATCH 25/46] Implement SubstituteAbstractType visitor --- .../src/types/attributes/impl_attributes.rs | 6 +- .../src/types/attributes/use_type.rs | 23 ++++++- crates/cgp-macro-core/src/visitors/mod.rs | 2 + .../src/visitors/substitute_abstract_type.rs | 27 ++++++++ crates/cgp-macro-lib/src/cgp_fn/apply_type.rs | 22 +++--- crates/cgp-macro-lib/src/cgp_fn/attributes.rs | 2 +- crates/cgp-macro-lib/src/cgp_fn/item_impl.rs | 4 +- crates/cgp-macro-lib/src/cgp_fn/item_trait.rs | 23 +++---- crates/cgp-macro-lib/src/cgp_fn/mod.rs | 2 - crates/cgp-macro-lib/src/cgp_fn/spec.rs | 4 +- .../src/cgp_fn/substitute_type.rs | 67 ------------------- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 4 +- .../src/derive_component/attributes.rs | 6 +- .../src/derive_component/preprocess.rs | 5 +- 14 files changed, 85 insertions(+), 112 deletions(-) create mode 100644 crates/cgp-macro-core/src/visitors/substitute_abstract_type.rs delete mode 100644 crates/cgp-macro-lib/src/cgp_fn/substitute_type.rs diff --git a/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs b/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs index 22d5c971..9bea0539 100644 --- a/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs +++ b/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs @@ -2,13 +2,13 @@ use syn::Attribute; use syn::punctuated::Punctuated; use syn::token::Comma; -use crate::types::attributes::{UseProviderAttribute, UseTypeAttribute}; +use crate::types::attributes::{UseProviderAttribute, UseTypeAttribute, UseTypeAttributes}; use crate::types::ident::IdentWithTypeArgs; #[derive(Default)] pub struct ImplAttributes { pub uses: Vec, - pub use_type: Vec, + pub use_type: UseTypeAttributes, pub use_provider: Vec, pub raw_attributes: Vec, } @@ -32,7 +32,7 @@ impl ImplAttributes { Punctuated::::parse_terminated, )?; - parsed_attributes.use_type.extend(use_type); + parsed_attributes.use_type.attributes.extend(use_type); } "use_provider" => { let use_provider = attribute.parse_args_with( diff --git a/crates/cgp-macro-core/src/types/attributes/use_type.rs b/crates/cgp-macro-core/src/types/attributes/use_type.rs index 250ca7aa..df524fa8 100644 --- a/crates/cgp-macro-core/src/types/attributes/use_type.rs +++ b/crates/cgp-macro-core/src/types/attributes/use_type.rs @@ -1,8 +1,15 @@ use syn::parse::{Parse, ParseStream}; use syn::token::{As, At, Brace, Colon, Comma, Eq, Gt, Lt}; -use syn::{Ident, Type, braced, parse_quote}; +use syn::visit_mut::VisitMut; +use syn::{Ident, ItemImpl, ItemTrait, Type, braced, parse_quote}; use crate::types::ident::IdentWithTypeArgs; +use crate::visitors::SubstituteAbstractType; + +#[derive(Default)] +pub struct UseTypeAttributes { + pub attributes: Vec, +} pub struct UseTypeAttribute { pub context_type: Type, @@ -16,6 +23,20 @@ pub struct UseTypeIdent { pub equals: Option, } +impl UseTypeAttributes { + pub fn substitute_abstract_types_in_item_trait(&self, item_trait: &mut ItemTrait) { + for type_spec in self.attributes.iter().rev() { + SubstituteAbstractType { type_spec }.visit_item_trait_mut(item_trait); + } + } + + pub fn substitute_abstract_types_in_item_impl(&self, item_impl: &mut ItemImpl) { + for type_spec in self.attributes.iter().rev() { + SubstituteAbstractType { type_spec }.visit_item_impl_mut(item_impl); + } + } +} + impl UseTypeAttribute { pub fn replace_ident(&self, ident: &Ident) -> Option { for type_ident in &self.type_idents { diff --git a/crates/cgp-macro-core/src/visitors/mod.rs b/crates/cgp-macro-core/src/visitors/mod.rs index 8b8ab8da..3a45b6f6 100644 --- a/crates/cgp-macro-core/src/visitors/mod.rs +++ b/crates/cgp-macro-core/src/visitors/mod.rs @@ -1,3 +1,5 @@ mod replace_self; +mod substitute_abstract_type; pub use replace_self::*; +pub use substitute_abstract_type::*; diff --git a/crates/cgp-macro-core/src/visitors/substitute_abstract_type.rs b/crates/cgp-macro-core/src/visitors/substitute_abstract_type.rs new file mode 100644 index 00000000..6a1e42f6 --- /dev/null +++ b/crates/cgp-macro-core/src/visitors/substitute_abstract_type.rs @@ -0,0 +1,27 @@ +use syn::visit_mut::VisitMut; +use syn::{PathArguments, Type, TypePath, parse_quote, visit_mut}; + +use crate::types::attributes::UseTypeAttribute; + +pub struct SubstituteAbstractType<'a> { + pub type_spec: &'a UseTypeAttribute, +} + +impl VisitMut for SubstituteAbstractType<'_> { + fn visit_type_mut(&mut self, ty: &mut Type) { + if let Type::Path(TypePath { qself: None, path }) = ty { + if path.leading_colon.is_none() && path.segments.len() == 1 { + let segment = &path.segments[0]; + if matches!(segment.arguments, PathArguments::None) { + if let Some(replacement_ident) = self.type_spec.replace_ident(&segment.ident) { + let trait_path = &self.type_spec.trait_path; + let context_type = &self.type_spec.context_type; + *ty = parse_quote! { <#context_type as #trait_path>::#replacement_ident }; + return; + } + } + } + } + visit_mut::visit_type_mut(self, ty); + } +} diff --git a/crates/cgp-macro-lib/src/cgp_fn/apply_type.rs b/crates/cgp-macro-lib/src/cgp_fn/apply_type.rs index 7b9812a9..b1ddbf5b 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/apply_type.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/apply_type.rs @@ -1,19 +1,15 @@ -use cgp_macro_core::types::attributes::UseTypeAttribute; -use quote::ToTokens; -use syn::{ItemImpl, parse2}; +use cgp_macro_core::types::attributes::UseTypeAttributes; +use syn::ItemImpl; -use crate::cgp_fn::{derive_use_type_predicates, substitute_abstract_types}; +use crate::cgp_fn::derive_use_type_predicates; pub fn apply_use_type_attributes_to_item_impl( - item_impl: &ItemImpl, - use_type_specs: &[UseTypeAttribute], -) -> syn::Result { - let mut item_impl: ItemImpl = parse2(substitute_abstract_types( - use_type_specs, - item_impl.to_token_stream(), - ))?; + item_impl: &mut ItemImpl, + use_type_specs: &UseTypeAttributes, +) -> syn::Result<()> { + use_type_specs.substitute_abstract_types_in_item_impl(item_impl); - let predicates = derive_use_type_predicates(use_type_specs)?; + let predicates = derive_use_type_predicates(&use_type_specs.attributes)?; item_impl .generics @@ -21,5 +17,5 @@ pub fn apply_use_type_attributes_to_item_impl( .predicates .extend(predicates); - Ok(item_impl) + Ok(()) } diff --git a/crates/cgp-macro-lib/src/cgp_fn/attributes.rs b/crates/cgp-macro-lib/src/cgp_fn/attributes.rs index b6b52e4d..be293325 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/attributes.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/attributes.rs @@ -33,7 +33,7 @@ pub fn parse_function_attributes( let use_type = attribute .parse_args_with(Punctuated::::parse_terminated)?; - parsed_attributes.use_type.extend(use_type); + parsed_attributes.use_type.attributes.extend(use_type); } else if ident == "use_provider" { let use_provider = attribute .parse_args_with(Punctuated::::parse_terminated)?; diff --git a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs index da6ef49c..2fccac0f 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs @@ -69,8 +69,8 @@ pub fn derive_item_impl( })?); } - if !attributes.use_type.is_empty() { - item_impl = apply_use_type_attributes_to_item_impl(&item_impl, &attributes.use_type)?; + if !attributes.use_type.attributes.is_empty() { + apply_use_type_attributes_to_item_impl(&mut item_impl, &attributes.use_type)?; } if !attributes.use_provider.is_empty() { diff --git a/crates/cgp-macro-lib/src/cgp_fn/item_trait.rs b/crates/cgp-macro-lib/src/cgp_fn/item_trait.rs index 291e2d0b..e8951233 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_trait.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_trait.rs @@ -1,8 +1,8 @@ -use cgp_macro_core::types::attributes::UseTypeAttribute; +use cgp_macro_core::types::attributes::UseTypeAttributes; use quote::{ToTokens, quote}; use syn::{Generics, Ident, ItemFn, ItemTrait, TraitItemFn, parse_quote, parse2}; -use crate::cgp_fn::{FunctionAttributes, substitute_abstract_types}; +use crate::cgp_fn::FunctionAttributes; pub fn derive_item_trait( trait_ident: &Ident, @@ -36,23 +36,20 @@ pub fn derive_item_trait( .extend(attributes.extend_where.clone()); } - if !attributes.use_type.is_empty() { - item_trait = expand_use_type_attributes_on_trait(&item_trait, &attributes.use_type)?; + if !attributes.use_type.attributes.is_empty() { + expand_use_type_attributes_on_trait(&mut item_trait, &attributes.use_type)?; } Ok(item_trait) } pub fn expand_use_type_attributes_on_trait( - item_trait: &ItemTrait, - use_type_specs: &[UseTypeAttribute], -) -> syn::Result { - let mut item_trait: ItemTrait = parse2(substitute_abstract_types( - use_type_specs, - item_trait.to_token_stream(), - ))?; + item_trait: &mut ItemTrait, + use_type_specs: &UseTypeAttributes, +) -> syn::Result<()> { + use_type_specs.substitute_abstract_types_in_item_trait(item_trait); - for use_type in use_type_specs.iter() { + for use_type in use_type_specs.attributes.iter() { if use_type.context_type != parse_quote! { Self } { continue; } @@ -62,5 +59,5 @@ pub fn expand_use_type_attributes_on_trait( .push(parse2(use_type.trait_path.to_token_stream())?); } - Ok(item_trait) + Ok(()) } diff --git a/crates/cgp-macro-lib/src/cgp_fn/mod.rs b/crates/cgp-macro-lib/src/cgp_fn/mod.rs index 2ab8bbbd..7570a86c 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/mod.rs @@ -4,7 +4,6 @@ mod derive; mod item_impl; mod item_trait; mod spec; -mod substitute_type; mod type_predicates; pub use apply_type::*; @@ -12,5 +11,4 @@ pub use attributes::*; pub use derive::*; pub use item_trait::*; pub use spec::*; -pub use substitute_type::*; pub use type_predicates::*; diff --git a/crates/cgp-macro-lib/src/cgp_fn/spec.rs b/crates/cgp-macro-lib/src/cgp_fn/spec.rs index 8c1cf8c8..de20413b 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/spec.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/spec.rs @@ -1,4 +1,4 @@ -use cgp_macro_core::types::attributes::{UseProviderAttribute, UseTypeAttribute}; +use cgp_macro_core::types::attributes::{UseProviderAttribute, UseTypeAttributes}; use cgp_macro_core::types::ident::IdentWithTypeArgs; use syn::{GenericParam, TypeParamBound, WherePredicate}; @@ -7,7 +7,7 @@ pub struct FunctionAttributes { pub extend: Vec, pub extend_where: Vec, pub uses: Vec, - pub use_type: Vec, + pub use_type: UseTypeAttributes, pub use_provider: Vec, pub impl_generics: Vec, } diff --git a/crates/cgp-macro-lib/src/cgp_fn/substitute_type.rs b/crates/cgp-macro-lib/src/cgp_fn/substitute_type.rs deleted file mode 100644 index ec28b696..00000000 --- a/crates/cgp-macro-lib/src/cgp_fn/substitute_type.rs +++ /dev/null @@ -1,67 +0,0 @@ -use cgp_macro_core::types::attributes::UseTypeAttribute; -use proc_macro2::{Group, TokenStream, TokenTree}; -use quote::quote; - -pub fn substitute_abstract_types( - type_specs: &[UseTypeAttribute], - body: TokenStream, -) -> TokenStream { - let mut out = body; - for spec in type_specs.iter().rev() { - out = substitute_abstract_type(spec, out); - } - out -} - -pub fn substitute_abstract_type(type_specs: &UseTypeAttribute, body: TokenStream) -> TokenStream { - let mut out = TokenStream::new(); - let mut last_token_was_colon = false; - let mut last_two_tokens_was_colon = false; - - for token_tree in body.into_iter() { - let token_is_colon = if let TokenTree::Punct(punct) = &token_tree - && punct.as_char() == ':' - { - true - } else { - false - }; - - match token_tree { - TokenTree::Group(group) => { - let new_stream = substitute_abstract_type(type_specs, group.stream()); - out.extend([TokenTree::Group(Group::new(group.delimiter(), new_stream))]); - } - TokenTree::Ident(ident) => { - if !last_two_tokens_was_colon - && let Some(replacement_ident) = type_specs.replace_ident(&ident) - { - let trait_path = &type_specs.trait_path; - let context_type = &type_specs.context_type; - - out.extend(quote! { - < #context_type as #trait_path > :: #replacement_ident - }); - } else { - out.extend([TokenTree::Ident(ident)]); - } - } - TokenTree::Punct(punct) => { - out.extend([TokenTree::Punct(punct)]); - } - TokenTree::Literal(literal) => { - out.extend([TokenTree::Literal(literal)]); - } - } - - if token_is_colon { - last_two_tokens_was_colon = last_token_was_colon; - last_token_was_colon = true; - } else { - last_two_tokens_was_colon = false; - last_token_was_colon = false; - } - } - - out -} diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index 038540a0..ff1944d9 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -30,8 +30,8 @@ pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result, - pub use_type: Vec, + pub use_type: UseTypeAttributes, pub namespace: Vec, } diff --git a/crates/cgp-macro-lib/src/derive_component/preprocess.rs b/crates/cgp-macro-lib/src/derive_component/preprocess.rs index 26d14ca6..ac03eca9 100644 --- a/crates/cgp-macro-lib/src/derive_component/preprocess.rs +++ b/crates/cgp-macro-lib/src/derive_component/preprocess.rs @@ -9,9 +9,8 @@ pub fn preprocess_consumer_trait( ) -> syn::Result<()> { consumer_trait.supertraits.extend(attributes.extend.clone()); - if !attributes.use_type.is_empty() { - *consumer_trait = - expand_use_type_attributes_on_trait(consumer_trait, &attributes.use_type)?; + if !attributes.use_type.attributes.is_empty() { + expand_use_type_attributes_on_trait(consumer_trait, &attributes.use_type)?; } Ok(()) From 6cf76ebc7244ece8348fbf9c302d3b85c4508cea Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 3 Jun 2026 23:47:24 +0200 Subject: [PATCH 26/46] Reorganize UseTypeAttribute constructs --- .../{use_type.rs => use_type/attribute.rs} | 64 +------------------ .../types/attributes/use_type/attributes.rs | 28 ++++++++ .../src/types/attributes/use_type/ident.rs | 41 ++++++++++++ .../src/types/attributes/use_type/mod.rs | 7 ++ .../src/cgp_fn/type_predicates.rs | 2 +- 5 files changed, 80 insertions(+), 62 deletions(-) rename crates/cgp-macro-core/src/types/attributes/{use_type.rs => use_type/attribute.rs} (57%) create mode 100644 crates/cgp-macro-core/src/types/attributes/use_type/attributes.rs create mode 100644 crates/cgp-macro-core/src/types/attributes/use_type/ident.rs create mode 100644 crates/cgp-macro-core/src/types/attributes/use_type/mod.rs diff --git a/crates/cgp-macro-core/src/types/attributes/use_type.rs b/crates/cgp-macro-core/src/types/attributes/use_type/attribute.rs similarity index 57% rename from crates/cgp-macro-core/src/types/attributes/use_type.rs rename to crates/cgp-macro-core/src/types/attributes/use_type/attribute.rs index df524fa8..735aa0ec 100644 --- a/crates/cgp-macro-core/src/types/attributes/use_type.rs +++ b/crates/cgp-macro-core/src/types/attributes/use_type/attribute.rs @@ -1,15 +1,9 @@ use syn::parse::{Parse, ParseStream}; -use syn::token::{As, At, Brace, Colon, Comma, Eq, Gt, Lt}; -use syn::visit_mut::VisitMut; -use syn::{Ident, ItemImpl, ItemTrait, Type, braced, parse_quote}; +use syn::token::{At, Brace, Colon, Comma, Gt, Lt}; +use syn::{Ident, Type, braced, parse_quote}; +use crate::types::attributes::UseTypeIdent; use crate::types::ident::IdentWithTypeArgs; -use crate::visitors::SubstituteAbstractType; - -#[derive(Default)] -pub struct UseTypeAttributes { - pub attributes: Vec, -} pub struct UseTypeAttribute { pub context_type: Type, @@ -17,26 +11,6 @@ pub struct UseTypeAttribute { pub type_idents: Vec, } -pub struct UseTypeIdent { - pub type_ident: Ident, - pub as_alias: Option, - pub equals: Option, -} - -impl UseTypeAttributes { - pub fn substitute_abstract_types_in_item_trait(&self, item_trait: &mut ItemTrait) { - for type_spec in self.attributes.iter().rev() { - SubstituteAbstractType { type_spec }.visit_item_trait_mut(item_trait); - } - } - - pub fn substitute_abstract_types_in_item_impl(&self, item_impl: &mut ItemImpl) { - for type_spec in self.attributes.iter().rev() { - SubstituteAbstractType { type_spec }.visit_item_impl_mut(item_impl); - } - } -} - impl UseTypeAttribute { pub fn replace_ident(&self, ident: &Ident) -> Option { for type_ident in &self.type_idents { @@ -51,12 +25,6 @@ impl UseTypeAttribute { } } -impl UseTypeIdent { - pub fn alias_ident(&self) -> &Ident { - self.as_alias.as_ref().unwrap_or(&self.type_ident) - } -} - impl Parse for UseTypeAttribute { fn parse(input: ParseStream) -> syn::Result { let body; @@ -115,29 +83,3 @@ impl Parse for UseTypeAttribute { }) } } - -impl Parse for UseTypeIdent { - fn parse(input: ParseStream) -> syn::Result { - let type_ident: Ident = input.parse()?; - - let as_alias = if input.peek(As) { - let _: As = input.parse()?; - Some(input.parse()?) - } else { - None - }; - - let equals = if input.peek(Eq) { - let _: Eq = input.parse()?; - Some(input.parse()?) - } else { - None - }; - - Ok(Self { - type_ident, - as_alias, - equals, - }) - } -} diff --git a/crates/cgp-macro-core/src/types/attributes/use_type/attributes.rs b/crates/cgp-macro-core/src/types/attributes/use_type/attributes.rs new file mode 100644 index 00000000..a6f2f7cc --- /dev/null +++ b/crates/cgp-macro-core/src/types/attributes/use_type/attributes.rs @@ -0,0 +1,28 @@ +use syn::visit_mut::VisitMut; +use syn::{ItemImpl, ItemTrait}; + +use crate::types::attributes::UseTypeAttribute; +use crate::visitors::SubstituteAbstractType; + +#[derive(Default)] +pub struct UseTypeAttributes { + pub attributes: Vec, +} + +impl UseTypeAttributes { + pub fn substitute_abstract_types_in_item_trait(&self, item_trait: &mut ItemTrait) { + for type_spec in self.attributes.iter().rev() { + SubstituteAbstractType { type_spec }.visit_item_trait_mut(item_trait); + } + } + + pub fn substitute_abstract_types_in_item_impl(&self, item_impl: &mut ItemImpl) { + for type_spec in self.attributes.iter().rev() { + SubstituteAbstractType { type_spec }.visit_item_impl_mut(item_impl); + } + } + + // pub fn transform_item_impl(&self, item_impl: &mut ItemImpl) { + + // } +} diff --git a/crates/cgp-macro-core/src/types/attributes/use_type/ident.rs b/crates/cgp-macro-core/src/types/attributes/use_type/ident.rs new file mode 100644 index 00000000..cc3edaf2 --- /dev/null +++ b/crates/cgp-macro-core/src/types/attributes/use_type/ident.rs @@ -0,0 +1,41 @@ +use syn::parse::{Parse, ParseStream}; +use syn::token::{As, Eq}; +use syn::{Ident, Type}; + +pub struct UseTypeIdent { + pub type_ident: Ident, + pub as_alias: Option, + pub equals: Option, +} + +impl UseTypeIdent { + pub fn alias_ident(&self) -> &Ident { + self.as_alias.as_ref().unwrap_or(&self.type_ident) + } +} + +impl Parse for UseTypeIdent { + fn parse(input: ParseStream) -> syn::Result { + let type_ident: Ident = input.parse()?; + + let as_alias = if input.peek(As) { + let _: As = input.parse()?; + Some(input.parse()?) + } else { + None + }; + + let equals = if input.peek(Eq) { + let _: Eq = input.parse()?; + Some(input.parse()?) + } else { + None + }; + + Ok(Self { + type_ident, + as_alias, + equals, + }) + } +} diff --git a/crates/cgp-macro-core/src/types/attributes/use_type/mod.rs b/crates/cgp-macro-core/src/types/attributes/use_type/mod.rs new file mode 100644 index 00000000..9657666f --- /dev/null +++ b/crates/cgp-macro-core/src/types/attributes/use_type/mod.rs @@ -0,0 +1,7 @@ +mod attribute; +mod attributes; +mod ident; + +pub use attribute::*; +pub use attributes::*; +pub use ident::*; diff --git a/crates/cgp-macro-lib/src/cgp_fn/type_predicates.rs b/crates/cgp-macro-lib/src/cgp_fn/type_predicates.rs index 13b5d718..b41d48d2 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/type_predicates.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/type_predicates.rs @@ -66,7 +66,7 @@ fn find_type_alias(specs: &[UseTypeAttribute], context_type: &Type) -> syn::Resu Ok(None) } -pub fn find_type_equalities( +fn find_type_equalities( current_spec: &UseTypeAttribute, specs: &[UseTypeAttribute], ) -> syn::Result> { From 7488e8075ba6db49b0f33f3f394983cf28e7bba9 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 3 Jun 2026 23:55:10 +0200 Subject: [PATCH 27/46] Implement transform_item_trait and transform_item_impl for UseTypeAttributes --- .../types/attributes/use_type/attributes.rs | 42 +++++++++++++++++-- .../src/types/attributes/use_type/mod.rs | 1 + .../attributes/use_type}/type_predicates.rs | 3 +- crates/cgp-macro-lib/src/cgp_fn/apply_type.rs | 21 ---------- crates/cgp-macro-lib/src/cgp_fn/item_impl.rs | 6 +-- crates/cgp-macro-lib/src/cgp_fn/item_trait.rs | 28 ++----------- crates/cgp-macro-lib/src/cgp_fn/mod.rs | 5 --- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 5 +-- .../src/derive_component/preprocess.rs | 5 +-- 9 files changed, 49 insertions(+), 67 deletions(-) rename crates/{cgp-macro-lib/src/cgp_fn => cgp-macro-core/src/types/attributes/use_type}/type_predicates.rs (98%) delete mode 100644 crates/cgp-macro-lib/src/cgp_fn/apply_type.rs diff --git a/crates/cgp-macro-core/src/types/attributes/use_type/attributes.rs b/crates/cgp-macro-core/src/types/attributes/use_type/attributes.rs index a6f2f7cc..34cef7a4 100644 --- a/crates/cgp-macro-core/src/types/attributes/use_type/attributes.rs +++ b/crates/cgp-macro-core/src/types/attributes/use_type/attributes.rs @@ -1,7 +1,9 @@ +use quote::ToTokens; use syn::visit_mut::VisitMut; -use syn::{ItemImpl, ItemTrait}; +use syn::{ItemImpl, ItemTrait, parse_quote, parse2}; use crate::types::attributes::UseTypeAttribute; +use crate::types::attributes::use_type::type_predicates::derive_use_type_predicates; use crate::visitors::SubstituteAbstractType; #[derive(Default)] @@ -22,7 +24,41 @@ impl UseTypeAttributes { } } - // pub fn transform_item_impl(&self, item_impl: &mut ItemImpl) { + pub fn transform_item_trait(&self, item_trait: &mut ItemTrait) -> syn::Result<()> { + if self.attributes.is_empty() { + return Ok(()); + } + + self.substitute_abstract_types_in_item_trait(item_trait); + + for use_type in self.attributes.iter() { + if use_type.context_type != parse_quote! { Self } { + continue; + } + + item_trait + .supertraits + .push(parse2(use_type.trait_path.to_token_stream())?); + } + + Ok(()) + } - // } + pub fn transform_item_impl(&self, item_impl: &mut ItemImpl) -> syn::Result<()> { + if self.attributes.is_empty() { + return Ok(()); + } + + self.substitute_abstract_types_in_item_impl(item_impl); + + let predicates = derive_use_type_predicates(&self.attributes)?; + + item_impl + .generics + .make_where_clause() + .predicates + .extend(predicates); + + Ok(()) + } } diff --git a/crates/cgp-macro-core/src/types/attributes/use_type/mod.rs b/crates/cgp-macro-core/src/types/attributes/use_type/mod.rs index 9657666f..be818cb8 100644 --- a/crates/cgp-macro-core/src/types/attributes/use_type/mod.rs +++ b/crates/cgp-macro-core/src/types/attributes/use_type/mod.rs @@ -1,6 +1,7 @@ mod attribute; mod attributes; mod ident; +mod type_predicates; pub use attribute::*; pub use attributes::*; diff --git a/crates/cgp-macro-lib/src/cgp_fn/type_predicates.rs b/crates/cgp-macro-core/src/types/attributes/use_type/type_predicates.rs similarity index 98% rename from crates/cgp-macro-lib/src/cgp_fn/type_predicates.rs rename to crates/cgp-macro-core/src/types/attributes/use_type/type_predicates.rs index b41d48d2..a10f868e 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/type_predicates.rs +++ b/crates/cgp-macro-core/src/types/attributes/use_type/type_predicates.rs @@ -1,10 +1,11 @@ -use cgp_macro_core::types::attributes::{UseTypeAttribute, UseTypeIdent}; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{Ident, Type, WherePredicate, parse_quote, parse2}; +use crate::types::attributes::{UseTypeAttribute, UseTypeIdent}; + pub fn derive_use_type_predicates(specs: &[UseTypeAttribute]) -> syn::Result> { let mut predicates = Vec::new(); diff --git a/crates/cgp-macro-lib/src/cgp_fn/apply_type.rs b/crates/cgp-macro-lib/src/cgp_fn/apply_type.rs deleted file mode 100644 index b1ddbf5b..00000000 --- a/crates/cgp-macro-lib/src/cgp_fn/apply_type.rs +++ /dev/null @@ -1,21 +0,0 @@ -use cgp_macro_core::types::attributes::UseTypeAttributes; -use syn::ItemImpl; - -use crate::cgp_fn::derive_use_type_predicates; - -pub fn apply_use_type_attributes_to_item_impl( - item_impl: &mut ItemImpl, - use_type_specs: &UseTypeAttributes, -) -> syn::Result<()> { - use_type_specs.substitute_abstract_types_in_item_impl(item_impl); - - let predicates = derive_use_type_predicates(&use_type_specs.attributes)?; - - item_impl - .generics - .make_where_clause() - .predicates - .extend(predicates); - - Ok(()) -} diff --git a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs index 2fccac0f..d072db3a 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs @@ -4,7 +4,7 @@ use syn::punctuated::Punctuated; use syn::token::Plus; use syn::{Generics, Ident, ItemFn, ItemImpl, TypeParamBound, parse_quote, parse2}; -use crate::cgp_fn::{FunctionAttributes, apply_use_type_attributes_to_item_impl}; +use crate::cgp_fn::FunctionAttributes; use crate::cgp_impl::derive_provider_bounds; pub fn derive_item_impl( @@ -69,9 +69,7 @@ pub fn derive_item_impl( })?); } - if !attributes.use_type.attributes.is_empty() { - apply_use_type_attributes_to_item_impl(&mut item_impl, &attributes.use_type)?; - } + attributes.use_type.transform_item_impl(&mut item_impl)?; if !attributes.use_provider.is_empty() { let where_clause = item_impl.generics.make_where_clause(); diff --git a/crates/cgp-macro-lib/src/cgp_fn/item_trait.rs b/crates/cgp-macro-lib/src/cgp_fn/item_trait.rs index e8951233..6f04b698 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_trait.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_trait.rs @@ -1,6 +1,5 @@ -use cgp_macro_core::types::attributes::UseTypeAttributes; -use quote::{ToTokens, quote}; -use syn::{Generics, Ident, ItemFn, ItemTrait, TraitItemFn, parse_quote, parse2}; +use quote::quote; +use syn::{Generics, Ident, ItemFn, ItemTrait, TraitItemFn, parse2}; use crate::cgp_fn::FunctionAttributes; @@ -36,28 +35,7 @@ pub fn derive_item_trait( .extend(attributes.extend_where.clone()); } - if !attributes.use_type.attributes.is_empty() { - expand_use_type_attributes_on_trait(&mut item_trait, &attributes.use_type)?; - } + attributes.use_type.transform_item_trait(&mut item_trait)?; Ok(item_trait) } - -pub fn expand_use_type_attributes_on_trait( - item_trait: &mut ItemTrait, - use_type_specs: &UseTypeAttributes, -) -> syn::Result<()> { - use_type_specs.substitute_abstract_types_in_item_trait(item_trait); - - for use_type in use_type_specs.attributes.iter() { - if use_type.context_type != parse_quote! { Self } { - continue; - } - - item_trait - .supertraits - .push(parse2(use_type.trait_path.to_token_stream())?); - } - - Ok(()) -} diff --git a/crates/cgp-macro-lib/src/cgp_fn/mod.rs b/crates/cgp-macro-lib/src/cgp_fn/mod.rs index 7570a86c..27e1f472 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/mod.rs @@ -1,14 +1,9 @@ -mod apply_type; mod attributes; mod derive; mod item_impl; mod item_trait; mod spec; -mod type_predicates; -pub use apply_type::*; pub use attributes::*; pub use derive::*; -pub use item_trait::*; pub use spec::*; -pub use type_predicates::*; diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index ff1944d9..177bd188 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -8,7 +8,6 @@ use syn::spanned::Spanned; use syn::token::Plus; use syn::{Error, ItemImpl, TypeParamBound, parse_quote, parse2}; -use crate::cgp_fn::apply_use_type_attributes_to_item_impl; use crate::cgp_impl::derive_provider_impl; use crate::cgp_impl::provider_bounds::derive_provider_bounds; use crate::derive_provider::{ @@ -30,9 +29,7 @@ pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result = Punctuated::default(); diff --git a/crates/cgp-macro-lib/src/derive_component/preprocess.rs b/crates/cgp-macro-lib/src/derive_component/preprocess.rs index ac03eca9..8702e446 100644 --- a/crates/cgp-macro-lib/src/derive_component/preprocess.rs +++ b/crates/cgp-macro-lib/src/derive_component/preprocess.rs @@ -1,6 +1,5 @@ use syn::ItemTrait; -use crate::cgp_fn::expand_use_type_attributes_on_trait; use crate::derive_component::attributes::ComponentAttributes; pub fn preprocess_consumer_trait( @@ -9,9 +8,7 @@ pub fn preprocess_consumer_trait( ) -> syn::Result<()> { consumer_trait.supertraits.extend(attributes.extend.clone()); - if !attributes.use_type.attributes.is_empty() { - expand_use_type_attributes_on_trait(consumer_trait, &attributes.use_type)?; - } + attributes.use_type.transform_item_trait(consumer_trait)?; Ok(()) } From f9068f8f524077a8be7ef15abecaab660d5eb994 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 4 Jun 2026 20:49:07 +0200 Subject: [PATCH 28/46] Move FunctionAttributes --- .../src/types/attributes/function.rs | 67 +++++++++++++++++++ .../src/types/attributes/mod.rs | 2 + crates/cgp-macro-lib/src/cgp_fn/attributes.rs | 56 ---------------- crates/cgp-macro-lib/src/cgp_fn/derive.rs | 9 ++- crates/cgp-macro-lib/src/cgp_fn/item_impl.rs | 2 +- crates/cgp-macro-lib/src/cgp_fn/item_trait.rs | 3 +- crates/cgp-macro-lib/src/cgp_fn/mod.rs | 4 -- crates/cgp-macro-lib/src/cgp_fn/spec.rs | 13 ---- 8 files changed, 75 insertions(+), 81 deletions(-) create mode 100644 crates/cgp-macro-core/src/types/attributes/function.rs delete mode 100644 crates/cgp-macro-lib/src/cgp_fn/attributes.rs delete mode 100644 crates/cgp-macro-lib/src/cgp_fn/spec.rs diff --git a/crates/cgp-macro-core/src/types/attributes/function.rs b/crates/cgp-macro-core/src/types/attributes/function.rs new file mode 100644 index 00000000..a100773f --- /dev/null +++ b/crates/cgp-macro-core/src/types/attributes/function.rs @@ -0,0 +1,67 @@ +use syn::punctuated::Punctuated; +use syn::token::Comma; +use syn::{Attribute, GenericParam, TypeParamBound, WherePredicate}; + +use crate::types::attributes::{UseProviderAttribute, UseTypeAttribute, UseTypeAttributes}; +use crate::types::ident::IdentWithTypeArgs; + +#[derive(Default)] +pub struct FunctionAttributes { + pub extend: Vec, + pub extend_where: Vec, + pub uses: Vec, + pub use_type: UseTypeAttributes, + pub use_provider: Vec, + pub impl_generics: Vec, + pub raw_attributes: Vec, +} + +impl FunctionAttributes { + pub fn parse(attributes: Vec) -> syn::Result { + let mut parsed_attributes = FunctionAttributes::default(); + + for attribute in attributes.into_iter() { + if let Some(ident) = attribute.path().get_ident() { + if ident == "extend" { + let extend_bound = attribute + .parse_args_with(Punctuated::::parse_terminated)?; + + parsed_attributes.extend.extend(extend_bound); + } else if ident == "extend_where" { + let where_predicates = attribute + .parse_args_with(Punctuated::::parse_terminated)?; + + parsed_attributes.extend_where.extend(where_predicates); + } else if ident == "uses" { + let uses = attribute.parse_args_with( + Punctuated::::parse_terminated, + )?; + + parsed_attributes.uses.extend(uses); + } else if ident == "use_type" { + let use_type = attribute + .parse_args_with(Punctuated::::parse_terminated)?; + + parsed_attributes.use_type.attributes.extend(use_type); + } else if ident == "use_provider" { + let use_provider = attribute.parse_args_with( + Punctuated::::parse_terminated, + )?; + + parsed_attributes.use_provider.extend(use_provider); + } else if ident == "impl_generics" { + let impl_generics = attribute + .parse_args_with(Punctuated::::parse_terminated)?; + + parsed_attributes.impl_generics.extend(impl_generics); + } else { + parsed_attributes.raw_attributes.push(attribute); + } + } else { + parsed_attributes.raw_attributes.push(attribute); + } + } + + Ok(parsed_attributes) + } +} diff --git a/crates/cgp-macro-core/src/types/attributes/mod.rs b/crates/cgp-macro-core/src/types/attributes/mod.rs index f1d9447d..23a104fb 100644 --- a/crates/cgp-macro-core/src/types/attributes/mod.rs +++ b/crates/cgp-macro-core/src/types/attributes/mod.rs @@ -1,7 +1,9 @@ +mod function; mod impl_attributes; mod use_provider; mod use_type; +pub use function::*; pub use impl_attributes::*; pub use use_provider::*; pub use use_type::*; diff --git a/crates/cgp-macro-lib/src/cgp_fn/attributes.rs b/crates/cgp-macro-lib/src/cgp_fn/attributes.rs deleted file mode 100644 index be293325..00000000 --- a/crates/cgp-macro-lib/src/cgp_fn/attributes.rs +++ /dev/null @@ -1,56 +0,0 @@ -use cgp_macro_core::types::attributes::{UseProviderAttribute, UseTypeAttribute}; -use cgp_macro_core::types::ident::IdentWithTypeArgs; -use syn::punctuated::Punctuated; -use syn::token::Comma; -use syn::{Attribute, GenericParam, TypeParamBound, WherePredicate}; - -use crate::cgp_fn::FunctionAttributes; - -pub fn parse_function_attributes( - attributes: Vec, -) -> syn::Result<(FunctionAttributes, Vec)> { - let mut parsed_attributes = FunctionAttributes::default(); - let mut rest_attributes = Vec::new(); - - for attribute in attributes.into_iter() { - if let Some(ident) = attribute.path().get_ident() { - if ident == "extend" { - let extend_bound = attribute - .parse_args_with(Punctuated::::parse_terminated)?; - - parsed_attributes.extend.extend(extend_bound); - } else if ident == "extend_where" { - let where_predicates = attribute - .parse_args_with(Punctuated::::parse_terminated)?; - - parsed_attributes.extend_where.extend(where_predicates); - } else if ident == "uses" { - let uses = attribute - .parse_args_with(Punctuated::::parse_terminated)?; - - parsed_attributes.uses.extend(uses); - } else if ident == "use_type" { - let use_type = attribute - .parse_args_with(Punctuated::::parse_terminated)?; - - parsed_attributes.use_type.attributes.extend(use_type); - } else if ident == "use_provider" { - let use_provider = attribute - .parse_args_with(Punctuated::::parse_terminated)?; - - parsed_attributes.use_provider.extend(use_provider); - } else if ident == "impl_generics" { - let impl_generics = attribute - .parse_args_with(Punctuated::::parse_terminated)?; - - parsed_attributes.impl_generics.extend(impl_generics); - } else { - rest_attributes.push(attribute); - } - } else { - rest_attributes.push(attribute); - } - } - - Ok((parsed_attributes, rest_attributes)) -} diff --git a/crates/cgp-macro-lib/src/cgp_fn/derive.rs b/crates/cgp-macro-lib/src/cgp_fn/derive.rs index 82ab9426..ef11ba3d 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/derive.rs @@ -1,13 +1,13 @@ use core::mem; use cgp_macro_core::functions::extract_and_parse_implicit_args; +use cgp_macro_core::types::attributes::FunctionAttributes; use proc_macro2::TokenStream; use quote::quote; use syn::{Ident, ItemFn, Visibility}; use crate::cgp_fn::item_impl::derive_item_impl; use crate::cgp_fn::item_trait::derive_item_trait; -use crate::cgp_fn::parse_function_attributes; pub fn derive_cgp_fn(trait_ident: &Ident, mut item_fn: ItemFn) -> syn::Result { let visibility = item_fn.vis.clone(); @@ -15,15 +15,14 @@ pub fn derive_cgp_fn(trait_ident: &Ident, mut item_fn: ItemFn) -> syn::Result syn::Result, - pub extend_where: Vec, - pub uses: Vec, - pub use_type: UseTypeAttributes, - pub use_provider: Vec, - pub impl_generics: Vec, -} From f7dc68809a344293ac356632b32171f9d0bcbcaf Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 4 Jun 2026 20:52:08 +0200 Subject: [PATCH 29/46] Change extract_implicit_args_from_impl_items into method --- .../src/functions/implicits/extract.rs | 25 ------------------- .../src/functions/implicits/mod.rs | 2 -- .../src/types/implicits/arg_fields.rs | 22 +++++++++++++++- crates/cgp-macro-lib/src/cgp_fn/derive.rs | 3 +-- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 4 +-- 5 files changed, 24 insertions(+), 32 deletions(-) delete mode 100644 crates/cgp-macro-core/src/functions/implicits/extract.rs diff --git a/crates/cgp-macro-core/src/functions/implicits/extract.rs b/crates/cgp-macro-core/src/functions/implicits/extract.rs deleted file mode 100644 index 7527fd38..00000000 --- a/crates/cgp-macro-core/src/functions/implicits/extract.rs +++ /dev/null @@ -1,25 +0,0 @@ -use syn::ImplItem; - -use crate::functions::extract_and_parse_implicit_args; -use crate::types::implicits::ImplicitArgFields; - -pub fn extract_implicit_args_from_impl_items( - impl_items: &mut [ImplItem], -) -> syn::Result { - let mut all_fields = Vec::new(); - - for item in impl_items { - if let ImplItem::Fn(method) = item { - let implicit_args = extract_and_parse_implicit_args(&mut method.sig.inputs)?; - implicit_args.prepend_to_block(&mut method.block)?; - - for implicit_arg in implicit_args.fields { - if !all_fields.contains(&implicit_arg) { - all_fields.push(implicit_arg); - } - } - } - } - - Ok(ImplicitArgFields { fields: all_fields }) -} diff --git a/crates/cgp-macro-core/src/functions/implicits/mod.rs b/crates/cgp-macro-core/src/functions/implicits/mod.rs index ab19c84d..4f42021d 100644 --- a/crates/cgp-macro-core/src/functions/implicits/mod.rs +++ b/crates/cgp-macro-core/src/functions/implicits/mod.rs @@ -1,5 +1,3 @@ -mod extract; mod parse; -pub use extract::*; pub use parse::*; diff --git a/crates/cgp-macro-core/src/types/implicits/arg_fields.rs b/crates/cgp-macro-core/src/types/implicits/arg_fields.rs index 52bd4ab9..323fd735 100644 --- a/crates/cgp-macro-core/src/types/implicits/arg_fields.rs +++ b/crates/cgp-macro-core/src/types/implicits/arg_fields.rs @@ -1,7 +1,8 @@ use syn::punctuated::Punctuated; use syn::token::Plus; -use syn::{Block, TypeParamBound, parse_quote}; +use syn::{Block, ImplItem, TypeParamBound, parse_quote}; +use crate::functions::extract_and_parse_implicit_args; use crate::types::implicits::ImplicitArgField; #[derive(Default)] @@ -39,4 +40,23 @@ impl ImplicitArgFields { Ok(()) } + + pub fn extract_from_impl_items(impl_items: &mut [ImplItem]) -> syn::Result { + let mut all_fields = Vec::new(); + + for item in impl_items { + if let ImplItem::Fn(method) = item { + let implicit_args = extract_and_parse_implicit_args(&mut method.sig.inputs)?; + implicit_args.prepend_to_block(&mut method.block)?; + + for implicit_arg in implicit_args.fields { + if !all_fields.contains(&implicit_arg) { + all_fields.push(implicit_arg); + } + } + } + } + + Ok(ImplicitArgFields { fields: all_fields }) + } } diff --git a/crates/cgp-macro-lib/src/cgp_fn/derive.rs b/crates/cgp-macro-lib/src/cgp_fn/derive.rs index ef11ba3d..1462bec2 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/derive.rs @@ -14,11 +14,10 @@ pub fn derive_cgp_fn(trait_ident: &Ident, mut item_fn: ItemFn) -> syn::Result syn::Result Date: Thu, 4 Jun 2026 20:58:09 +0200 Subject: [PATCH 30/46] Implement add_type_param_bounds for ImplicitArgFields --- .../src/types/implicits/arg_fields.rs | 21 ++++++++++++++++++- crates/cgp-macro-lib/src/cgp_fn/item_impl.rs | 9 +------- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 10 +-------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/crates/cgp-macro-core/src/types/implicits/arg_fields.rs b/crates/cgp-macro-core/src/types/implicits/arg_fields.rs index 323fd735..f2af0242 100644 --- a/crates/cgp-macro-core/src/types/implicits/arg_fields.rs +++ b/crates/cgp-macro-core/src/types/implicits/arg_fields.rs @@ -1,6 +1,6 @@ use syn::punctuated::Punctuated; use syn::token::Plus; -use syn::{Block, ImplItem, TypeParamBound, parse_quote}; +use syn::{Block, Generics, ImplItem, Type, TypeParamBound, parse_quote}; use crate::functions::extract_and_parse_implicit_args; use crate::types::implicits::ImplicitArgField; @@ -17,6 +17,25 @@ impl ImplicitArgFields { } impl ImplicitArgFields { + pub fn add_type_param_bounds( + &self, + self_type: &Type, + generics: &mut Generics, + ) -> syn::Result<()> { + if self.fields.is_empty() { + return Ok(()); + } + + let where_clause = generics.make_where_clause(); + let bounds = self.to_type_param_bounds()?; + + where_clause.predicates.push(parse_quote! { + #self_type: #bounds + }); + + Ok(()) + } + pub fn to_type_param_bounds(&self) -> syn::Result> { let mut constraints: Punctuated = Punctuated::new(); diff --git a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs index fe7946e2..6825eaee 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs @@ -60,14 +60,7 @@ pub fn derive_item_impl( .extend(attributes.extend_where.clone()); } - if !implicit_args.fields.is_empty() { - let where_clause = item_impl.generics.make_where_clause(); - let bounds = implicit_args.to_type_param_bounds()?; - - where_clause.predicates.push(parse2(quote! { - Self: #bounds - })?); - } + implicit_args.add_type_param_bounds(&parse_quote!(Self), &mut item_impl.generics)?; attributes.use_type.transform_item_impl(&mut item_impl)?; diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index a92f1595..e76fb759 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -19,15 +19,7 @@ pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result Date: Thu, 4 Jun 2026 21:10:14 +0200 Subject: [PATCH 31/46] Add AddTypeParamBounds trait --- crates/cgp-macro-core/src/traits/bounds.rs | 28 +++++++++++++++++++ crates/cgp-macro-core/src/traits/mod.rs | 2 ++ .../src/types/attributes/impl_attributes.rs | 8 ++++-- .../src/types/attributes/mod.rs | 2 ++ .../src/types/attributes/uses.rs | 23 +++++++++++++++ .../src/types/implicits/arg_fields.rs | 28 ++++--------------- crates/cgp-macro-lib/src/cgp_fn/item_impl.rs | 1 + crates/cgp-macro-lib/src/cgp_impl/derive.rs | 24 ++++------------ 8 files changed, 72 insertions(+), 44 deletions(-) create mode 100644 crates/cgp-macro-core/src/traits/bounds.rs create mode 100644 crates/cgp-macro-core/src/types/attributes/uses.rs diff --git a/crates/cgp-macro-core/src/traits/bounds.rs b/crates/cgp-macro-core/src/traits/bounds.rs new file mode 100644 index 00000000..4f3d1882 --- /dev/null +++ b/crates/cgp-macro-core/src/traits/bounds.rs @@ -0,0 +1,28 @@ +use syn::punctuated::Punctuated; +use syn::token::Plus; +use syn::{Generics, Type, TypeParamBound, parse_quote}; + +pub trait ToTypeParamBounds { + fn to_type_param_bounds(&self) -> syn::Result>; +} + +pub trait AddTypeParamBounds { + fn add_type_param_bounds(&self, self_type: &Type, generics: &mut Generics) -> syn::Result<()>; +} + +impl AddTypeParamBounds for T +where + T: ToTypeParamBounds, +{ + fn add_type_param_bounds(&self, self_type: &Type, generics: &mut Generics) -> syn::Result<()> { + let bounds = self.to_type_param_bounds()?; + + if !bounds.is_empty() { + generics.make_where_clause().predicates.push(parse_quote! { + #self_type: #bounds + }); + } + + Ok(()) + } +} diff --git a/crates/cgp-macro-core/src/traits/mod.rs b/crates/cgp-macro-core/src/traits/mod.rs index 9484894c..577220eb 100644 --- a/crates/cgp-macro-core/src/traits/mod.rs +++ b/crates/cgp-macro-core/src/traits/mod.rs @@ -1,5 +1,7 @@ +mod bounds; mod keyword; mod to_type; +pub use bounds::*; pub use keyword::*; pub use to_type::*; diff --git a/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs b/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs index 9bea0539..a49b62bc 100644 --- a/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs +++ b/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs @@ -2,12 +2,14 @@ use syn::Attribute; use syn::punctuated::Punctuated; use syn::token::Comma; -use crate::types::attributes::{UseProviderAttribute, UseTypeAttribute, UseTypeAttributes}; +use crate::types::attributes::{ + UseProviderAttribute, UseTypeAttribute, UseTypeAttributes, UsesAttributes, +}; use crate::types::ident::IdentWithTypeArgs; #[derive(Default)] pub struct ImplAttributes { - pub uses: Vec, + pub uses: UsesAttributes, pub use_type: UseTypeAttributes, pub use_provider: Vec, pub raw_attributes: Vec, @@ -25,7 +27,7 @@ impl ImplAttributes { Punctuated::::parse_terminated, )?; - parsed_attributes.uses.extend(uses); + parsed_attributes.uses.imports.extend(uses); } "use_type" => { let use_type = attribute.parse_args_with( diff --git a/crates/cgp-macro-core/src/types/attributes/mod.rs b/crates/cgp-macro-core/src/types/attributes/mod.rs index 23a104fb..72930efc 100644 --- a/crates/cgp-macro-core/src/types/attributes/mod.rs +++ b/crates/cgp-macro-core/src/types/attributes/mod.rs @@ -2,8 +2,10 @@ mod function; mod impl_attributes; mod use_provider; mod use_type; +mod uses; pub use function::*; pub use impl_attributes::*; pub use use_provider::*; pub use use_type::*; +pub use uses::*; diff --git a/crates/cgp-macro-core/src/types/attributes/uses.rs b/crates/cgp-macro-core/src/types/attributes/uses.rs new file mode 100644 index 00000000..cc088b7d --- /dev/null +++ b/crates/cgp-macro-core/src/types/attributes/uses.rs @@ -0,0 +1,23 @@ +use syn::punctuated::Punctuated; +use syn::token::Plus; +use syn::{TypeParamBound, parse_quote}; + +use crate::traits::ToTypeParamBounds; +use crate::types::ident::IdentWithTypeArgs; + +#[derive(Default)] +pub struct UsesAttributes { + pub imports: Vec, +} + +impl ToTypeParamBounds for UsesAttributes { + fn to_type_param_bounds(&self) -> syn::Result> { + let mut bounds: Punctuated = Punctuated::default(); + + for import in &self.imports { + bounds.push(parse_quote! { #import }); + } + + Ok(bounds) + } +} diff --git a/crates/cgp-macro-core/src/types/implicits/arg_fields.rs b/crates/cgp-macro-core/src/types/implicits/arg_fields.rs index f2af0242..d79e8e8f 100644 --- a/crates/cgp-macro-core/src/types/implicits/arg_fields.rs +++ b/crates/cgp-macro-core/src/types/implicits/arg_fields.rs @@ -1,8 +1,9 @@ use syn::punctuated::Punctuated; use syn::token::Plus; -use syn::{Block, Generics, ImplItem, Type, TypeParamBound, parse_quote}; +use syn::{Block, ImplItem, TypeParamBound, parse_quote}; use crate::functions::extract_and_parse_implicit_args; +use crate::traits::ToTypeParamBounds; use crate::types::implicits::ImplicitArgField; #[derive(Default)] @@ -16,27 +17,8 @@ impl ImplicitArgFields { } } -impl ImplicitArgFields { - pub fn add_type_param_bounds( - &self, - self_type: &Type, - generics: &mut Generics, - ) -> syn::Result<()> { - if self.fields.is_empty() { - return Ok(()); - } - - let where_clause = generics.make_where_clause(); - let bounds = self.to_type_param_bounds()?; - - where_clause.predicates.push(parse_quote! { - #self_type: #bounds - }); - - Ok(()) - } - - pub fn to_type_param_bounds(&self) -> syn::Result> { +impl ToTypeParamBounds for ImplicitArgFields { + fn to_type_param_bounds(&self) -> syn::Result> { let mut constraints: Punctuated = Punctuated::new(); for field in &self.fields { @@ -46,7 +28,9 @@ impl ImplicitArgFields { Ok(constraints) } +} +impl ImplicitArgFields { pub fn prepend_to_block(&self, block: &mut Block) -> syn::Result<()> { let block_statements = core::mem::take(&mut block.stmts); diff --git a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs index 6825eaee..634c5dcd 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs @@ -1,3 +1,4 @@ +use cgp_macro_core::traits::AddTypeParamBounds; use cgp_macro_core::types::attributes::FunctionAttributes; use cgp_macro_core::types::implicits::ImplicitArgFields; use quote::quote; diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index e76fb759..14c9f4fb 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -1,12 +1,11 @@ +use cgp_macro_core::traits::AddTypeParamBounds; use cgp_macro_core::types::attributes::ImplAttributes; use cgp_macro_core::types::cgp_impl::ImplArgs; use cgp_macro_core::types::implicits::ImplicitArgFields; use proc_macro2::TokenStream; use quote::quote; -use syn::punctuated::Punctuated; use syn::spanned::Spanned; -use syn::token::Plus; -use syn::{Error, ItemImpl, TypeParamBound, parse_quote, parse2}; +use syn::{Error, ItemImpl, parse_quote}; use crate::cgp_impl::derive_provider_impl; use crate::cgp_impl::provider_bounds::derive_provider_bounds; @@ -20,25 +19,12 @@ pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result = Punctuated::default(); - - for import in attributes.uses.iter() { - bounds.push(parse2(quote! { #import })?); - } - - item_impl - .generics - .make_where_clause() - .predicates - .push(parse2(quote! { - Self: #bounds - })?); - } - if !attributes.use_provider.is_empty() { let where_clause = item_impl.generics.make_where_clause(); From 54f6521b1d9bbcb46915f70d4006669dcc32459c Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 4 Jun 2026 21:25:41 +0200 Subject: [PATCH 32/46] Turn derive_provider_bounds into method --- .../src/types/attributes/use_provider.rs | 31 ++++++++++++++++++- crates/cgp-macro-lib/src/cgp_fn/item_impl.rs | 14 ++++----- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 17 +++++----- crates/cgp-macro-lib/src/cgp_impl/mod.rs | 2 -- 4 files changed, 46 insertions(+), 18 deletions(-) diff --git a/crates/cgp-macro-core/src/types/attributes/use_provider.rs b/crates/cgp-macro-core/src/types/attributes/use_provider.rs index 95b8fa16..4089a516 100644 --- a/crates/cgp-macro-core/src/types/attributes/use_provider.rs +++ b/crates/cgp-macro-core/src/types/attributes/use_provider.rs @@ -1,7 +1,7 @@ use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::token::{Colon, Plus}; -use syn::{Type, parse_quote}; +use syn::{Type, TypeParamBound, WherePredicate, parse_quote}; use crate::types::ident::IdentWithTypeArgs; @@ -12,6 +12,35 @@ pub struct UseProviderAttribute { pub provider_trait_bounds: Punctuated, } +impl UseProviderAttribute { + pub fn to_provider_bounds(&self, context_type: &Type) -> syn::Result { + let context_type = if self.context_type == parse_quote! { Self } { + context_type + } else { + &self.context_type + }; + + let provider_type = &self.provider_type; + let mut bounds = Punctuated::::new(); + + for bound in &self.provider_trait_bounds { + let mut bound = bound.clone(); + bound + .type_args + .make_args() + .insert(0, parse_quote!(#context_type)); + + bounds.push(parse_quote!(#bound)); + } + + let predicate = parse_quote! { + #provider_type: #bounds + }; + + Ok(predicate) + } +} + impl Parse for UseProviderAttribute { fn parse(input: ParseStream) -> syn::Result { let context_type = parse_quote!(Self); diff --git a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs index 634c5dcd..cf21a50c 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs @@ -4,9 +4,7 @@ use cgp_macro_core::types::implicits::ImplicitArgFields; use quote::quote; use syn::punctuated::Punctuated; use syn::token::Plus; -use syn::{Generics, Ident, ItemFn, ItemImpl, TypeParamBound, parse_quote, parse2}; - -use crate::cgp_impl::derive_provider_bounds; +use syn::{Generics, Ident, ItemFn, ItemImpl, Type, TypeParamBound, parse_quote, parse2}; pub fn derive_item_impl( trait_ident: &Ident, @@ -17,6 +15,8 @@ pub fn derive_item_impl( ) -> syn::Result { let type_generics = generics.split_for_impl().1; + let self_type: Type = parse_quote!(Self); + let mut item_impl: ItemImpl = parse2(quote! { impl #trait_ident #type_generics for __Context__ { #item_fn @@ -61,16 +61,16 @@ pub fn derive_item_impl( .extend(attributes.extend_where.clone()); } - implicit_args.add_type_param_bounds(&parse_quote!(Self), &mut item_impl.generics)?; + implicit_args.add_type_param_bounds(&self_type, &mut item_impl.generics)?; attributes.use_type.transform_item_impl(&mut item_impl)?; if !attributes.use_provider.is_empty() { let where_clause = item_impl.generics.make_where_clause(); - for spec in attributes.use_provider.iter() { - let provider_bounds = derive_provider_bounds(&parse_quote! { Self }, spec)?; - where_clause.predicates.push(provider_bounds); + for use_provider in attributes.use_provider.iter() { + let predicate = use_provider.to_provider_bounds(&self_type)?; + where_clause.predicates.push(predicate); } } diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index 14c9f4fb..6df10b26 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -5,10 +5,9 @@ use cgp_macro_core::types::implicits::ImplicitArgFields; use proc_macro2::TokenStream; use quote::quote; use syn::spanned::Spanned; -use syn::{Error, ItemImpl, parse_quote}; +use syn::{Error, ItemImpl, Type, parse_quote}; use crate::cgp_impl::derive_provider_impl; -use crate::cgp_impl::provider_bounds::derive_provider_bounds; use crate::derive_provider::{ derive_component_name_from_provider_impl, derive_is_provider_for, derive_provider_struct, }; @@ -17,24 +16,26 @@ pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result Date: Thu, 4 Jun 2026 21:40:48 +0200 Subject: [PATCH 33/46] Implement add_type_param_bounds for UseProviderAttributes --- .../src/types/attributes/function.rs | 11 +++++--- .../src/types/attributes/impl_attributes.rs | 10 ++++--- .../attribute.rs} | 19 ++++++++------ .../attributes/use_provider/attributes.rs | 26 +++++++++++++++++++ .../src/types/attributes/use_provider/mod.rs | 5 ++++ crates/cgp-macro-lib/src/cgp_fn/item_impl.rs | 12 +++------ crates/cgp-macro-lib/src/cgp_impl/derive.rs | 12 +++------ 7 files changed, 63 insertions(+), 32 deletions(-) rename crates/cgp-macro-core/src/types/attributes/{use_provider.rs => use_provider/attribute.rs} (86%) create mode 100644 crates/cgp-macro-core/src/types/attributes/use_provider/attributes.rs create mode 100644 crates/cgp-macro-core/src/types/attributes/use_provider/mod.rs diff --git a/crates/cgp-macro-core/src/types/attributes/function.rs b/crates/cgp-macro-core/src/types/attributes/function.rs index a100773f..3e97e52e 100644 --- a/crates/cgp-macro-core/src/types/attributes/function.rs +++ b/crates/cgp-macro-core/src/types/attributes/function.rs @@ -2,7 +2,9 @@ use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{Attribute, GenericParam, TypeParamBound, WherePredicate}; -use crate::types::attributes::{UseProviderAttribute, UseTypeAttribute, UseTypeAttributes}; +use crate::types::attributes::{ + UseProviderAttribute, UseProviderAttributes, UseTypeAttribute, UseTypeAttributes, +}; use crate::types::ident::IdentWithTypeArgs; #[derive(Default)] @@ -11,7 +13,7 @@ pub struct FunctionAttributes { pub extend_where: Vec, pub uses: Vec, pub use_type: UseTypeAttributes, - pub use_provider: Vec, + pub use_provider: UseProviderAttributes, pub impl_generics: Vec, pub raw_attributes: Vec, } @@ -48,7 +50,10 @@ impl FunctionAttributes { Punctuated::::parse_terminated, )?; - parsed_attributes.use_provider.extend(use_provider); + parsed_attributes + .use_provider + .attributes + .extend(use_provider); } else if ident == "impl_generics" { let impl_generics = attribute .parse_args_with(Punctuated::::parse_terminated)?; diff --git a/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs b/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs index a49b62bc..cea9184b 100644 --- a/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs +++ b/crates/cgp-macro-core/src/types/attributes/impl_attributes.rs @@ -3,7 +3,8 @@ use syn::punctuated::Punctuated; use syn::token::Comma; use crate::types::attributes::{ - UseProviderAttribute, UseTypeAttribute, UseTypeAttributes, UsesAttributes, + UseProviderAttribute, UseProviderAttributes, UseTypeAttribute, UseTypeAttributes, + UsesAttributes, }; use crate::types::ident::IdentWithTypeArgs; @@ -11,7 +12,7 @@ use crate::types::ident::IdentWithTypeArgs; pub struct ImplAttributes { pub uses: UsesAttributes, pub use_type: UseTypeAttributes, - pub use_provider: Vec, + pub use_provider: UseProviderAttributes, pub raw_attributes: Vec, } @@ -41,7 +42,10 @@ impl ImplAttributes { Punctuated::::parse_terminated, )?; - parsed_attributes.use_provider.extend(use_provider); + parsed_attributes + .use_provider + .attributes + .extend(use_provider); } _ => { parsed_attributes.raw_attributes.push(attribute.clone()); diff --git a/crates/cgp-macro-core/src/types/attributes/use_provider.rs b/crates/cgp-macro-core/src/types/attributes/use_provider/attribute.rs similarity index 86% rename from crates/cgp-macro-core/src/types/attributes/use_provider.rs rename to crates/cgp-macro-core/src/types/attributes/use_provider/attribute.rs index 4089a516..5865f471 100644 --- a/crates/cgp-macro-core/src/types/attributes/use_provider.rs +++ b/crates/cgp-macro-core/src/types/attributes/use_provider/attribute.rs @@ -13,14 +13,10 @@ pub struct UseProviderAttribute { } impl UseProviderAttribute { - pub fn to_provider_bounds(&self, context_type: &Type) -> syn::Result { - let context_type = if self.context_type == parse_quote! { Self } { - context_type - } else { - &self.context_type - }; - - let provider_type = &self.provider_type; + pub fn to_type_param_bounds( + &self, + context_type: &Type, + ) -> syn::Result> { let mut bounds = Punctuated::::new(); for bound in &self.provider_trait_bounds { @@ -33,6 +29,13 @@ impl UseProviderAttribute { bounds.push(parse_quote!(#bound)); } + Ok(bounds) + } + + pub fn to_provider_bounds(&self, context_type: &Type) -> syn::Result { + let provider_type = &self.provider_type; + let bounds = self.to_type_param_bounds(context_type)?; + let predicate = parse_quote! { #provider_type: #bounds }; diff --git a/crates/cgp-macro-core/src/types/attributes/use_provider/attributes.rs b/crates/cgp-macro-core/src/types/attributes/use_provider/attributes.rs new file mode 100644 index 00000000..2aae24c3 --- /dev/null +++ b/crates/cgp-macro-core/src/types/attributes/use_provider/attributes.rs @@ -0,0 +1,26 @@ +use syn::{Generics, Type}; + +use crate::traits::AddTypeParamBounds; +use crate::types::attributes::UseProviderAttribute; + +#[derive(Default)] +pub struct UseProviderAttributes { + pub attributes: Vec, +} + +impl AddTypeParamBounds for UseProviderAttributes { + fn add_type_param_bounds(&self, self_type: &Type, generics: &mut Generics) -> syn::Result<()> { + if self.attributes.is_empty() { + return Ok(()); + } + + let where_clause = generics.make_where_clause(); + + for use_provider in &self.attributes { + let predicate = use_provider.to_provider_bounds(&self_type)?; + where_clause.predicates.push(predicate); + } + + Ok(()) + } +} diff --git a/crates/cgp-macro-core/src/types/attributes/use_provider/mod.rs b/crates/cgp-macro-core/src/types/attributes/use_provider/mod.rs new file mode 100644 index 00000000..ea33ebcb --- /dev/null +++ b/crates/cgp-macro-core/src/types/attributes/use_provider/mod.rs @@ -0,0 +1,5 @@ +mod attribute; +mod attributes; + +pub use attribute::*; +pub use attributes::*; diff --git a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs index cf21a50c..36acbabe 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs @@ -64,15 +64,9 @@ pub fn derive_item_impl( implicit_args.add_type_param_bounds(&self_type, &mut item_impl.generics)?; attributes.use_type.transform_item_impl(&mut item_impl)?; - - if !attributes.use_provider.is_empty() { - let where_clause = item_impl.generics.make_where_clause(); - - for use_provider in attributes.use_provider.iter() { - let predicate = use_provider.to_provider_bounds(&self_type)?; - where_clause.predicates.push(predicate); - } - } + attributes + .use_provider + .add_type_param_bounds(&self_type, &mut item_impl.generics)?; Ok(item_impl) } diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index 6df10b26..baaa6e90 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -25,15 +25,9 @@ pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result Date: Thu, 4 Jun 2026 21:51:03 +0200 Subject: [PATCH 34/46] Implement lower for ItemCgpImpl --- .../cgp-macro-core/src/types/cgp_impl/args.rs | 1 + .../cgp-macro-core/src/types/cgp_impl/item.rs | 26 +++++++++++--- .../{with_parsed_attrs.rs => lowered.rs} | 2 +- .../cgp-macro-core/src/types/cgp_impl/mod.rs | 4 +-- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 36 +++++++------------ 5 files changed, 38 insertions(+), 31 deletions(-) rename crates/cgp-macro-core/src/types/cgp_impl/{with_parsed_attrs.rs => lowered.rs} (73%) diff --git a/crates/cgp-macro-core/src/types/cgp_impl/args.rs b/crates/cgp-macro-core/src/types/cgp_impl/args.rs index 2b1ad9dd..89427b21 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/args.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/args.rs @@ -6,6 +6,7 @@ use crate::traits::ParseOptionalKeyword; use crate::types::keyword::Keyword; use crate::types::keywords::New; +#[derive(Clone)] pub struct ImplArgs { pub new: Option>, pub provider_type: Type, diff --git a/crates/cgp-macro-core/src/types/cgp_impl/item.rs b/crates/cgp-macro-core/src/types/cgp_impl/item.rs index 32d3493b..aec4b303 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/item.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/item.rs @@ -1,7 +1,9 @@ -use syn::ItemImpl; +use syn::{ItemImpl, Type, parse_quote}; +use crate::traits::AddTypeParamBounds; use crate::types::attributes::ImplAttributes; -use crate::types::cgp_impl::{CgpImplWithParsedAttributes, ImplArgs}; +use crate::types::cgp_impl::{ImplArgs, LoweredCgpImpl}; +use crate::types::implicits::ImplicitArgFields; pub struct ItemCgpImpl { pub args: ImplArgs, @@ -9,12 +11,28 @@ pub struct ItemCgpImpl { } impl ItemCgpImpl { - pub fn lower(&self) -> syn::Result { + pub fn lower(&self) -> syn::Result { let mut item_impl = self.item_impl.clone(); let attributes = ImplAttributes::parse(&item_impl.attrs)?; item_impl.attrs = attributes.raw_attributes; - todo!() + let self_type: Type = parse_quote!(Self); + + let implicit_args = ImplicitArgFields::extract_from_impl_items(&mut item_impl.items)?; + implicit_args.add_type_param_bounds(&self_type, &mut item_impl.generics)?; + attributes + .uses + .add_type_param_bounds(&self_type, &mut item_impl.generics)?; + + attributes.use_type.transform_item_impl(&mut item_impl)?; + attributes + .use_provider + .add_type_param_bounds(&self_type, &mut item_impl.generics)?; + + Ok(LoweredCgpImpl { + args: self.args.clone(), + item_impl, + }) } } diff --git a/crates/cgp-macro-core/src/types/cgp_impl/with_parsed_attrs.rs b/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs similarity index 73% rename from crates/cgp-macro-core/src/types/cgp_impl/with_parsed_attrs.rs rename to crates/cgp-macro-core/src/types/cgp_impl/lowered.rs index a2e201b2..9ddb2fec 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/with_parsed_attrs.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs @@ -2,7 +2,7 @@ use syn::ItemImpl; use crate::types::cgp_impl::ImplArgs; -pub struct CgpImplWithParsedAttributes { +pub struct LoweredCgpImpl { pub args: ImplArgs, pub item_impl: ItemImpl, } diff --git a/crates/cgp-macro-core/src/types/cgp_impl/mod.rs b/crates/cgp-macro-core/src/types/cgp_impl/mod.rs index 9c71de25..0e0cf2f1 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/mod.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/mod.rs @@ -1,7 +1,7 @@ mod args; mod item; -mod with_parsed_attrs; +mod lowered; pub use args::*; pub use item::*; -pub use with_parsed_attrs::*; +pub use lowered::*; diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index baaa6e90..1ac26848 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -1,35 +1,23 @@ -use cgp_macro_core::traits::AddTypeParamBounds; -use cgp_macro_core::types::attributes::ImplAttributes; -use cgp_macro_core::types::cgp_impl::ImplArgs; -use cgp_macro_core::types::implicits::ImplicitArgFields; +use cgp_macro_core::types::cgp_impl::{ImplArgs, ItemCgpImpl}; use proc_macro2::TokenStream; use quote::quote; use syn::spanned::Spanned; -use syn::{Error, ItemImpl, Type, parse_quote}; +use syn::{Error, ItemImpl, parse_quote}; use crate::cgp_impl::derive_provider_impl; use crate::derive_provider::{ derive_component_name_from_provider_impl, derive_is_provider_for, derive_provider_struct, }; -pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result { - let attributes = ImplAttributes::parse(&item_impl.attrs)?; - item_impl.attrs = attributes.raw_attributes; +pub fn derive_cgp_impl(args: ImplArgs, item_impl: ItemImpl) -> syn::Result { + let item = ItemCgpImpl { + args: args.clone(), + item_impl, + }; - let self_type: Type = parse_quote!(Self); + let item_impl = item.lower()?.item_impl; - let implicit_args = ImplicitArgFields::extract_from_impl_items(&mut item_impl.items)?; - implicit_args.add_type_param_bounds(&self_type, &mut item_impl.generics)?; - attributes - .uses - .add_type_param_bounds(&self_type, &mut item_impl.generics)?; - - attributes.use_type.transform_item_impl(&mut item_impl)?; - attributes - .use_provider - .add_type_param_bounds(&self_type, &mut item_impl.generics)?; - - if spec.provider_type == self_type { + if args.provider_type == parse_quote!(Self) { if item_impl.trait_.is_none() { return Err(Error::new( item_impl.span(), @@ -41,9 +29,9 @@ pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result component_type.clone(), None => derive_component_name_from_provider_impl(&provider_impl)?, }; @@ -51,7 +39,7 @@ pub fn derive_cgp_impl(spec: ImplArgs, mut item_impl: ItemImpl) -> syn::Result Date: Thu, 4 Jun 2026 22:05:51 +0200 Subject: [PATCH 35/46] Compute consumer trait path and context type inside lowering --- .../cgp-macro-core/src/types/cgp_impl/item.rs | 24 ++++++++++- .../src/types/cgp_impl/lowered.rs | 5 ++- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 34 +++++++-------- crates/cgp-macro-lib/src/cgp_impl/mod.rs | 2 - .../src/cgp_impl/provider_impl.rs | 42 ------------------- 5 files changed, 44 insertions(+), 63 deletions(-) delete mode 100644 crates/cgp-macro-lib/src/cgp_impl/provider_impl.rs diff --git a/crates/cgp-macro-core/src/types/cgp_impl/item.rs b/crates/cgp-macro-core/src/types/cgp_impl/item.rs index aec4b303..5d6a83fe 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/item.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/item.rs @@ -1,4 +1,5 @@ -use syn::{ItemImpl, Type, parse_quote}; +use quote::ToTokens; +use syn::{ItemImpl, Type, parse_quote, parse2}; use crate::traits::AddTypeParamBounds; use crate::types::attributes::ImplAttributes; @@ -30,9 +31,30 @@ impl ItemCgpImpl { .use_provider .add_type_param_bounds(&self_type, &mut item_impl.generics)?; + let (consumer_trait_path, context_type) = match &item_impl.trait_ { + Some((_, path, _)) => { + let consumer_trait_path = parse2(path.to_token_stream())?; + let context_type = item_impl.self_ty.as_ref().clone(); + (consumer_trait_path, context_type) + } + None => { + let consumer_trait_path = parse2(item_impl.self_ty.to_token_stream())?; + let context_type = parse_quote! { __Context__ }; + + item_impl + .generics + .params + .insert(0, parse_quote! { #context_type }); + + (consumer_trait_path, context_type) + } + }; + Ok(LoweredCgpImpl { args: self.args.clone(), item_impl, + context_type, + consumer_trait_path, }) } } diff --git a/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs b/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs index 9ddb2fec..ff6406c2 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs @@ -1,8 +1,11 @@ -use syn::ItemImpl; +use syn::{ItemImpl, Type}; use crate::types::cgp_impl::ImplArgs; +use crate::types::ident::IdentWithTypeArgs; pub struct LoweredCgpImpl { pub args: ImplArgs, pub item_impl: ItemImpl, + pub context_type: Type, + pub consumer_trait_path: IdentWithTypeArgs, } diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index 1ac26848..99179b78 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -1,37 +1,37 @@ use cgp_macro_core::types::cgp_impl::{ImplArgs, ItemCgpImpl}; use proc_macro2::TokenStream; -use quote::quote; +use quote::{ToTokens, quote}; use syn::spanned::Spanned; use syn::{Error, ItemImpl, parse_quote}; -use crate::cgp_impl::derive_provider_impl; +use crate::cgp_impl::transform_impl_trait; use crate::derive_provider::{ derive_component_name_from_provider_impl, derive_is_provider_for, derive_provider_struct, }; pub fn derive_cgp_impl(args: ImplArgs, item_impl: ItemImpl) -> syn::Result { - let item = ItemCgpImpl { - args: args.clone(), - item_impl, - }; + let item = ItemCgpImpl { args, item_impl }; - let item_impl = item.lower()?.item_impl; + let lowered = item.lower()?; - if args.provider_type == parse_quote!(Self) { - if item_impl.trait_.is_none() { + if lowered.args.provider_type == parse_quote!(Self) { + if lowered.item_impl.trait_.is_none() { return Err(Error::new( - item_impl.span(), + lowered.item_impl.span(), "Expected context type to be specified", )); } - Ok(quote! { - #item_impl - }) + Ok(lowered.item_impl.to_token_stream()) } else { - let (_context_type, provider_impl) = derive_provider_impl(&args.provider_type, item_impl)?; - - let component_type = match &args.component_type { + let provider_impl = transform_impl_trait( + &lowered.item_impl, + &lowered.consumer_trait_path, + &lowered.args.provider_type, + &lowered.context_type, + )?; + + let component_type = match &lowered.args.component_type { Some(component_type) => component_type.clone(), None => derive_component_name_from_provider_impl(&provider_impl)?, }; @@ -39,7 +39,7 @@ pub fn derive_cgp_impl(args: ImplArgs, item_impl: ItemImpl) -> syn::Result syn::Result<(Type, ItemImpl)> { - match &item_impl.trait_ { - Some((_, path, _)) => { - let consumer_trait_path = parse2(path.to_token_stream())?; - let context_type = item_impl.self_ty.as_ref(); - let item_trait = transform_impl_trait( - &item_impl, - &consumer_trait_path, - provider_type, - context_type, - )?; - - Ok((context_type.clone(), item_trait)) - } - None => { - let consumer_trait_path = parse2(item_impl.self_ty.to_token_stream())?; - let context_type = parse_quote! { __Context__ }; - - item_impl - .generics - .params - .insert(0, parse_quote! { __Context__ }); - - let item_trait = transform_impl_trait( - &item_impl, - &consumer_trait_path, - provider_type, - &context_type, - )?; - - Ok((context_type, item_trait)) - } - } -} From 0b2a8fa98d000e28942aa9277db9d1bdec659622 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 4 Jun 2026 22:10:34 +0200 Subject: [PATCH 36/46] Implement to_raw_item_impl method --- .../src/types/cgp_impl/lowered.rs | 73 ++++++++++++++++++- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 8 +- crates/cgp-macro-lib/src/cgp_impl/mod.rs | 2 - .../src/cgp_impl/provider_bounds.rs | 35 --------- .../cgp-macro-lib/src/cgp_impl/transform.rs | 71 ------------------ 5 files changed, 73 insertions(+), 116 deletions(-) delete mode 100644 crates/cgp-macro-lib/src/cgp_impl/provider_bounds.rs delete mode 100644 crates/cgp-macro-lib/src/cgp_impl/transform.rs diff --git a/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs b/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs index ff6406c2..93a2f343 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs @@ -1,7 +1,15 @@ -use syn::{ItemImpl, Type}; +use proc_macro2::Span; +use quote::ToTokens; +use syn::token::For; +use syn::visit_mut::VisitMut; +use syn::{Ident, ImplItem, ItemImpl, Type, parse_quote, parse2}; +use crate::functions::to_snake_case_ident; use crate::types::cgp_impl::ImplArgs; use crate::types::ident::IdentWithTypeArgs; +use crate::visitors::{ + ReplaceSelfReceiverVisitor, ReplaceSelfTypeVisitor, ReplaceSelfValueVisitor, +}; pub struct LoweredCgpImpl { pub args: ImplArgs, @@ -9,3 +17,66 @@ pub struct LoweredCgpImpl { pub context_type: Type, pub consumer_trait_path: IdentWithTypeArgs, } + +impl LoweredCgpImpl { + pub fn to_raw_item_impl(&self) -> syn::Result { + let item_impl = &self.item_impl; + let context_type = &self.context_type; + let consumer_trait_path = &self.consumer_trait_path; + let provider_type = &self.args.provider_type; + + let context_ident = if let Ok(ident) = parse2::(context_type.to_token_stream()) { + to_snake_case_ident(&ident) + } else { + Ident::new("__context__", Span::call_site()) + }; + + let local_assoc_types: Vec = item_impl + .items + .iter() + .filter_map(|item| { + if let ImplItem::Type(assoc_type) = item { + Some(assoc_type.ident.clone()) + } else { + None + } + }) + .collect(); + + let mut out_impl = item_impl.clone(); + + out_impl.self_ty = Box::new(provider_type.clone()); + + let mut provider_trait_path = consumer_trait_path.clone(); + + provider_trait_path + .type_args + .make_args() + .insert(0, parse_quote!(#context_type)); + + out_impl.trait_ = Some(( + None, + parse2(provider_trait_path.to_token_stream())?, + For(Span::call_site()), + )); + + ReplaceSelfTypeVisitor { + replaced_type: &context_type, + skip_assoc_types: &local_assoc_types, + } + .visit_item_impl_mut(&mut out_impl); + + ReplaceSelfReceiverVisitor { + replaced_ident: &context_ident, + replaced_type: &context_type, + } + .visit_item_impl_mut(&mut out_impl); + + ReplaceSelfValueVisitor { + replaced_ident: &context_ident, + } + .visit_item_impl_mut(&mut out_impl); + + Ok(out_impl) + } +} diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index 99179b78..ce9f77ca 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -4,7 +4,6 @@ use quote::{ToTokens, quote}; use syn::spanned::Spanned; use syn::{Error, ItemImpl, parse_quote}; -use crate::cgp_impl::transform_impl_trait; use crate::derive_provider::{ derive_component_name_from_provider_impl, derive_is_provider_for, derive_provider_struct, }; @@ -24,12 +23,7 @@ pub fn derive_cgp_impl(args: ImplArgs, item_impl: ItemImpl) -> syn::Result component_type.clone(), diff --git a/crates/cgp-macro-lib/src/cgp_impl/mod.rs b/crates/cgp-macro-lib/src/cgp_impl/mod.rs index f1594c0d..61eca8a7 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/mod.rs @@ -1,5 +1,3 @@ mod derive; -mod transform; pub use derive::*; -pub use transform::*; diff --git a/crates/cgp-macro-lib/src/cgp_impl/provider_bounds.rs b/crates/cgp-macro-lib/src/cgp_impl/provider_bounds.rs deleted file mode 100644 index 95011bb1..00000000 --- a/crates/cgp-macro-lib/src/cgp_impl/provider_bounds.rs +++ /dev/null @@ -1,35 +0,0 @@ -use cgp_macro_core::types::attributes::UseProviderAttribute; -use quote::quote; -use syn::punctuated::Punctuated; -use syn::token::Plus; -use syn::{Type, TypeParamBound, WherePredicate, parse_quote, parse2}; - -pub fn derive_provider_bounds( - context_type: &Type, - spec: &UseProviderAttribute, -) -> syn::Result { - let context_type = if spec.context_type == parse_quote! { Self } { - context_type - } else { - &spec.context_type - }; - - let provider_type = &spec.provider_type; - let mut bounds = Punctuated::::new(); - - for bound in &spec.provider_trait_bounds { - let mut bound = bound.clone(); - bound - .type_args - .make_args() - .insert(0, parse_quote!(#context_type)); - - bounds.push(parse_quote!(#bound)); - } - - let predicate = parse2(quote! { - #provider_type: #bounds - })?; - - Ok(predicate) -} diff --git a/crates/cgp-macro-lib/src/cgp_impl/transform.rs b/crates/cgp-macro-lib/src/cgp_impl/transform.rs deleted file mode 100644 index f64d272d..00000000 --- a/crates/cgp-macro-lib/src/cgp_impl/transform.rs +++ /dev/null @@ -1,71 +0,0 @@ -use cgp_macro_core::functions::to_snake_case_ident; -use cgp_macro_core::types::ident::IdentWithTypeArgs; -use cgp_macro_core::visitors::{ - ReplaceSelfReceiverVisitor, ReplaceSelfTypeVisitor, ReplaceSelfValueVisitor, -}; -use proc_macro2::Span; -use quote::ToTokens; -use syn::token::For; -use syn::visit_mut::VisitMut; -use syn::{Ident, ImplItem, ItemImpl, Type, parse_quote, parse2}; - -pub fn transform_impl_trait( - item_impl: &ItemImpl, - consumer_trait_path: &IdentWithTypeArgs, - provider_type: &Type, - context_type: &Type, -) -> syn::Result { - let context_ident = if let Ok(ident) = parse2::(context_type.to_token_stream()) { - to_snake_case_ident(&ident) - } else { - Ident::new("__context__", Span::call_site()) - }; - - let local_assoc_types: Vec = item_impl - .items - .iter() - .filter_map(|item| { - if let ImplItem::Type(assoc_type) = item { - Some(assoc_type.ident.clone()) - } else { - None - } - }) - .collect(); - - let mut out_impl = item_impl.clone(); - - out_impl.self_ty = Box::new(provider_type.clone()); - - let mut provider_trait_path = consumer_trait_path.clone(); - - provider_trait_path - .type_args - .make_args() - .insert(0, parse_quote!(#context_type)); - - out_impl.trait_ = Some(( - None, - parse2(provider_trait_path.to_token_stream())?, - For(Span::call_site()), - )); - - ReplaceSelfTypeVisitor { - replaced_type: &context_type, - skip_assoc_types: &local_assoc_types, - } - .visit_item_impl_mut(&mut out_impl); - - ReplaceSelfReceiverVisitor { - replaced_ident: &context_ident, - replaced_type: &context_type, - } - .visit_item_impl_mut(&mut out_impl); - - ReplaceSelfValueVisitor { - replaced_ident: &context_ident, - } - .visit_item_impl_mut(&mut out_impl); - - Ok(out_impl) -} From 123d6f5bb877f32f3090cc40e0966fbf510fa8fb Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 4 Jun 2026 23:24:54 +0200 Subject: [PATCH 37/46] Draft implement ItemCgpProvider --- .../src/types/cgp_provider/args.rs | 30 +++++ .../src/types/cgp_provider/item.rs | 105 +++++++++++++++++- .../src/types/cgp_provider/mod.rs | 2 + .../src/types/generics/arguments.rs | 51 ++++++++- crates/cgp-macro-core/src/visitors/mod.rs | 2 + .../src/visitors/replace_provider.rs} | 0 .../src/derive_provider/component_name.rs | 4 +- .../src/derive_provider/derive.rs | 3 +- .../cgp-macro-lib/src/derive_provider/mod.rs | 2 - 9 files changed, 190 insertions(+), 9 deletions(-) create mode 100644 crates/cgp-macro-core/src/types/cgp_provider/args.rs rename crates/{cgp-macro-lib/src/derive_provider/replace_constraint.rs => cgp-macro-core/src/visitors/replace_provider.rs} (100%) diff --git a/crates/cgp-macro-core/src/types/cgp_provider/args.rs b/crates/cgp-macro-core/src/types/cgp_provider/args.rs new file mode 100644 index 00000000..6f7dd909 --- /dev/null +++ b/crates/cgp-macro-core/src/types/cgp_provider/args.rs @@ -0,0 +1,30 @@ +use syn::Type; +use syn::parse::{Parse, ParseStream}; + +use crate::traits::ParseOptionalKeyword; +use crate::types::keyword::Keyword; +use crate::types::keywords::New; + +#[derive(Clone)] +pub struct ProviderArgs { + pub new: Option>, + pub component_type: Option, +} + +impl Parse for ProviderArgs { + fn parse(input: ParseStream) -> syn::Result { + let new = input.parse_optional_keyword()?; + + let component_type = if input.is_empty() { + let component_type: Type = input.parse()?; + Some(component_type) + } else { + None + }; + + Ok(ProviderArgs { + new, + component_type, + }) + } +} diff --git a/crates/cgp-macro-core/src/types/cgp_provider/item.rs b/crates/cgp-macro-core/src/types/cgp_provider/item.rs index c24969cd..549425f5 100644 --- a/crates/cgp-macro-core/src/types/cgp_provider/item.rs +++ b/crates/cgp-macro-core/src/types/cgp_provider/item.rs @@ -1,6 +1,107 @@ -use syn::{ItemImpl, Type}; +use std::collections::BTreeMap; + +use proc_macro2::Span; +use quote::ToTokens; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::token::{Comma, For}; +use syn::{Error, Ident, ItemImpl, ItemStruct, Path, Type, parse_quote, parse2}; + +use crate::types::cgp_provider::ProviderArgs; +use crate::types::ident::{IdentWithTypeArgs, IdentWithTypeGenerics}; +use crate::visitors::replace_provider_in_generics; pub struct ItemCgpProvider { - pub component_type: Option, + pub args: ProviderArgs, pub item_impl: ItemImpl, } + +impl ItemCgpProvider { + pub fn component_type(&self) -> syn::Result { + let item_impl = &self.item_impl; + + let (_, provider_trait_path, _) = item_impl.trait_.as_ref().ok_or_else(|| { + Error::new(item_impl.span(), "expect provider trait name to be present") + })?; + + let provider_trait: IdentWithTypeArgs = parse2(provider_trait_path.to_token_stream())?; + + let component_ident = Ident::new( + &format!("{}Component", provider_trait.ident), + provider_trait.span(), + ); + + parse2(component_ident.to_token_stream()) + } + + pub fn to_is_provider_for_impl(&self) -> syn::Result { + let component_name = self.component_type()?; + + let provider_impl = &self.item_impl; + + let (_, provider_path, _) = provider_impl.trait_.as_ref().ok_or_else(|| { + Error::new( + provider_impl.span(), + "provider impl should contain trait path", + ) + })?; + + let provider_ident: IdentWithTypeArgs = parse2(provider_path.to_token_stream())?; + + let provider_map = BTreeMap::from([(provider_ident.ident.clone(), component_name.clone())]); + + let is_provider_params = provider_ident.type_args.to_param_types()?; + let is_provider_params = Punctuated::<_, Comma>::from_iter(is_provider_params); + + let context_arg = provider_ident.type_args.type_args().first().ok_or_else(|| { + Error::new( + provider_impl.span(), + "provider impl should contain trait path containing at least one generic parameter", + ) + })?.clone(); + + let is_provider_path: Path = parse_quote!( IsProviderFor < #component_name, #context_arg, ( #is_provider_params ) > ); + + let mut is_provider_impl = provider_impl.clone(); + + is_provider_impl.attrs.clear(); + is_provider_impl.items.clear(); + is_provider_impl.defaultness = None; + is_provider_impl.unsafety = None; + + is_provider_impl.trait_ = Some((None, is_provider_path, For(Span::call_site()))); + + replace_provider_in_generics(&provider_map, &mut is_provider_impl.generics); + + Ok(is_provider_impl) + } + + pub fn to_provider_struct(&self) -> syn::Result> { + if self.args.new.is_none() { + return Ok(None); + } + + let provider_impl = &self.item_impl; + + let impl_self_type = &provider_impl.self_ty; + + let provider_type: IdentWithTypeGenerics = parse_quote!( #impl_self_type ); + + let provider_name = &provider_type.ident; + let type_generics_params = &provider_type.type_generics.params; + + let provider_struct = if type_generics_params.is_empty() { + parse_quote! { + pub struct #provider_name; + } + } else { + parse_quote! { + pub struct #provider_name<#type_generics_params>( + pub ::core::marker::PhantomData<(#type_generics_params)> + ); + } + }; + + Ok(Some(provider_struct)) + } +} diff --git a/crates/cgp-macro-core/src/types/cgp_provider/mod.rs b/crates/cgp-macro-core/src/types/cgp_provider/mod.rs index 95e0a691..d05a74f5 100644 --- a/crates/cgp-macro-core/src/types/cgp_provider/mod.rs +++ b/crates/cgp-macro-core/src/types/cgp_provider/mod.rs @@ -1,3 +1,5 @@ +mod args; mod item; +pub use args::*; pub use item::*; diff --git a/crates/cgp-macro-core/src/types/generics/arguments.rs b/crates/cgp-macro-core/src/types/generics/arguments.rs index f0284ea9..0d986124 100644 --- a/crates/cgp-macro-core/src/types/generics/arguments.rs +++ b/crates/cgp-macro-core/src/types/generics/arguments.rs @@ -2,8 +2,9 @@ use proc_macro2::TokenStream; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; +use syn::spanned::Spanned; use syn::token::{Comma, Lt}; -use syn::{AngleBracketedGenericArguments, GenericArgument, parse_quote}; +use syn::{AngleBracketedGenericArguments, Error, GenericArgument, Type, parse_quote}; use crate::types::generics::TypeGenerics; @@ -16,6 +17,54 @@ impl GenericArguments { pub fn make_args(&mut self) -> &mut Punctuated { &mut self.args.get_or_insert_with(|| parse_quote!(<>)).args } + + pub fn type_args(&self) -> Vec { + let mut params: Vec = Vec::new(); + + if let Some(args) = &self.args { + for arg in &args.args { + match arg { + GenericArgument::Type(ty) => { + params.push(ty.clone()); + } + _ => {} + } + } + } + + params + } + + /// Convert the arguments to a list of types to be used in `IsProviderFor`. + /// This mainly converts the lifetimes `'a` into `Life<'a>` so that they can + /// be used as types. + /// + /// Other generic parameters like const generics arguments are currently + /// unsupported. + pub fn to_param_types(&self) -> syn::Result> { + let mut params: Vec = Vec::new(); + + if let Some(args) = &self.args { + for arg in &args.args { + match arg { + GenericArgument::Lifetime(life) => { + params.push(parse_quote! { Life<#life> }); + } + GenericArgument::Type(ty) => { + params.push(ty.clone()); + } + _ => { + return Err(Error::new( + arg.span(), + format!("unsupported type argument: {:?}", arg), + )); + } + } + } + } + + Ok(params) + } } impl Parse for GenericArguments { diff --git a/crates/cgp-macro-core/src/visitors/mod.rs b/crates/cgp-macro-core/src/visitors/mod.rs index 3a45b6f6..8a4dbdcd 100644 --- a/crates/cgp-macro-core/src/visitors/mod.rs +++ b/crates/cgp-macro-core/src/visitors/mod.rs @@ -1,5 +1,7 @@ +mod replace_provider; mod replace_self; mod substitute_abstract_type; +pub use replace_provider::*; pub use replace_self::*; pub use substitute_abstract_type::*; diff --git a/crates/cgp-macro-lib/src/derive_provider/replace_constraint.rs b/crates/cgp-macro-core/src/visitors/replace_provider.rs similarity index 100% rename from crates/cgp-macro-lib/src/derive_provider/replace_constraint.rs rename to crates/cgp-macro-core/src/visitors/replace_provider.rs diff --git a/crates/cgp-macro-lib/src/derive_provider/component_name.rs b/crates/cgp-macro-lib/src/derive_provider/component_name.rs index 01744cbb..f2729ba5 100644 --- a/crates/cgp-macro-lib/src/derive_provider/component_name.rs +++ b/crates/cgp-macro-lib/src/derive_provider/component_name.rs @@ -4,14 +4,14 @@ use syn::spanned::Spanned; use syn::{Error, Ident, ItemImpl, Type, parse2}; pub fn derive_component_name_from_provider_impl(provider_impl: &ItemImpl) -> syn::Result { - let provider_trait = provider_impl.trait_.as_ref().ok_or_else(|| { + let (_, provider_trait_path, _) = provider_impl.trait_.as_ref().ok_or_else(|| { Error::new( provider_impl.span(), "expect provider trait name to be present", ) })?; - let provider_trait: IdentWithTypeArgs = parse2(provider_trait.1.to_token_stream())?; + let provider_trait: IdentWithTypeArgs = parse2(provider_trait_path.to_token_stream())?; let component_ident = Ident::new( &format!("{}Component", provider_trait.ident), diff --git a/crates/cgp-macro-lib/src/derive_provider/derive.rs b/crates/cgp-macro-lib/src/derive_provider/derive.rs index 5d20800c..ec09d6d7 100644 --- a/crates/cgp-macro-lib/src/derive_provider/derive.rs +++ b/crates/cgp-macro-lib/src/derive_provider/derive.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use cgp_macro_core::types::ident::IdentWithTypeGenerics; +use cgp_macro_core::visitors::replace_provider_in_generics; use proc_macro2::Span; use quote::quote; use syn::punctuated::Punctuated; @@ -11,8 +12,6 @@ use syn::{ PathArguments, Type, parse_quote, }; -use crate::derive_provider::replace_provider_in_generics; - pub fn derive_provider_struct(provider_impl: &ItemImpl) -> syn::Result { let impl_self_type = &provider_impl.self_ty; diff --git a/crates/cgp-macro-lib/src/derive_provider/mod.rs b/crates/cgp-macro-lib/src/derive_provider/mod.rs index 07b38c97..ad77d90a 100644 --- a/crates/cgp-macro-lib/src/derive_provider/mod.rs +++ b/crates/cgp-macro-lib/src/derive_provider/mod.rs @@ -1,7 +1,5 @@ mod component_name; mod derive; -mod replace_constraint; pub use component_name::*; pub use derive::*; -pub use replace_constraint::*; From d24b605b4ab75e8251bf11cccf5ef713711a1332 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 4 Jun 2026 23:52:31 +0200 Subject: [PATCH 38/46] Implement ItemCgpProvider --- .../src/types/cgp_provider/args.rs | 2 +- .../src/types/cgp_provider/item.rs | 27 +++---- .../src/types/cgp_provider/mod.rs | 2 + .../types/cgp_provider/provider_impl_args.rs | 77 +++++++++++++++++++ .../src/types/generics/arguments.rs | 51 +----------- .../src/entrypoints/cgp_new_provider.rs | 28 +++---- .../src/entrypoints/cgp_provider.rs | 21 +++-- 7 files changed, 114 insertions(+), 94 deletions(-) create mode 100644 crates/cgp-macro-core/src/types/cgp_provider/provider_impl_args.rs diff --git a/crates/cgp-macro-core/src/types/cgp_provider/args.rs b/crates/cgp-macro-core/src/types/cgp_provider/args.rs index 6f7dd909..7bb08435 100644 --- a/crates/cgp-macro-core/src/types/cgp_provider/args.rs +++ b/crates/cgp-macro-core/src/types/cgp_provider/args.rs @@ -15,7 +15,7 @@ impl Parse for ProviderArgs { fn parse(input: ParseStream) -> syn::Result { let new = input.parse_optional_keyword()?; - let component_type = if input.is_empty() { + let component_type = if !input.is_empty() { let component_type: Type = input.parse()?; Some(component_type) } else { diff --git a/crates/cgp-macro-core/src/types/cgp_provider/item.rs b/crates/cgp-macro-core/src/types/cgp_provider/item.rs index 549425f5..a602a769 100644 --- a/crates/cgp-macro-core/src/types/cgp_provider/item.rs +++ b/crates/cgp-macro-core/src/types/cgp_provider/item.rs @@ -2,12 +2,11 @@ use std::collections::BTreeMap; use proc_macro2::Span; use quote::ToTokens; -use syn::punctuated::Punctuated; use syn::spanned::Spanned; -use syn::token::{Comma, For}; +use syn::token::For; use syn::{Error, Ident, ItemImpl, ItemStruct, Path, Type, parse_quote, parse2}; -use crate::types::cgp_provider::ProviderArgs; +use crate::types::cgp_provider::{ProviderArgs, ProviderImplArgs}; use crate::types::ident::{IdentWithTypeArgs, IdentWithTypeGenerics}; use crate::visitors::replace_provider_in_generics; @@ -46,21 +45,16 @@ impl ItemCgpProvider { ) })?; - let provider_ident: IdentWithTypeArgs = parse2(provider_path.to_token_stream())?; + let IdentWithTypeArgs { + ident: provider_ident, + type_args: provider_generics, + } = parse2(provider_path.to_token_stream())?; - let provider_map = BTreeMap::from([(provider_ident.ident.clone(), component_name.clone())]); + let impl_args = ProviderImplArgs::from_generic_args(&provider_generics)?; + let context_type = &impl_args.context_type; - let is_provider_params = provider_ident.type_args.to_param_types()?; - let is_provider_params = Punctuated::<_, Comma>::from_iter(is_provider_params); - - let context_arg = provider_ident.type_args.type_args().first().ok_or_else(|| { - Error::new( - provider_impl.span(), - "provider impl should contain trait path containing at least one generic parameter", - ) - })?.clone(); - - let is_provider_path: Path = parse_quote!( IsProviderFor < #component_name, #context_arg, ( #is_provider_params ) > ); + let is_provider_path: Path = + parse_quote!( IsProviderFor < #component_name, #context_type, ( #impl_args ) > ); let mut is_provider_impl = provider_impl.clone(); @@ -71,6 +65,7 @@ impl ItemCgpProvider { is_provider_impl.trait_ = Some((None, is_provider_path, For(Span::call_site()))); + let provider_map = BTreeMap::from([(provider_ident.clone(), component_name.clone())]); replace_provider_in_generics(&provider_map, &mut is_provider_impl.generics); Ok(is_provider_impl) diff --git a/crates/cgp-macro-core/src/types/cgp_provider/mod.rs b/crates/cgp-macro-core/src/types/cgp_provider/mod.rs index d05a74f5..f9f93b11 100644 --- a/crates/cgp-macro-core/src/types/cgp_provider/mod.rs +++ b/crates/cgp-macro-core/src/types/cgp_provider/mod.rs @@ -1,5 +1,7 @@ mod args; mod item; +mod provider_impl_args; pub use args::*; pub use item::*; +pub use provider_impl_args::*; diff --git a/crates/cgp-macro-core/src/types/cgp_provider/provider_impl_args.rs b/crates/cgp-macro-core/src/types/cgp_provider/provider_impl_args.rs new file mode 100644 index 00000000..e6d31c3f --- /dev/null +++ b/crates/cgp-macro-core/src/types/cgp_provider/provider_impl_args.rs @@ -0,0 +1,77 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, quote}; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::token::Comma; +use syn::{Error, GenericArgument, Lifetime, Type}; + +use crate::types::generics::GenericArguments; + +pub struct ProviderImplArgs { + pub context_type: Type, + pub impl_args: Punctuated, +} + +pub enum ProviderImplArg { + Type(Type), + Life(Lifetime), +} + +impl ProviderImplArgs { + pub fn from_generic_args(generic_args: &GenericArguments) -> syn::Result { + let mut impl_args: Punctuated = Punctuated::new(); + let mut context_type: Option = None; + + if let Some(args) = &generic_args.args { + for arg in &args.args { + match arg { + GenericArgument::Lifetime(life) => { + impl_args.push(ProviderImplArg::Life(life.clone())); + } + GenericArgument::Type(ty) => { + if context_type.is_none() { + context_type = Some(ty.clone()); + } else { + impl_args.push(ProviderImplArg::Type(ty.clone())); + } + } + _ => { + return Err(Error::new( + arg.span(), + format!("unsupported type argument: {:?}", arg), + )); + } + } + } + } + + let context_type = context_type.ok_or_else(|| Error::new( + generic_args.span(), + "provider impl should contain trait path containing at least one generic type parameter", + ))?; + + Ok(Self { + context_type, + impl_args, + }) + } +} + +impl ToTokens for ProviderImplArgs { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.impl_args.to_tokens(tokens); + } +} + +impl ToTokens for ProviderImplArg { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + ProviderImplArg::Type(ty) => { + ty.to_tokens(tokens); + } + ProviderImplArg::Life(life) => { + tokens.extend(quote!(Life<#life>)); + } + } + } +} diff --git a/crates/cgp-macro-core/src/types/generics/arguments.rs b/crates/cgp-macro-core/src/types/generics/arguments.rs index 0d986124..f0284ea9 100644 --- a/crates/cgp-macro-core/src/types/generics/arguments.rs +++ b/crates/cgp-macro-core/src/types/generics/arguments.rs @@ -2,9 +2,8 @@ use proc_macro2::TokenStream; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; -use syn::spanned::Spanned; use syn::token::{Comma, Lt}; -use syn::{AngleBracketedGenericArguments, Error, GenericArgument, Type, parse_quote}; +use syn::{AngleBracketedGenericArguments, GenericArgument, parse_quote}; use crate::types::generics::TypeGenerics; @@ -17,54 +16,6 @@ impl GenericArguments { pub fn make_args(&mut self) -> &mut Punctuated { &mut self.args.get_or_insert_with(|| parse_quote!(<>)).args } - - pub fn type_args(&self) -> Vec { - let mut params: Vec = Vec::new(); - - if let Some(args) = &self.args { - for arg in &args.args { - match arg { - GenericArgument::Type(ty) => { - params.push(ty.clone()); - } - _ => {} - } - } - } - - params - } - - /// Convert the arguments to a list of types to be used in `IsProviderFor`. - /// This mainly converts the lifetimes `'a` into `Life<'a>` so that they can - /// be used as types. - /// - /// Other generic parameters like const generics arguments are currently - /// unsupported. - pub fn to_param_types(&self) -> syn::Result> { - let mut params: Vec = Vec::new(); - - if let Some(args) = &self.args { - for arg in &args.args { - match arg { - GenericArgument::Lifetime(life) => { - params.push(parse_quote! { Life<#life> }); - } - GenericArgument::Type(ty) => { - params.push(ty.clone()); - } - _ => { - return Err(Error::new( - arg.span(), - format!("unsupported type argument: {:?}", arg), - )); - } - } - } - } - - Ok(params) - } } impl Parse for GenericArguments { diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_new_provider.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_new_provider.rs index 653ff7c5..be415a2d 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_new_provider.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_new_provider.rs @@ -1,27 +1,23 @@ +use cgp_macro_core::types::cgp_provider::{ItemCgpProvider, ProviderArgs}; +use cgp_macro_core::types::keyword::Keyword; use proc_macro2::TokenStream; use quote::quote; -use syn::{ItemImpl, Type}; - -use crate::derive_provider::{ - derive_component_name_from_provider_impl, derive_is_provider_for, derive_provider_struct, -}; +use syn::{ItemImpl, parse2}; pub fn cgp_new_provider(attr: TokenStream, body: TokenStream) -> syn::Result { - let provider_impl: ItemImpl = syn::parse2(body)?; - - let component_name: Type = if !attr.is_empty() { - syn::parse2(attr)? - } else { - derive_component_name_from_provider_impl(&provider_impl)? - }; + let item_impl: ItemImpl = parse2(body)?; + let mut args: ProviderArgs = parse2(attr)?; + args.new = Some(Keyword::default()); - let provider_struct = derive_provider_struct(&provider_impl)?; + let item = ItemCgpProvider { args, item_impl }; - let is_provider_for_impl: ItemImpl = derive_is_provider_for(&component_name, &provider_impl)?; + let is_provider_for_impl = item.to_is_provider_for_impl()?; + let item_struct = item.to_provider_struct()?; + let item_impl = item.item_impl; let result = quote! { - #provider_struct - #provider_impl + #item_struct + #item_impl #is_provider_for_impl }; diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_provider.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_provider.rs index 33f8bf11..d6ab22f5 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_provider.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_provider.rs @@ -1,22 +1,21 @@ +use cgp_macro_core::types::cgp_provider::{ItemCgpProvider, ProviderArgs}; use proc_macro2::TokenStream; use quote::quote; -use syn::{ItemImpl, Type, parse2}; - -use crate::derive_provider::{derive_component_name_from_provider_impl, derive_is_provider_for}; +use syn::{ItemImpl, parse2}; pub fn cgp_provider(attr: TokenStream, body: TokenStream) -> syn::Result { - let provider_impl: ItemImpl = parse2(body)?; + let item_impl: ItemImpl = parse2(body)?; + let args: ProviderArgs = parse2(attr)?; - let component_name: Type = if !attr.is_empty() { - syn::parse2(attr)? - } else { - derive_component_name_from_provider_impl(&provider_impl)? - }; + let item = ItemCgpProvider { args, item_impl }; - let is_provider_for_impl: ItemImpl = derive_is_provider_for(&component_name, &provider_impl)?; + let is_provider_for_impl = item.to_is_provider_for_impl()?; + let item_struct = item.to_provider_struct()?; + let item_impl = item.item_impl; let result = quote! { - #provider_impl + #item_struct + #item_impl #is_provider_for_impl }; From 786cf711e74061762ccd561ec20f09227a891e0c Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 6 Jun 2026 21:33:47 +0200 Subject: [PATCH 39/46] Implement lowering for ItemCgpImpl --- .../src/types/cgp_provider/item.rs | 13 ++++++++++++- .../src/types/cgp_provider/lower.rs | 17 +++++++++++++++++ .../src/types/cgp_provider/mod.rs | 2 ++ .../src/entrypoints/cgp_new_provider.rs | 8 ++------ .../src/entrypoints/cgp_provider.rs | 8 ++------ 5 files changed, 35 insertions(+), 13 deletions(-) create mode 100644 crates/cgp-macro-core/src/types/cgp_provider/lower.rs diff --git a/crates/cgp-macro-core/src/types/cgp_provider/item.rs b/crates/cgp-macro-core/src/types/cgp_provider/item.rs index a602a769..ed911ca7 100644 --- a/crates/cgp-macro-core/src/types/cgp_provider/item.rs +++ b/crates/cgp-macro-core/src/types/cgp_provider/item.rs @@ -6,7 +6,7 @@ use syn::spanned::Spanned; use syn::token::For; use syn::{Error, Ident, ItemImpl, ItemStruct, Path, Type, parse_quote, parse2}; -use crate::types::cgp_provider::{ProviderArgs, ProviderImplArgs}; +use crate::types::cgp_provider::{LoweredCgpProvider, ProviderArgs, ProviderImplArgs}; use crate::types::ident::{IdentWithTypeArgs, IdentWithTypeGenerics}; use crate::visitors::replace_provider_in_generics; @@ -16,6 +16,17 @@ pub struct ItemCgpProvider { } impl ItemCgpProvider { + pub fn lower(&self) -> syn::Result { + let is_provider_for_impl = self.to_is_provider_for_impl()?; + let provider_struct = self.to_provider_struct()?; + + Ok(LoweredCgpProvider { + item_impl: self.item_impl.clone(), + is_provider_for_impl, + provider_struct, + }) + } + pub fn component_type(&self) -> syn::Result { let item_impl = &self.item_impl; diff --git a/crates/cgp-macro-core/src/types/cgp_provider/lower.rs b/crates/cgp-macro-core/src/types/cgp_provider/lower.rs new file mode 100644 index 00000000..10fb4496 --- /dev/null +++ b/crates/cgp-macro-core/src/types/cgp_provider/lower.rs @@ -0,0 +1,17 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{ItemImpl, ItemStruct}; + +pub struct LoweredCgpProvider { + pub item_impl: ItemImpl, + pub is_provider_for_impl: ItemImpl, + pub provider_struct: Option, +} + +impl ToTokens for LoweredCgpProvider { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.item_impl.to_tokens(tokens); + self.is_provider_for_impl.to_tokens(tokens); + self.provider_struct.to_tokens(tokens); + } +} diff --git a/crates/cgp-macro-core/src/types/cgp_provider/mod.rs b/crates/cgp-macro-core/src/types/cgp_provider/mod.rs index f9f93b11..1634b662 100644 --- a/crates/cgp-macro-core/src/types/cgp_provider/mod.rs +++ b/crates/cgp-macro-core/src/types/cgp_provider/mod.rs @@ -1,7 +1,9 @@ mod args; mod item; +mod lower; mod provider_impl_args; pub use args::*; pub use item::*; +pub use lower::*; pub use provider_impl_args::*; diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_new_provider.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_new_provider.rs index be415a2d..81c15f63 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_new_provider.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_new_provider.rs @@ -11,14 +11,10 @@ pub fn cgp_new_provider(attr: TokenStream, body: TokenStream) -> syn::Result syn::Result Date: Sat, 6 Jun 2026 21:40:28 +0200 Subject: [PATCH 40/46] Use ItemCgpProvider in derive_cgp_impl --- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 33 +++++++++---------- .../src/derive_provider/derive.rs | 29 ++-------------- 2 files changed, 18 insertions(+), 44 deletions(-) diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index ce9f77ca..286dcfa4 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/derive.rs @@ -1,17 +1,19 @@ use cgp_macro_core::types::cgp_impl::{ImplArgs, ItemCgpImpl}; +use cgp_macro_core::types::cgp_provider::{ItemCgpProvider, ProviderArgs}; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::spanned::Spanned; use syn::{Error, ItemImpl, parse_quote}; -use crate::derive_provider::{ - derive_component_name_from_provider_impl, derive_is_provider_for, derive_provider_struct, -}; +use crate::derive_provider::derive_component_name_from_provider_impl; pub fn derive_cgp_impl(args: ImplArgs, item_impl: ItemImpl) -> syn::Result { - let item = ItemCgpImpl { args, item_impl }; + let item_cgp_impl = ItemCgpImpl { + args: args.clone(), + item_impl, + }; - let lowered = item.lower()?; + let lowered = item_cgp_impl.lower()?; if lowered.args.provider_type == parse_quote!(Self) { if lowered.item_impl.trait_.is_none() { @@ -30,21 +32,18 @@ pub fn derive_cgp_impl(args: ImplArgs, item_impl: ItemImpl) -> syn::Result derive_component_name_from_provider_impl(&provider_impl)?, }; - let is_provider_for_impl: ItemImpl = - derive_is_provider_for(&component_type, &provider_impl)?; - - let provider_struct = if lowered.args.new.is_some() { - Some(derive_provider_struct(&provider_impl)?) - } else { - None + let item_cgp_provider = ItemCgpProvider { + args: ProviderArgs { + new: args.new, + component_type: Some(component_type), + }, + item_impl: provider_impl, }; - Ok(quote! { - #provider_struct - - #provider_impl + let lowered = item_cgp_provider.lower()?; - #is_provider_for_impl + Ok(quote! { + #lowered }) } } diff --git a/crates/cgp-macro-lib/src/derive_provider/derive.rs b/crates/cgp-macro-lib/src/derive_provider/derive.rs index ec09d6d7..a339f5f7 100644 --- a/crates/cgp-macro-lib/src/derive_provider/derive.rs +++ b/crates/cgp-macro-lib/src/derive_provider/derive.rs @@ -1,40 +1,15 @@ use std::collections::BTreeMap; -use cgp_macro_core::types::ident::IdentWithTypeGenerics; use cgp_macro_core::visitors::replace_provider_in_generics; use proc_macro2::Span; -use quote::quote; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::token::{Comma, For}; use syn::{ - AngleBracketedGenericArguments, Error, GenericArgument, ItemImpl, ItemStruct, Path, - PathArguments, Type, parse_quote, + AngleBracketedGenericArguments, Error, GenericArgument, ItemImpl, Path, PathArguments, Type, + parse_quote, }; -pub fn derive_provider_struct(provider_impl: &ItemImpl) -> syn::Result { - let impl_self_type = &provider_impl.self_ty; - - let provider_type: IdentWithTypeGenerics = syn::parse2(quote!( #impl_self_type ))?; - - let provider_name = &provider_type.ident; - let type_generics_params = &provider_type.type_generics.params; - - let provider_struct = if type_generics_params.is_empty() { - parse_quote! { - pub struct #provider_name; - } - } else { - parse_quote! { - pub struct #provider_name<#type_generics_params>( - pub ::core::marker::PhantomData<(#type_generics_params)> - ); - } - }; - - Ok(provider_struct) -} - pub fn derive_is_provider_for( component_name: &Type, provider_impl: &ItemImpl, From 21dcdc15fc5223501052b87305cb4aa37f811548 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 6 Jun 2026 21:51:48 +0200 Subject: [PATCH 41/46] Fully migrate to new cgp_impl implementation --- .../src/types/cgp_impl/lowered.rs | 33 ++++++++++++- .../cgp-macro-core/src/types/cgp_impl/mod.rs | 2 + .../src/types/cgp_impl/provider_or_bare.rs | 21 ++++++++ crates/cgp-macro-lib/src/cgp_impl/derive.rs | 49 ------------------- crates/cgp-macro-lib/src/cgp_impl/mod.rs | 3 -- .../src/derive_provider/component_name.rs | 22 --------- .../cgp-macro-lib/src/derive_provider/mod.rs | 2 - .../cgp-macro-lib/src/entrypoints/cgp_impl.rs | 14 ++++-- crates/cgp-macro-lib/src/lib.rs | 1 - 9 files changed, 63 insertions(+), 84 deletions(-) create mode 100644 crates/cgp-macro-core/src/types/cgp_impl/provider_or_bare.rs delete mode 100644 crates/cgp-macro-lib/src/cgp_impl/derive.rs delete mode 100644 crates/cgp-macro-lib/src/cgp_impl/mod.rs delete mode 100644 crates/cgp-macro-lib/src/derive_provider/component_name.rs diff --git a/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs b/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs index 93a2f343..4084315c 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs @@ -1,11 +1,13 @@ use proc_macro2::Span; use quote::ToTokens; +use syn::spanned::Spanned; use syn::token::For; use syn::visit_mut::VisitMut; -use syn::{Ident, ImplItem, ItemImpl, Type, parse_quote, parse2}; +use syn::{Error, Ident, ImplItem, ItemImpl, Type, parse_quote, parse2}; use crate::functions::to_snake_case_ident; -use crate::types::cgp_impl::ImplArgs; +use crate::types::cgp_impl::{CgpProviderOrBareImpl, ImplArgs}; +use crate::types::cgp_provider::{ItemCgpProvider, ProviderArgs}; use crate::types::ident::IdentWithTypeArgs; use crate::visitors::{ ReplaceSelfReceiverVisitor, ReplaceSelfTypeVisitor, ReplaceSelfValueVisitor, @@ -19,6 +21,33 @@ pub struct LoweredCgpImpl { } impl LoweredCgpImpl { + pub fn lower(&self) -> syn::Result { + if self.args.provider_type == parse_quote!(Self) { + if self.item_impl.trait_.is_none() { + return Err(Error::new( + self.item_impl.span(), + "Expected context type to be specified", + )); + } + + Ok(CgpProviderOrBareImpl::Bare(self.item_impl.clone())) + } else { + let provider_impl = self.to_raw_item_impl()?; + + let item_cgp_provider = ItemCgpProvider { + args: ProviderArgs { + new: self.args.new.clone(), + component_type: self.args.component_type.clone(), + }, + item_impl: provider_impl, + }; + + let lowered = item_cgp_provider.lower()?; + + Ok(CgpProviderOrBareImpl::Provider(lowered)) + } + } + pub fn to_raw_item_impl(&self) -> syn::Result { let item_impl = &self.item_impl; let context_type = &self.context_type; diff --git a/crates/cgp-macro-core/src/types/cgp_impl/mod.rs b/crates/cgp-macro-core/src/types/cgp_impl/mod.rs index 0e0cf2f1..23c3960e 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/mod.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/mod.rs @@ -1,7 +1,9 @@ mod args; mod item; mod lowered; +mod provider_or_bare; pub use args::*; pub use item::*; pub use lowered::*; +pub use provider_or_bare::*; diff --git a/crates/cgp-macro-core/src/types/cgp_impl/provider_or_bare.rs b/crates/cgp-macro-core/src/types/cgp_impl/provider_or_bare.rs new file mode 100644 index 00000000..f3c9c11e --- /dev/null +++ b/crates/cgp-macro-core/src/types/cgp_impl/provider_or_bare.rs @@ -0,0 +1,21 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::ItemImpl; + +use crate::types::cgp_provider::LoweredCgpProvider; + +pub enum CgpProviderOrBareImpl { + Bare(ItemImpl), + Provider(LoweredCgpProvider), +} + +impl ToTokens for CgpProviderOrBareImpl { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + CgpProviderOrBareImpl::Bare(item_impl) => item_impl.to_tokens(tokens), + CgpProviderOrBareImpl::Provider(item_cgp_provider) => { + item_cgp_provider.to_tokens(tokens) + } + } + } +} diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs deleted file mode 100644 index 286dcfa4..00000000 --- a/crates/cgp-macro-lib/src/cgp_impl/derive.rs +++ /dev/null @@ -1,49 +0,0 @@ -use cgp_macro_core::types::cgp_impl::{ImplArgs, ItemCgpImpl}; -use cgp_macro_core::types::cgp_provider::{ItemCgpProvider, ProviderArgs}; -use proc_macro2::TokenStream; -use quote::{ToTokens, quote}; -use syn::spanned::Spanned; -use syn::{Error, ItemImpl, parse_quote}; - -use crate::derive_provider::derive_component_name_from_provider_impl; - -pub fn derive_cgp_impl(args: ImplArgs, item_impl: ItemImpl) -> syn::Result { - let item_cgp_impl = ItemCgpImpl { - args: args.clone(), - item_impl, - }; - - let lowered = item_cgp_impl.lower()?; - - if lowered.args.provider_type == parse_quote!(Self) { - if lowered.item_impl.trait_.is_none() { - return Err(Error::new( - lowered.item_impl.span(), - "Expected context type to be specified", - )); - } - - Ok(lowered.item_impl.to_token_stream()) - } else { - let provider_impl = lowered.to_raw_item_impl()?; - - let component_type = match &lowered.args.component_type { - Some(component_type) => component_type.clone(), - None => derive_component_name_from_provider_impl(&provider_impl)?, - }; - - let item_cgp_provider = ItemCgpProvider { - args: ProviderArgs { - new: args.new, - component_type: Some(component_type), - }, - item_impl: provider_impl, - }; - - let lowered = item_cgp_provider.lower()?; - - Ok(quote! { - #lowered - }) - } -} diff --git a/crates/cgp-macro-lib/src/cgp_impl/mod.rs b/crates/cgp-macro-lib/src/cgp_impl/mod.rs deleted file mode 100644 index 61eca8a7..00000000 --- a/crates/cgp-macro-lib/src/cgp_impl/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod derive; - -pub use derive::*; diff --git a/crates/cgp-macro-lib/src/derive_provider/component_name.rs b/crates/cgp-macro-lib/src/derive_provider/component_name.rs deleted file mode 100644 index f2729ba5..00000000 --- a/crates/cgp-macro-lib/src/derive_provider/component_name.rs +++ /dev/null @@ -1,22 +0,0 @@ -use cgp_macro_core::types::ident::IdentWithTypeArgs; -use quote::ToTokens; -use syn::spanned::Spanned; -use syn::{Error, Ident, ItemImpl, Type, parse2}; - -pub fn derive_component_name_from_provider_impl(provider_impl: &ItemImpl) -> syn::Result { - let (_, provider_trait_path, _) = provider_impl.trait_.as_ref().ok_or_else(|| { - Error::new( - provider_impl.span(), - "expect provider trait name to be present", - ) - })?; - - let provider_trait: IdentWithTypeArgs = parse2(provider_trait_path.to_token_stream())?; - - let component_ident = Ident::new( - &format!("{}Component", provider_trait.ident), - provider_trait.span(), - ); - - parse2(component_ident.to_token_stream()) -} diff --git a/crates/cgp-macro-lib/src/derive_provider/mod.rs b/crates/cgp-macro-lib/src/derive_provider/mod.rs index ad77d90a..61eca8a7 100644 --- a/crates/cgp-macro-lib/src/derive_provider/mod.rs +++ b/crates/cgp-macro-lib/src/derive_provider/mod.rs @@ -1,5 +1,3 @@ -mod component_name; mod derive; -pub use component_name::*; pub use derive::*; diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs index f5ac31ab..16ee9fe1 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs @@ -1,12 +1,16 @@ -use cgp_macro_core::types::cgp_impl::ImplArgs; +use cgp_macro_core::types::cgp_impl::{ImplArgs, ItemCgpImpl}; use proc_macro2::TokenStream; +use quote::ToTokens; use syn::{ItemImpl, parse2}; -use crate::cgp_impl::derive_cgp_impl; - pub fn cgp_impl(attr: TokenStream, body: TokenStream) -> syn::Result { - let spec: ImplArgs = parse2(attr)?; + let args: ImplArgs = parse2(attr)?; let item_impl: ItemImpl = parse2(body)?; - derive_cgp_impl(spec, item_impl) + let item_cgp_impl = ItemCgpImpl { args, item_impl }; + + let lowered = item_cgp_impl.lower()?; + let lowered = lowered.lower()?; + + Ok(lowered.to_token_stream()) } diff --git a/crates/cgp-macro-lib/src/lib.rs b/crates/cgp-macro-lib/src/lib.rs index 3969a465..95e2a230 100644 --- a/crates/cgp-macro-lib/src/lib.rs +++ b/crates/cgp-macro-lib/src/lib.rs @@ -10,7 +10,6 @@ extern crate alloc; pub(crate) mod attributes; pub(crate) mod blanket_trait; pub(crate) mod cgp_fn; -pub(crate) mod cgp_impl; pub(crate) mod check_components; pub(crate) mod delegate_components; pub(crate) mod derive_builder; From b2a1521d55ef945f1a994bb91d89a4319f5bbd38 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 6 Jun 2026 22:07:47 +0200 Subject: [PATCH 42/46] Implement IsProviderFor --- .../src/types/cgp_provider/item.rs | 55 +++---------------- .../src/types/is_provider_for.rs | 52 ++++++++++++++++++ crates/cgp-macro-core/src/types/mod.rs | 1 + 3 files changed, 62 insertions(+), 46 deletions(-) create mode 100644 crates/cgp-macro-core/src/types/is_provider_for.rs diff --git a/crates/cgp-macro-core/src/types/cgp_provider/item.rs b/crates/cgp-macro-core/src/types/cgp_provider/item.rs index ed911ca7..6c953b3c 100644 --- a/crates/cgp-macro-core/src/types/cgp_provider/item.rs +++ b/crates/cgp-macro-core/src/types/cgp_provider/item.rs @@ -1,14 +1,10 @@ -use std::collections::BTreeMap; - -use proc_macro2::Span; use quote::ToTokens; use syn::spanned::Spanned; -use syn::token::For; -use syn::{Error, Ident, ItemImpl, ItemStruct, Path, Type, parse_quote, parse2}; +use syn::{Error, Ident, ItemImpl, ItemStruct, Type, parse_quote, parse2}; -use crate::types::cgp_provider::{LoweredCgpProvider, ProviderArgs, ProviderImplArgs}; +use crate::types::cgp_provider::{LoweredCgpProvider, ProviderArgs}; use crate::types::ident::{IdentWithTypeArgs, IdentWithTypeGenerics}; -use crate::visitors::replace_provider_in_generics; +use crate::types::is_provider_for::IsProviderFor; pub struct ItemCgpProvider { pub args: ProviderArgs, @@ -17,9 +13,14 @@ pub struct ItemCgpProvider { impl ItemCgpProvider { pub fn lower(&self) -> syn::Result { - let is_provider_for_impl = self.to_is_provider_for_impl()?; let provider_struct = self.to_provider_struct()?; + let is_provider_for_impl = IsProviderFor { + component_type: self.component_type()?, + item_impl: self.item_impl.clone(), + } + .lower()?; + Ok(LoweredCgpProvider { item_impl: self.item_impl.clone(), is_provider_for_impl, @@ -44,44 +45,6 @@ impl ItemCgpProvider { parse2(component_ident.to_token_stream()) } - pub fn to_is_provider_for_impl(&self) -> syn::Result { - let component_name = self.component_type()?; - - let provider_impl = &self.item_impl; - - let (_, provider_path, _) = provider_impl.trait_.as_ref().ok_or_else(|| { - Error::new( - provider_impl.span(), - "provider impl should contain trait path", - ) - })?; - - let IdentWithTypeArgs { - ident: provider_ident, - type_args: provider_generics, - } = parse2(provider_path.to_token_stream())?; - - let impl_args = ProviderImplArgs::from_generic_args(&provider_generics)?; - let context_type = &impl_args.context_type; - - let is_provider_path: Path = - parse_quote!( IsProviderFor < #component_name, #context_type, ( #impl_args ) > ); - - let mut is_provider_impl = provider_impl.clone(); - - is_provider_impl.attrs.clear(); - is_provider_impl.items.clear(); - is_provider_impl.defaultness = None; - is_provider_impl.unsafety = None; - - is_provider_impl.trait_ = Some((None, is_provider_path, For(Span::call_site()))); - - let provider_map = BTreeMap::from([(provider_ident.clone(), component_name.clone())]); - replace_provider_in_generics(&provider_map, &mut is_provider_impl.generics); - - Ok(is_provider_impl) - } - pub fn to_provider_struct(&self) -> syn::Result> { if self.args.new.is_none() { return Ok(None); diff --git a/crates/cgp-macro-core/src/types/is_provider_for.rs b/crates/cgp-macro-core/src/types/is_provider_for.rs new file mode 100644 index 00000000..85d3c786 --- /dev/null +++ b/crates/cgp-macro-core/src/types/is_provider_for.rs @@ -0,0 +1,52 @@ +use std::collections::BTreeMap; + +use proc_macro2::Span; +use quote::ToTokens; +use syn::spanned::Spanned; +use syn::token::For; +use syn::{Error, ItemImpl, Path, Type, parse_quote, parse2}; + +use crate::types::cgp_provider::ProviderImplArgs; +use crate::types::ident::IdentWithTypeArgs; +use crate::visitors::replace_provider_in_generics; + +pub struct IsProviderFor { + pub component_type: Type, + pub item_impl: ItemImpl, +} + +impl IsProviderFor { + pub fn lower(&self) -> syn::Result { + let component_type = &self.component_type; + let item_impl = &self.item_impl; + + let (_, provider_path, _) = item_impl.trait_.as_ref().ok_or_else(|| { + Error::new(item_impl.span(), "provider impl should contain trait path") + })?; + + let IdentWithTypeArgs { + ident: provider_ident, + type_args: provider_generics, + } = parse2(provider_path.to_token_stream())?; + + let impl_args = ProviderImplArgs::from_generic_args(&provider_generics)?; + let context_type = &impl_args.context_type; + + let is_provider_path: Path = + parse_quote!( IsProviderFor < #component_type, #context_type, ( #impl_args ) > ); + + let mut is_provider_impl = item_impl.clone(); + + is_provider_impl.attrs.clear(); + is_provider_impl.items.clear(); + is_provider_impl.defaultness = None; + is_provider_impl.unsafety = None; + + is_provider_impl.trait_ = Some((None, is_provider_path, For(Span::call_site()))); + + let provider_map = BTreeMap::from([(provider_ident.clone(), component_type.clone())]); + replace_provider_in_generics(&provider_map, &mut is_provider_impl.generics); + + Ok(is_provider_impl) + } +} diff --git a/crates/cgp-macro-core/src/types/mod.rs b/crates/cgp-macro-core/src/types/mod.rs index 652db583..fa03e43d 100644 --- a/crates/cgp-macro-core/src/types/mod.rs +++ b/crates/cgp-macro-core/src/types/mod.rs @@ -7,6 +7,7 @@ pub mod generics; pub mod getter; pub mod ident; pub mod implicits; +pub mod is_provider_for; pub mod keyword; pub mod keywords; pub mod namespace; From e07a18b050937c329ad208e4087850219e96a86c Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 6 Jun 2026 22:12:14 +0200 Subject: [PATCH 43/46] Use IsProviderFor to implement derive_is_provider_for --- .../src/types/is_provider_for.rs | 11 +++ .../src/derive_component/derive.rs | 2 +- .../src/derive_provider/derive.rs | 91 ------------------- .../cgp-macro-lib/src/derive_provider/mod.rs | 3 - .../src/entrypoints/cgp_getter.rs | 2 +- crates/cgp-macro-lib/src/lib.rs | 1 - .../src/type_component/derive.rs | 2 +- 7 files changed, 14 insertions(+), 98 deletions(-) delete mode 100644 crates/cgp-macro-lib/src/derive_provider/derive.rs delete mode 100644 crates/cgp-macro-lib/src/derive_provider/mod.rs diff --git a/crates/cgp-macro-core/src/types/is_provider_for.rs b/crates/cgp-macro-core/src/types/is_provider_for.rs index 85d3c786..99ac962d 100644 --- a/crates/cgp-macro-core/src/types/is_provider_for.rs +++ b/crates/cgp-macro-core/src/types/is_provider_for.rs @@ -10,6 +10,17 @@ use crate::types::cgp_provider::ProviderImplArgs; use crate::types::ident::IdentWithTypeArgs; use crate::visitors::replace_provider_in_generics; +pub fn derive_is_provider_for( + component_type: &Type, + item_impl: &ItemImpl, +) -> syn::Result { + IsProviderFor { + component_type: component_type.clone(), + item_impl: item_impl.clone(), + } + .lower() +} + pub struct IsProviderFor { pub component_type: Type, pub item_impl: ItemImpl, diff --git a/crates/cgp-macro-lib/src/derive_component/derive.rs b/crates/cgp-macro-lib/src/derive_component/derive.rs index 1f024499..740dee69 100644 --- a/crates/cgp-macro-lib/src/derive_component/derive.rs +++ b/crates/cgp-macro-lib/src/derive_component/derive.rs @@ -1,3 +1,4 @@ +use cgp_macro_core::types::is_provider_for::derive_is_provider_for; use proc_macro2::TokenStream; use quote::{ToTokens, TokenStreamExt, quote}; use syn::{ItemImpl, ItemStruct, ItemTrait, parse2}; @@ -12,7 +13,6 @@ use crate::derive_component::provider_impl::derive_provider_impl; use crate::derive_component::provider_trait::derive_provider_trait; use crate::derive_component::use_context_impl::derive_use_context_impl; use crate::derive_component::use_delegate_impl::derive_delegate_impl; -use crate::derive_provider::derive_is_provider_for; use crate::parse::ComponentSpec; pub fn derive_component_with_ast( diff --git a/crates/cgp-macro-lib/src/derive_provider/derive.rs b/crates/cgp-macro-lib/src/derive_provider/derive.rs deleted file mode 100644 index a339f5f7..00000000 --- a/crates/cgp-macro-lib/src/derive_provider/derive.rs +++ /dev/null @@ -1,91 +0,0 @@ -use std::collections::BTreeMap; - -use cgp_macro_core::visitors::replace_provider_in_generics; -use proc_macro2::Span; -use syn::punctuated::Punctuated; -use syn::spanned::Spanned; -use syn::token::{Comma, For}; -use syn::{ - AngleBracketedGenericArguments, Error, GenericArgument, ItemImpl, Path, PathArguments, Type, - parse_quote, -}; - -pub fn derive_is_provider_for( - component_name: &Type, - provider_impl: &ItemImpl, -) -> syn::Result { - let provider_path = provider_impl - .trait_ - .as_ref() - .ok_or_else(|| { - Error::new( - provider_impl.span(), - "provider impl should contain trait path", - ) - })? - .1 - .segments - .last() - .ok_or_else(|| { - Error::new( - provider_impl.span(), - "provider impl should contain trait path containing generic parameters", - ) - })?; - - let provider_map = BTreeMap::from([(provider_path.ident.clone(), component_name.clone())]); - - let is_provider_generics: AngleBracketedGenericArguments = match &provider_path.arguments { - PathArguments::AngleBracketed(generics) => { - let mut generic_args = generics.clone().args.into_iter(); - - let mut is_provider_params: Punctuated = Punctuated::default(); - - let mut context_arg: Option = None; - - for arg in generic_args.by_ref() { - if let GenericArgument::Lifetime(life) = arg { - // Lifetime params are forced to be pushed to the front of a provider trait. - // Skip those and put them in the form of `Life<'a>` inside the IsProviderFor params - is_provider_params.push(parse_quote! { Life<#life> }) - } else { - // Find the first non-lifetime context type argument and break - context_arg = Some(arg); - break; - } - } - - let context_arg = context_arg.ok_or_else(|| { - Error::new( - provider_impl.span(), - "provider impl should contain trait path containing at least one generic parameter", - ) - })?; - - is_provider_params.extend(generic_args); - - parse_quote!( < #component_name, #context_arg, ( #is_provider_params ) > ) - } - _ => { - return Err(Error::new( - provider_impl.span(), - "provider impl should contain trait path containing generic parameters", - )); - } - }; - - let is_provider_path: Path = parse_quote!( IsProviderFor #is_provider_generics ); - - let mut is_provider_impl = provider_impl.clone(); - - is_provider_impl.attrs.clear(); - is_provider_impl.items.clear(); - is_provider_impl.defaultness = None; - is_provider_impl.unsafety = None; - - is_provider_impl.trait_ = Some((None, is_provider_path, For(Span::call_site()))); - - replace_provider_in_generics(&provider_map, &mut is_provider_impl.generics); - - Ok(is_provider_impl) -} diff --git a/crates/cgp-macro-lib/src/derive_provider/mod.rs b/crates/cgp-macro-lib/src/derive_provider/mod.rs deleted file mode 100644 index 61eca8a7..00000000 --- a/crates/cgp-macro-lib/src/derive_provider/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod derive; - -pub use derive::*; diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_getter.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_getter.rs index 9c97bf6a..dcc319a3 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_getter.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_getter.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::collections::btree_map::Entry; +use cgp_macro_core::types::is_provider_for::derive_is_provider_for; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::{Ident, ItemTrait, Type, parse_quote, parse2}; @@ -12,7 +13,6 @@ use crate::derive_getter::{ GetterField, derive_use_field_impl, derive_use_fields_impl, derive_with_provider_impl, parse_getter_fields, }; -use crate::derive_provider::derive_is_provider_for; use crate::parse::{ComponentSpec, Entries}; pub fn cgp_getter(attr: TokenStream, body: TokenStream) -> syn::Result { diff --git a/crates/cgp-macro-lib/src/lib.rs b/crates/cgp-macro-lib/src/lib.rs index 95e2a230..421bede0 100644 --- a/crates/cgp-macro-lib/src/lib.rs +++ b/crates/cgp-macro-lib/src/lib.rs @@ -17,7 +17,6 @@ pub(crate) mod derive_component; pub(crate) mod derive_extractor; pub(crate) mod derive_getter; pub(crate) mod derive_has_fields; -pub(crate) mod derive_provider; pub(crate) mod field; pub(crate) mod for_each_replace; pub(crate) mod parse; diff --git a/crates/cgp-macro-lib/src/type_component/derive.rs b/crates/cgp-macro-lib/src/type_component/derive.rs index 53b18322..4671f6a7 100644 --- a/crates/cgp-macro-lib/src/type_component/derive.rs +++ b/crates/cgp-macro-lib/src/type_component/derive.rs @@ -1,10 +1,10 @@ use alloc::vec::Vec; +use cgp_macro_core::types::is_provider_for::derive_is_provider_for; use quote::{ToTokens, quote}; use syn::spanned::Spanned; use syn::{Error, Generics, ItemImpl, ItemTrait, TraitItem, TraitItemType, Type, parse2}; -use crate::derive_provider::derive_is_provider_for; use crate::parse::ComponentSpec; use crate::type_component::replace::get_bounds_and_replace_self_assoc_type; From 274b88f1a3f12d63253deb05346130d36eb3ba35 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 6 Jun 2026 22:13:01 +0200 Subject: [PATCH 44/46] Rename to ItemIsProviderFor --- crates/cgp-macro-core/src/types/cgp_provider/item.rs | 4 ++-- crates/cgp-macro-core/src/types/is_provider_for.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/cgp-macro-core/src/types/cgp_provider/item.rs b/crates/cgp-macro-core/src/types/cgp_provider/item.rs index 6c953b3c..d522e59e 100644 --- a/crates/cgp-macro-core/src/types/cgp_provider/item.rs +++ b/crates/cgp-macro-core/src/types/cgp_provider/item.rs @@ -4,7 +4,7 @@ use syn::{Error, Ident, ItemImpl, ItemStruct, Type, parse_quote, parse2}; use crate::types::cgp_provider::{LoweredCgpProvider, ProviderArgs}; use crate::types::ident::{IdentWithTypeArgs, IdentWithTypeGenerics}; -use crate::types::is_provider_for::IsProviderFor; +use crate::types::is_provider_for::ItemIsProviderFor; pub struct ItemCgpProvider { pub args: ProviderArgs, @@ -15,7 +15,7 @@ impl ItemCgpProvider { pub fn lower(&self) -> syn::Result { let provider_struct = self.to_provider_struct()?; - let is_provider_for_impl = IsProviderFor { + let is_provider_for_impl = ItemIsProviderFor { component_type: self.component_type()?, item_impl: self.item_impl.clone(), } diff --git a/crates/cgp-macro-core/src/types/is_provider_for.rs b/crates/cgp-macro-core/src/types/is_provider_for.rs index 99ac962d..e793de78 100644 --- a/crates/cgp-macro-core/src/types/is_provider_for.rs +++ b/crates/cgp-macro-core/src/types/is_provider_for.rs @@ -14,19 +14,19 @@ pub fn derive_is_provider_for( component_type: &Type, item_impl: &ItemImpl, ) -> syn::Result { - IsProviderFor { + ItemIsProviderFor { component_type: component_type.clone(), item_impl: item_impl.clone(), } .lower() } -pub struct IsProviderFor { +pub struct ItemIsProviderFor { pub component_type: Type, pub item_impl: ItemImpl, } -impl IsProviderFor { +impl ItemIsProviderFor { pub fn lower(&self) -> syn::Result { let component_type = &self.component_type; let item_impl = &self.item_impl; From c0d7cd2098467d804bed42c4c3cb28b6fccb1aea Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 6 Jun 2026 22:14:13 +0200 Subject: [PATCH 45/46] Fix clippy --- .../attributes/use_provider/attributes.rs | 2 +- .../src/types/cgp_impl/lowered.rs | 4 +-- .../src/types/implicits/arg_field.rs | 2 +- .../replace_self/replace_self_type.rs | 29 +++++++++---------- .../src/visitors/substitute_abstract_type.rs | 23 ++++++++------- .../src/derive_getter/blanket.rs | 2 +- .../src/derive_getter/use_field.rs | 2 +- .../src/derive_getter/use_fields.rs | 2 +- 8 files changed, 33 insertions(+), 33 deletions(-) diff --git a/crates/cgp-macro-core/src/types/attributes/use_provider/attributes.rs b/crates/cgp-macro-core/src/types/attributes/use_provider/attributes.rs index 2aae24c3..dc4ae554 100644 --- a/crates/cgp-macro-core/src/types/attributes/use_provider/attributes.rs +++ b/crates/cgp-macro-core/src/types/attributes/use_provider/attributes.rs @@ -17,7 +17,7 @@ impl AddTypeParamBounds for UseProviderAttributes { let where_clause = generics.make_where_clause(); for use_provider in &self.attributes { - let predicate = use_provider.to_provider_bounds(&self_type)?; + let predicate = use_provider.to_provider_bounds(self_type)?; where_clause.predicates.push(predicate); } diff --git a/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs b/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs index 4084315c..27315ecb 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs @@ -90,14 +90,14 @@ impl LoweredCgpImpl { )); ReplaceSelfTypeVisitor { - replaced_type: &context_type, + replaced_type: context_type, skip_assoc_types: &local_assoc_types, } .visit_item_impl_mut(&mut out_impl); ReplaceSelfReceiverVisitor { replaced_ident: &context_ident, - replaced_type: &context_type, + replaced_type: context_type, } .visit_item_impl_mut(&mut out_impl); diff --git a/crates/cgp-macro-core/src/types/implicits/arg_field.rs b/crates/cgp-macro-core/src/types/implicits/arg_field.rs index 3428b0f2..da7ff56a 100644 --- a/crates/cgp-macro-core/src/types/implicits/arg_field.rs +++ b/crates/cgp-macro-core/src/types/implicits/arg_field.rs @@ -20,7 +20,7 @@ impl ImplicitArgField { Ok(HasFieldBound { field_type: self.field_type.clone(), - field_mut: self.field_mut.clone(), + field_mut: self.field_mut, field_mode: self.field_mode.clone(), tag_type, }) diff --git a/crates/cgp-macro-core/src/visitors/replace_self/replace_self_type.rs b/crates/cgp-macro-core/src/visitors/replace_self/replace_self_type.rs index 5251394a..891514b0 100644 --- a/crates/cgp-macro-core/src/visitors/replace_self/replace_self_type.rs +++ b/crates/cgp-macro-core/src/visitors/replace_self/replace_self_type.rs @@ -20,13 +20,13 @@ impl<'a> ReplaceSelfTypeVisitor<'a> { if path.segments.len() >= 2 && self.skip_assoc_types.contains(&path.segments[1].ident) { return; } - if let Type::Path(replaced) = self.replaced_type { - if replaced.qself.is_none() { - let rest: Vec<_> = path.segments.iter().skip(1).cloned().collect(); - let mut new_path = replaced.path.clone(); - new_path.segments.extend(rest); - *path = new_path; - } + if let Type::Path(replaced) = self.replaced_type + && replaced.qself.is_none() + { + let rest: Vec<_> = path.segments.iter().skip(1).cloned().collect(); + let mut new_path = replaced.path.clone(); + new_path.segments.extend(rest); + *path = new_path; } } } @@ -35,14 +35,13 @@ impl VisitMut for ReplaceSelfTypeVisitor<'_> { fn visit_type_mut(&mut self, ty: &mut Type) { // Handle standalone `Self` type — replaced_type may not be a path (e.g. a reference), // so we must replace the whole Type node here rather than going through visit_path_mut. - if let Type::Path(type_path) = ty { - if type_path.qself.is_none() - && type_path.path.segments.len() == 1 - && type_path.path.segments[0].ident == "Self" - { - *ty = self.replaced_type.clone(); - return; - } + if let Type::Path(type_path) = ty + && type_path.qself.is_none() + && type_path.path.segments.len() == 1 + && type_path.path.segments[0].ident == "Self" + { + *ty = self.replaced_type.clone(); + return; } visit_mut::visit_type_mut(self, ty); } diff --git a/crates/cgp-macro-core/src/visitors/substitute_abstract_type.rs b/crates/cgp-macro-core/src/visitors/substitute_abstract_type.rs index 6a1e42f6..59dbfd39 100644 --- a/crates/cgp-macro-core/src/visitors/substitute_abstract_type.rs +++ b/crates/cgp-macro-core/src/visitors/substitute_abstract_type.rs @@ -9,17 +9,18 @@ pub struct SubstituteAbstractType<'a> { impl VisitMut for SubstituteAbstractType<'_> { fn visit_type_mut(&mut self, ty: &mut Type) { - if let Type::Path(TypePath { qself: None, path }) = ty { - if path.leading_colon.is_none() && path.segments.len() == 1 { - let segment = &path.segments[0]; - if matches!(segment.arguments, PathArguments::None) { - if let Some(replacement_ident) = self.type_spec.replace_ident(&segment.ident) { - let trait_path = &self.type_spec.trait_path; - let context_type = &self.type_spec.context_type; - *ty = parse_quote! { <#context_type as #trait_path>::#replacement_ident }; - return; - } - } + if let Type::Path(TypePath { qself: None, path }) = ty + && path.leading_colon.is_none() + && path.segments.len() == 1 + { + let segment = &path.segments[0]; + if matches!(segment.arguments, PathArguments::None) + && let Some(replacement_ident) = self.type_spec.replace_ident(&segment.ident) + { + let trait_path = &self.type_spec.trait_path; + let context_type = &self.type_spec.context_type; + *ty = parse_quote! { <#context_type as #trait_path>::#replacement_ident }; + return; } } visit_mut::visit_type_mut(self, ty); diff --git a/crates/cgp-macro-lib/src/derive_getter/blanket.rs b/crates/cgp-macro-lib/src/derive_getter/blanket.rs index a418c809..777b2ef9 100644 --- a/crates/cgp-macro-lib/src/derive_getter/blanket.rs +++ b/crates/cgp-macro-lib/src/derive_getter/blanket.rs @@ -81,7 +81,7 @@ pub fn derive_blanket_impl( let constraint = HasFieldBound { field_type, - field_mut: field.receiver_mut.clone(), + field_mut: field.receiver_mut, field_mode: field.field_mode.clone(), tag_type, }; diff --git a/crates/cgp-macro-lib/src/derive_getter/use_field.rs b/crates/cgp-macro-lib/src/derive_getter/use_field.rs index cad88f85..2c5da4f9 100644 --- a/crates/cgp-macro-lib/src/derive_getter/use_field.rs +++ b/crates/cgp-macro-lib/src/derive_getter/use_field.rs @@ -71,7 +71,7 @@ pub fn derive_use_field_impl( let constraint = HasFieldBound { field_type, - field_mut: field.receiver_mut.clone(), + field_mut: field.receiver_mut, field_mode: field.field_mode.clone(), tag_type: tag_type.clone(), }; diff --git a/crates/cgp-macro-lib/src/derive_getter/use_fields.rs b/crates/cgp-macro-lib/src/derive_getter/use_fields.rs index a2aa03a4..901e5a38 100644 --- a/crates/cgp-macro-lib/src/derive_getter/use_fields.rs +++ b/crates/cgp-macro-lib/src/derive_getter/use_fields.rs @@ -72,7 +72,7 @@ pub fn derive_use_fields_impl( let constraint = HasFieldBound { field_type, - field_mut: field.receiver_mut.clone(), + field_mut: field.receiver_mut, field_mode: field.field_mode.clone(), tag_type: tag_type.clone(), }; From a2a48b6453d9afea6404a7f0ea9f62d182d14fe9 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 6 Jun 2026 22:16:43 +0200 Subject: [PATCH 46/46] Fix clippy --- crates/cgp-macro-core/src/types/cgp_impl/lowered.rs | 6 ++++-- .../cgp-macro-core/src/types/cgp_impl/provider_or_bare.rs | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs b/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs index 27315ecb..bb1cf48e 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/lowered.rs @@ -30,7 +30,9 @@ impl LoweredCgpImpl { )); } - Ok(CgpProviderOrBareImpl::Bare(self.item_impl.clone())) + Ok(CgpProviderOrBareImpl::Bare(Box::new( + self.item_impl.clone(), + ))) } else { let provider_impl = self.to_raw_item_impl()?; @@ -44,7 +46,7 @@ impl LoweredCgpImpl { let lowered = item_cgp_provider.lower()?; - Ok(CgpProviderOrBareImpl::Provider(lowered)) + Ok(CgpProviderOrBareImpl::Provider(Box::new(lowered))) } } diff --git a/crates/cgp-macro-core/src/types/cgp_impl/provider_or_bare.rs b/crates/cgp-macro-core/src/types/cgp_impl/provider_or_bare.rs index f3c9c11e..34b38b80 100644 --- a/crates/cgp-macro-core/src/types/cgp_impl/provider_or_bare.rs +++ b/crates/cgp-macro-core/src/types/cgp_impl/provider_or_bare.rs @@ -5,8 +5,8 @@ use syn::ItemImpl; use crate::types::cgp_provider::LoweredCgpProvider; pub enum CgpProviderOrBareImpl { - Bare(ItemImpl), - Provider(LoweredCgpProvider), + Bare(Box), + Provider(Box), } impl ToTokens for CgpProviderOrBareImpl {