Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions crates/cgp-macro-lib/src/check_components/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ use crate::check_components::override_span;
use crate::parse::{CheckComponents, CheckEntry};

pub fn derive_check_components(spec: &CheckComponents) -> syn::Result<(ItemTrait, Vec<ItemImpl>)> {
if let Some(providers) = &spec.check_provider {
return derive_check_provider(spec, providers);
}

let mut item_impls = Vec::new();
let unit: Type = parse2(quote!(()))?;

Expand Down Expand Up @@ -42,3 +46,43 @@ pub fn derive_check_components(spec: &CheckComponents) -> syn::Result<(ItemTrait

Ok((item_trait, item_impls))
}

pub fn derive_check_provider(
spec: &CheckComponents,
providers: &[Type],
) -> syn::Result<(ItemTrait, Vec<ItemImpl>)> {
let mut item_impls = Vec::new();
let unit: Type = parse2(quote!(()))?;

let context_type = &spec.context_type;
let trait_name = &spec.trait_name;
let impl_generics = &spec.impl_generics;
let where_clause = &spec.where_clause;

let item_trait = parse2(quote! {
trait #trait_name <__Component__, __Params__: ?Sized>: IsProviderFor<__Component__, #context_type, __Params__> {}
})?;

for CheckEntry {
component_type,
component_params,
..
} in spec.check_entries.entries.iter()
{
let component_param = component_params.as_ref().unwrap_or(&unit);

for provider in providers {
let item_impl: ItemImpl = parse2(quote! {
impl #impl_generics
#trait_name < #component_type, #component_param >
for #provider
#where_clause
{}
})?;

item_impls.push(item_impl);
}
}

Ok((item_trait, item_impls))
}
14 changes: 9 additions & 5 deletions crates/cgp-macro-lib/src/entrypoints/check_components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@ use quote::{ToTokens, TokenStreamExt};
use syn::parse2;

use crate::check_components::derive_check_components;
use crate::parse::CheckComponents;
use crate::parse::CheckComponentsSpecs;

pub fn check_components(body: TokenStream) -> syn::Result<TokenStream> {
let spec: CheckComponents = parse2(body)?;
let spec: CheckComponentsSpecs = parse2(body)?;

let (item_trait, item_impls) = derive_check_components(&spec)?;
let mut out = TokenStream::new();

let mut out = item_trait.to_token_stream();
out.append_all(item_impls);
for spec in spec.specs {
let (item_trait, item_impls) = derive_check_components(&spec)?;

out.append_all(item_trait.to_token_stream());
out.append_all(item_impls);
}

Ok(out)
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub fn delegate_and_check_components(body: TokenStream) -> syn::Result<TokenStre
impl_delegate_components(&spec.provider_type, &spec.impl_generics, &delegate_entries)?;

let check_spec = CheckComponents {
check_provider: None,
impl_generics: spec.impl_generics,
trait_name: spec.trait_name,
context_type: spec.context_type,
Expand Down
48 changes: 46 additions & 2 deletions crates/cgp-macro-lib/src/parse/check_components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ use proc_macro2::Span;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::token::{Bracket, Colon, Comma, For, Lt, Where};
use syn::{Ident, Type, WhereClause, braced, bracketed};
use syn::token::{Bracket, Colon, Comma, For, Lt, Pound, Where};
use syn::{Ident, Type, WhereClause, braced, bracketed, parenthesized};

use crate::parse::ImplGenerics;

pub struct CheckComponentsSpecs {
pub specs: Vec<CheckComponents>,
}

pub struct CheckComponents {
pub check_provider: Option<Vec<Type>>,
pub impl_generics: ImplGenerics,
pub trait_name: Ident,
pub context_type: Type,
Expand All @@ -29,8 +34,46 @@ struct ParseCheckEntries {
pub entries: Vec<CheckEntry>,
}

impl Parse for CheckComponentsSpecs {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut specs = Vec::new();

while !input.is_empty() {
let spec: CheckComponents = input.parse()?;
specs.push(spec);
}

Ok(Self { specs })
}
}

impl Parse for CheckComponents {
fn parse(input: ParseStream) -> syn::Result<Self> {
let check_provider = if input.peek(Pound) {
let _: Pound = input.parse()?;

let content;
bracketed!(content in input);

let command: Ident = content.parse()?;
if command != "check_providers" {
return Err(syn::Error::new(
command.span(),
"expected `check_providers` attribute",
));
}

let raw_providers;
parenthesized!(raw_providers in content);

let provider_types: Punctuated<Type, Comma> =
Punctuated::parse_terminated(&raw_providers)?;

Some(provider_types.into_iter().collect())
} else {
None
};

let impl_generics = if input.peek(Lt) {
input.parse()?
} else {
Expand Down Expand Up @@ -58,6 +101,7 @@ impl Parse for CheckComponents {
let entries: CheckEntries = content.parse()?;

Ok(Self {
check_provider,
impl_generics,
trait_name,
context_type,
Expand Down
30 changes: 30 additions & 0 deletions crates/cgp-tests/src/tests/check_components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub fn test_basic_check_components() {
#[derive(HasField)]
pub struct Context {
pub dummy: (),
pub extra_dummy: (),
}

delegate_components! {
Expand Down Expand Up @@ -61,6 +62,35 @@ pub fn test_basic_check_components() {
],
FooGetterAtComponent:
Index<3>,
}

CanUseContext2 for Context {
BarGetterAtComponent: [
(Index<0>, Index<1>),
(Index<1>, Index<0>),
],
BarGetterAtComponent:
(Index<3>, Index<4>),
[
FooGetterAtComponent,
BarGetterAtComponent,
]: [
(Index<5>, Index<6>),
(Index<7>, Index<8>),
]
}

#[check_providers(
UseField<Symbol!("dummy")>,
UseField<Symbol!("extra_dummy")>,
)]
CanUseDummyField for Context {
FooGetterAtComponent: [
Index<0>,
Index<1>,
],
FooGetterAtComponent:
Index<3>,
BarGetterAtComponent: [
(Index<0>, Index<1>),
(Index<1>, Index<0>),
Expand Down
Loading