diff --git a/crates/cgp-macro-lib/src/cgp_fn/attributes.rs b/crates/cgp-macro-lib/src/cgp_fn/attributes.rs index 3a7653a5..9f6e30f6 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/attributes.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/attributes.rs @@ -1,6 +1,6 @@ use syn::punctuated::Punctuated; use syn::token::Comma; -use syn::{Attribute, TypeParamBound, WherePredicate}; +use syn::{Attribute, GenericParam, TypeParamBound, WherePredicate}; use crate::cgp_fn::{FunctionAttributes, UseTypeSpec}; use crate::cgp_impl::UseProviderSpec; @@ -17,23 +17,33 @@ pub fn parse_function_attributes( 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.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); } 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 5b784350..d17b80f0 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs @@ -30,6 +30,11 @@ pub fn derive_item_impl( .params .insert(0, parse2(quote! { __Context__ })?); + item_impl + .generics + .params + .extend(attributes.impl_generics.clone()); + { let mut bounds: Punctuated = Punctuated::default(); bounds.extend(attributes.extend.clone()); diff --git a/crates/cgp-macro-lib/src/cgp_fn/spec.rs b/crates/cgp-macro-lib/src/cgp_fn/spec.rs index 92fec38b..3dc2ad94 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/spec.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/spec.rs @@ -1,5 +1,5 @@ use syn::token::Mut; -use syn::{Ident, Type, TypeParamBound, WherePredicate}; +use syn::{GenericParam, Ident, Type, TypeParamBound, WherePredicate}; use crate::cgp_fn::UseTypeSpec; use crate::cgp_impl::UseProviderSpec; @@ -22,4 +22,5 @@ pub struct FunctionAttributes { pub uses: Vec, pub use_type: Vec, pub use_provider: Vec, + pub impl_generics: Vec, } diff --git a/crates/cgp-tests/tests/cgp_fn_tests/impl_generics.rs b/crates/cgp-tests/tests/cgp_fn_tests/impl_generics.rs new file mode 100644 index 00000000..65f0e629 --- /dev/null +++ b/crates/cgp-tests/tests/cgp_fn_tests/impl_generics.rs @@ -0,0 +1,32 @@ +use core::fmt::Display; + +use cgp::prelude::*; + +#[cgp_fn] +#[impl_generics(Name: Display)] +pub fn greet(&self, #[implicit] name: &Name) -> String +where + Name: Display, +{ + format!("Hello, {}!", name) +} + +#[cgp_fn] +#[uses(Greet)] +pub fn test_greet(&self) { + assert_eq!(self.greet(), "Hello, John!"); +} + +#[derive(HasField)] +pub struct Person { + pub name: String, +} + +#[test] +fn test_impl_generics() { + let person = Person { + name: "John".to_string(), + }; + + person.test_greet(); +} diff --git a/crates/cgp-tests/tests/cgp_fn_tests/mod.rs b/crates/cgp-tests/tests/cgp_fn_tests/mod.rs index 829f72ac..e4c5804e 100644 --- a/crates/cgp-tests/tests/cgp_fn_tests/mod.rs +++ b/crates/cgp-tests/tests/cgp_fn_tests/mod.rs @@ -5,6 +5,7 @@ pub mod extend; pub mod foreign_type; pub mod foreign_type_equality; pub mod generics; +pub mod impl_generics; pub mod multi; pub mod mutable; pub mod nested_foreign_type;