From 2eb8a9c5245cae95fdfd003f86de4b8d3062b120 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 27 Feb 2026 23:05:28 +0100 Subject: [PATCH 1/3] Support `#[use_provider]` inside `#[cgp_fn]` --- crates/cgp-macro-lib/src/cgp_fn/attributes.rs | 5 +++++ crates/cgp-macro-lib/src/cgp_fn/item_impl.rs | 12 +++++++++++- crates/cgp-macro-lib/src/cgp_fn/spec.rs | 2 ++ crates/cgp-macro-lib/src/cgp_impl/mod.rs | 2 ++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/crates/cgp-macro-lib/src/cgp_fn/attributes.rs b/crates/cgp-macro-lib/src/cgp_fn/attributes.rs index 0645c0fc..433edc08 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/attributes.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/attributes.rs @@ -5,6 +5,7 @@ use syn::token::Comma; use syn::{Attribute, TypeParamBound, WherePredicate}; use crate::cgp_fn::{FunctionAttributes, UseTypeSpec}; +use crate::cgp_impl::UseProviderSpec; use crate::parse::SimpleType; pub fn parse_function_attributes( @@ -32,6 +33,10 @@ pub fn parse_function_attributes( 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); } 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 ec369dd1..5b784350 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs @@ -1,12 +1,13 @@ use quote::quote; use syn::punctuated::Punctuated; use syn::token::Plus; -use syn::{Generics, Ident, ItemFn, ItemImpl, TypeParamBound, parse2}; +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, }; +use crate::cgp_impl::derive_provider_bounds; pub fn derive_item_impl( trait_ident: &Ident, @@ -69,5 +70,14 @@ pub fn derive_item_impl( item_impl = apply_use_type_attributes_to_item_impl(&item_impl, &attributes.use_type)?; } + 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); + } + } + Ok(item_impl) } diff --git a/crates/cgp-macro-lib/src/cgp_fn/spec.rs b/crates/cgp-macro-lib/src/cgp_fn/spec.rs index aed51337..92fec38b 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/spec.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/spec.rs @@ -2,6 +2,7 @@ use syn::token::Mut; use syn::{Ident, Type, TypeParamBound, WherePredicate}; use crate::cgp_fn::UseTypeSpec; +use crate::cgp_impl::UseProviderSpec; use crate::derive_getter::FieldMode; use crate::parse::SimpleType; @@ -20,4 +21,5 @@ pub struct FunctionAttributes { pub extend_where: Vec, pub uses: Vec, pub use_type: Vec, + pub use_provider: Vec, } diff --git a/crates/cgp-macro-lib/src/cgp_impl/mod.rs b/crates/cgp-macro-lib/src/cgp_impl/mod.rs index 9ee4d384..ae07c33d 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/mod.rs @@ -9,6 +9,8 @@ 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::*; From c26f9878d2cf034934e0503d26df0e0d619d2aae Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 27 Feb 2026 23:07:57 +0100 Subject: [PATCH 2/3] Test #[use_provider] --- crates/cgp-tests/tests/cgp_fn_tests/mod.rs | 1 + .../tests/cgp_fn_tests/use_provider.rs | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 crates/cgp-tests/tests/cgp_fn_tests/use_provider.rs diff --git a/crates/cgp-tests/tests/cgp_fn_tests/mod.rs b/crates/cgp-tests/tests/cgp_fn_tests/mod.rs index ce42cf2f..380c7b91 100644 --- a/crates/cgp-tests/tests/cgp_fn_tests/mod.rs +++ b/crates/cgp-tests/tests/cgp_fn_tests/mod.rs @@ -11,3 +11,4 @@ pub mod type_equality; pub mod use_type; pub mod use_type_alias; pub mod uses; +pub mod use_provider; \ No newline at end of file diff --git a/crates/cgp-tests/tests/cgp_fn_tests/use_provider.rs b/crates/cgp-tests/tests/cgp_fn_tests/use_provider.rs new file mode 100644 index 00000000..aaa6d77f --- /dev/null +++ b/crates/cgp-tests/tests/cgp_fn_tests/use_provider.rs @@ -0,0 +1,35 @@ +use cgp::prelude::*; + +#[cgp_component(AreaCalculator)] +pub trait CanCalculateArea { + fn area(&self) -> f64; +} + +#[cgp_impl(new RectangleAreaCalculator)] +impl AreaCalculator { + fn area(&self, #[implicit] width: f64, #[implicit] height: f64) -> f64 { + width * height + } +} + +#[cgp_fn] +#[use_provider(RectangleAreaCalculator: AreaCalculator)] +fn rectangle_area(&self) -> f64 { + RectangleAreaCalculator::area(self) +} + +#[derive(HasField)] +pub struct Rectangle { + pub width: f64, + pub height: f64, +} + +#[test] +fn test_use_provider() { + let rectangle = Rectangle { + width: 3.0, + height: 4.0, + }; + + assert_eq!(rectangle.rectangle_area(), 12.0); +} \ No newline at end of file From c5b37f9ba2143178437dd9397e5ae763111435c5 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 27 Feb 2026 23:09:41 +0100 Subject: [PATCH 3/3] Remove use of `#[use_provider]` for method call --- crates/cgp-macro-lib/src/cgp_impl/derive.rs | 3 - crates/cgp-macro-lib/src/cgp_impl/mod.rs | 1 - .../src/cgp_impl/provider_call.rs | 80 ------------------- crates/cgp-tests/tests/cgp_fn_tests/mod.rs | 2 +- .../tests/cgp_fn_tests/use_provider.rs | 2 +- .../component_tests/cgp_impl/impl_self.rs | 3 +- .../component_tests/cgp_impl/use_provider.rs | 5 +- 7 files changed, 4 insertions(+), 92 deletions(-) delete mode 100644 crates/cgp-macro-lib/src/cgp_impl/provider_call.rs diff --git a/crates/cgp-macro-lib/src/cgp_impl/derive.rs b/crates/cgp-macro-lib/src/cgp_impl/derive.rs index f903c250..d0460e67 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::{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::provider_call::transform_provider_call; use crate::cgp_impl::{ImplProviderSpec, derive_provider_impl, implicit_args}; use crate::derive_provider::{ derive_component_name_from_provider_impl, derive_is_provider_for, derive_provider_struct, @@ -58,8 +57,6 @@ pub fn derive_cgp_impl( let provider_bounds = derive_provider_bounds(&parse_quote! { Self }, spec)?; where_clause.predicates.push(provider_bounds); } - - transform_provider_call(&mut item_impl)?; } if spec.provider_type == parse_quote! { Self } { diff --git a/crates/cgp-macro-lib/src/cgp_impl/mod.rs b/crates/cgp-macro-lib/src/cgp_impl/mod.rs index ae07c33d..79e49bc4 100644 --- a/crates/cgp-macro-lib/src/cgp_impl/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_impl/mod.rs @@ -2,7 +2,6 @@ mod attributes; mod derive; mod implicit_args; mod provider_bounds; -mod provider_call; mod provider_impl; mod spec; mod transform; diff --git a/crates/cgp-macro-lib/src/cgp_impl/provider_call.rs b/crates/cgp-macro-lib/src/cgp_impl/provider_call.rs deleted file mode 100644 index 13b0f9e4..00000000 --- a/crates/cgp-macro-lib/src/cgp_impl/provider_call.rs +++ /dev/null @@ -1,80 +0,0 @@ -use quote::quote; -use syn::parse::Parse; -use syn::visit_mut::{VisitMut, visit_item_impl_mut}; -use syn::{Expr, ExprMethodCall, ItemImpl, Type, parse2}; - -pub fn transform_provider_call(item_impl: &mut ItemImpl) -> syn::Result<()> { - let mut visitor = TransformProviderCallVisitor::default(); - visit_item_impl_mut(&mut visitor, item_impl); - - if let Some(err) = visitor.error { - Err(err) - } else { - Ok(()) - } -} - -#[derive(Default)] -pub struct TransformProviderCallVisitor { - pub error: Option, -} - -impl VisitMut for TransformProviderCallVisitor { - fn visit_expr_mut(&mut self, expr: &mut syn::Expr) { - if self.error.is_some() { - return; - } - - if let syn::Expr::MethodCall(method_call) = expr { - match visit_provider_call(method_call) { - Ok(Some(new_expr)) => { - *expr = new_expr; - } - Ok(None) => {} - Err(e) => { - self.error = Some(e); - } - } - } - - syn::visit_mut::visit_expr_mut(self, expr); - } -} - -fn visit_provider_call(expr: &ExprMethodCall) -> syn::Result> { - let attributes = expr.attrs.clone(); - let mut out_attributes = Vec::new(); - - let mut m_use_provider = None; - - for attribute in attributes { - if attribute.path().is_ident("use_provider") { - if m_use_provider.is_some() { - return Err(syn::Error::new_spanned( - attribute, - "Multiple #[use_provider] attributes found", - )); - } - - m_use_provider = Some(attribute.parse_args_with(Type::parse)?); - } else { - out_attributes.push(attribute); - } - } - - if let Some(provider_type) = m_use_provider { - let mut args = expr.args.clone(); - args.insert(0, expr.receiver.as_ref().clone()); - - let method = &expr.method; - let turbofish = &expr.turbofish; - - let new_expr: Expr = parse2(quote! { - #provider_type::#method #turbofish ( #args ) - })?; - - Ok(Some(new_expr)) - } else { - Ok(None) - } -} diff --git a/crates/cgp-tests/tests/cgp_fn_tests/mod.rs b/crates/cgp-tests/tests/cgp_fn_tests/mod.rs index 380c7b91..5db1140a 100644 --- a/crates/cgp-tests/tests/cgp_fn_tests/mod.rs +++ b/crates/cgp-tests/tests/cgp_fn_tests/mod.rs @@ -8,7 +8,7 @@ pub mod multi; pub mod mutable; pub mod nested_foreign_type; pub mod type_equality; +pub mod use_provider; pub mod use_type; pub mod use_type_alias; pub mod uses; -pub mod use_provider; \ No newline at end of file diff --git a/crates/cgp-tests/tests/cgp_fn_tests/use_provider.rs b/crates/cgp-tests/tests/cgp_fn_tests/use_provider.rs index aaa6d77f..b6f32b2f 100644 --- a/crates/cgp-tests/tests/cgp_fn_tests/use_provider.rs +++ b/crates/cgp-tests/tests/cgp_fn_tests/use_provider.rs @@ -32,4 +32,4 @@ fn test_use_provider() { }; assert_eq!(rectangle.rectangle_area(), 12.0); -} \ No newline at end of file +} diff --git a/crates/cgp-tests/tests/component_tests/cgp_impl/impl_self.rs b/crates/cgp-tests/tests/component_tests/cgp_impl/impl_self.rs index b62a3ffa..214742f4 100644 --- a/crates/cgp-tests/tests/component_tests/cgp_impl/impl_self.rs +++ b/crates/cgp-tests/tests/component_tests/cgp_impl/impl_self.rs @@ -22,7 +22,6 @@ pub struct Rectangle { #[use_provider(RectangleArea: AreaCalculator)] impl CanCalculateArea for Rectangle { fn area(&self) -> f64 { - #[use_provider(RectangleArea)] - self.area() + RectangleArea::area(self) } } diff --git a/crates/cgp-tests/tests/component_tests/cgp_impl/use_provider.rs b/crates/cgp-tests/tests/component_tests/cgp_impl/use_provider.rs index 44e1a690..a8fa174d 100644 --- a/crates/cgp-tests/tests/component_tests/cgp_impl/use_provider.rs +++ b/crates/cgp-tests/tests/component_tests/cgp_impl/use_provider.rs @@ -16,10 +16,7 @@ impl AreaCalculator { #[use_provider(Inner: AreaCalculator)] impl AreaCalculator { fn area(&self, #[implicit] scale_factor: f64) -> f64 { - let base_area = #[use_provider(Inner)] - self.area(); - - base_area * scale_factor * scale_factor + Inner::area(self) * scale_factor * scale_factor } }