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
33 changes: 21 additions & 12 deletions crates/cgp-macro-lib/src/cgp_fn/item_trait.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use quote::{ToTokens, quote};
use syn::{Generics, Ident, ItemFn, ItemTrait, TraitItemFn, parse2};

use crate::cgp_fn::{FunctionAttributes, substitute_abstract_type};
use crate::cgp_fn::{FunctionAttributes, UseTypeSpec, substitute_abstract_type};

pub fn derive_item_trait(
trait_ident: &Ident,
Expand All @@ -27,17 +27,26 @@ pub fn derive_item_trait(
item_trait.supertraits.extend(attributes.extend.clone());

if !attributes.use_type.is_empty() {
item_trait = parse2(substitute_abstract_type(
&quote! { Self },
&attributes.use_type,
item_trait.to_token_stream(),
))?;

for use_type in attributes.use_type.iter() {
item_trait
.supertraits
.push(parse2(use_type.trait_path.to_token_stream())?);
}
item_trait = expand_use_type_attributes_on_trait(&item_trait, &attributes.use_type)?;
}

Ok(item_trait)
}

pub fn expand_use_type_attributes_on_trait(
item_trait: &ItemTrait,
use_type_specs: &[UseTypeSpec],
) -> syn::Result<ItemTrait> {
let mut item_trait: ItemTrait = parse2(substitute_abstract_type(
&quote! { Self },
use_type_specs,
item_trait.to_token_stream(),
))?;

for use_type in use_type_specs.iter() {
item_trait
.supertraits
.push(parse2(use_type.trait_path.to_token_stream())?);
}

Ok(item_trait)
Expand Down
1 change: 1 addition & 0 deletions crates/cgp-macro-lib/src/cgp_fn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub use attributes::*;
pub use bounds::*;
pub use derive::*;
pub use fn_body::*;
pub use item_trait::*;
pub use parse_implicits::*;
pub use spec::*;
pub use substitute_type::*;
Expand Down
11 changes: 5 additions & 6 deletions crates/cgp-macro-lib/src/cgp_fn/substitute_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,11 @@ pub fn substitute_abstract_type(
}

if token_is_colon {
if last_token_was_colon {
last_token_was_colon = true;
} else {
last_token_was_colon = true;
last_two_tokens_was_colon = false;
}
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;
}
}

Expand Down
53 changes: 53 additions & 0 deletions crates/cgp-macro-lib/src/derive_component/attributes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use core::mem;

use syn::punctuated::Punctuated;
use syn::token::Comma;
use syn::{Attribute, TypeParamBound};

use crate::cgp_fn::UseTypeSpec;

pub fn parse_component_attributes(
attributes: &mut Vec<Attribute>,
) -> syn::Result<ComponentAttributes> {
let mut parsed_attributes = ComponentAttributes::default();

let in_attributes = mem::take(attributes);

for attribute in in_attributes.into_iter() {
if let Some(ident) = attribute.path().get_ident() {
if ident == "extend" {
let extend_bound = attribute
.parse_args_with(Punctuated::<TypeParamBound, Comma>::parse_terminated)?;
parsed_attributes.extend.extend(extend_bound);
} else if ident == "use_type" {
let use_type_specs = attribute
.parse_args_with(Punctuated::<UseTypeSpec, Comma>::parse_terminated)?;

for use_type_spec in use_type_specs.iter() {
for type_ident in use_type_spec.type_idents.iter() {
if let Some(equals) = &type_ident.equals {
return Err(syn::Error::new_spanned(
equals,
"Type equality constraints cannot be used in component trait definition",
));
}
}
}

parsed_attributes.use_type.extend(use_type_specs);
} else {
attributes.push(attribute);
}
} else {
attributes.push(attribute);
}
}

Ok(parsed_attributes)
}

#[derive(Default)]
pub struct ComponentAttributes {
pub extend: Vec<TypeParamBound>,
pub use_type: Vec<UseTypeSpec>,
}
5 changes: 4 additions & 1 deletion crates/cgp-macro-lib/src/derive_component/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use syn::{ItemImpl, ItemStruct, ItemTrait, parse2};

use crate::derive_component::component_name::derive_component_name_struct;
use crate::derive_component::consumer_impl::derive_consumer_impl;
use crate::derive_component::preprocess_consumer_trait;
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;
Expand All @@ -13,14 +14,16 @@ use crate::parse::ComponentSpec;

pub fn derive_component_with_ast(
spec: &ComponentSpec,
consumer_trait: ItemTrait,
mut consumer_trait: ItemTrait,
) -> syn::Result<DerivedComponent> {
let provider_name = &spec.provider_name;
let context_type = &spec.context_type;

let component_name = &spec.component_name;
let component_params = &spec.component_params;

preprocess_consumer_trait(&mut consumer_trait)?;

let component_struct = derive_component_name_struct(component_name, component_params)?;

let provider_trait = derive_provider_trait(
Expand Down
3 changes: 3 additions & 0 deletions crates/cgp-macro-lib/src/derive_component/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
mod attributes;
mod component_name;
mod consumer_impl;
mod delegate_fn;
mod delegate_type;
mod derive;
mod preprocess;
mod provider_impl;
mod provider_trait;
mod signature_args;
mod use_context_impl;
mod use_delegate_impl;

pub use derive::*;
pub use preprocess::*;
17 changes: 17 additions & 0 deletions crates/cgp-macro-lib/src/derive_component/preprocess.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use syn::ItemTrait;

use crate::cgp_fn::expand_use_type_attributes_on_trait;
use crate::derive_component::attributes::parse_component_attributes;

pub fn preprocess_consumer_trait(consumer_trait: &mut ItemTrait) -> syn::Result<()> {
let attributes = parse_component_attributes(&mut consumer_trait.attrs)?;

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)?;
}

Ok(())
}
5 changes: 4 additions & 1 deletion crates/cgp-macro-lib/src/entrypoints/cgp_auto_getter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{Error, Ident, ItemTrait};

use crate::derive_component::preprocess_consumer_trait;
use crate::derive_getter::{derive_blanket_impl, parse_getter_fields};

pub fn cgp_auto_getter(attr: TokenStream, body: TokenStream) -> syn::Result<TokenStream> {
Expand All @@ -12,7 +13,9 @@ pub fn cgp_auto_getter(attr: TokenStream, body: TokenStream) -> syn::Result<Toke
));
}

let consumer_trait: ItemTrait = syn::parse2(body)?;
let mut consumer_trait: ItemTrait = syn::parse2(body)?;

preprocess_consumer_trait(&mut consumer_trait)?;

let context_type = Ident::new("__Context__", Span::call_site());

Expand Down
6 changes: 4 additions & 2 deletions crates/cgp-macro-lib/src/entrypoints/cgp_getter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use syn::{Ident, ItemTrait, Type, parse_quote, parse2};

use crate::derive_component::derive_component_with_ast;
use crate::derive_component::{derive_component_with_ast, preprocess_consumer_trait};
use crate::derive_getter::{
GetterField, derive_use_field_impl, derive_use_fields_impl, derive_with_provider_impl,
parse_getter_fields,
Expand All @@ -20,7 +20,9 @@ pub fn cgp_getter(attr: TokenStream, body: TokenStream) -> syn::Result<TokenStre
parse2::<Entries>(attr)?.entries
};

let consumer_trait: ItemTrait = syn::parse2(body)?;
let mut consumer_trait: ItemTrait = syn::parse2(body)?;

preprocess_consumer_trait(&mut consumer_trait)?;

let provider_entry = entries.entry("provider".to_owned());

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::convert::Infallible;
use std::ops::Mul;

use cgp::core::error::ErrorTypeProviderComponent;
use cgp::prelude::*;

#[cgp_type]
Expand All @@ -8,18 +10,19 @@ pub trait HasScalarType {
}

#[cgp_component(AreaCalculator)]
pub trait CanCalculateArea: HasScalarType {
fn area(&self) -> Self::Scalar;
#[use_type(HasScalarType::Scalar, HasErrorType::Error)]
pub trait CanCalculateArea {
fn area(&self) -> Result<Scalar, Error>;
}

#[cgp_impl(new RectangleArea)]
#[use_type(HasScalarType::Scalar)]
#[use_type(HasScalarType::Scalar, HasErrorType::Error)]
impl AreaCalculator
where
Scalar: Mul<Output = Scalar> + Clone,
{
fn area(&self, #[implicit] width: Scalar, #[implicit] height: Scalar) -> Scalar {
width * height
fn area(&self, #[implicit] width: Scalar, #[implicit] height: Scalar) -> Result<Scalar, Error> {
Ok(width * height)
}
}

Expand All @@ -32,6 +35,8 @@ pub struct Rectangle {
delegate_and_check_components! {
CanUseRectangle for Rectangle;
Rectangle {
ErrorTypeProviderComponent:
UseType<Infallible>,
ScalarTypeProviderComponent:
UseType<f64>,
AreaCalculatorComponent:
Expand Down
49 changes: 49 additions & 0 deletions crates/cgp-tests/tests/component_tests/abstract_types/extend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use std::convert::Infallible;
use std::ops::Mul;

use cgp::core::error::ErrorTypeProviderComponent;
use cgp::prelude::*;

#[cgp_type]
pub trait HasScalarType {
type Scalar;
}

#[cgp_component(AreaCalculator)]
#[extend(HasScalarType, HasErrorType)]
pub trait CanCalculateArea {
fn area(&self) -> Result<Self::Scalar, Self::Error>;
}

#[cgp_impl(new RectangleArea)]
#[uses(HasScalarType, HasErrorType)]
impl AreaCalculator
where
Self::Scalar: Mul<Output = Self::Scalar> + Clone,
{
fn area(
&self,
#[implicit] width: Self::Scalar,
#[implicit] height: Self::Scalar,
) -> Result<Self::Scalar, Self::Error> {
Ok(width * height)
}
}

#[derive(HasField)]
pub struct Rectangle {
pub width: f64,
pub height: f64,
}

delegate_and_check_components! {
CanUseRectangle for Rectangle;
Rectangle {
ErrorTypeProviderComponent:
UseType<Infallible>,
ScalarTypeProviderComponent:
UseType<f64>,
AreaCalculatorComponent:
RectangleArea,
}
}
2 changes: 2 additions & 0 deletions crates/cgp-tests/tests/component_tests/abstract_types/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod basic;
pub mod extend;

This file was deleted.

1 change: 0 additions & 1 deletion crates/cgp-tests/tests/component_tests/cgp_impl/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
pub mod abstract_types;
pub mod basic;
pub mod implicit_args;
pub mod implicit_context;
1 change: 1 addition & 0 deletions crates/cgp-tests/tests/component_tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod abstract_types;
pub mod cgp_component;
pub mod cgp_impl;
pub mod consumer_delegate;
Expand Down
22 changes: 22 additions & 0 deletions crates/cgp-tests/tests/getter_tests/abstract_type/import.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use cgp::prelude::*;

#[cgp_type]
pub trait HasScalarType {
type Scalar: Clone;
}

#[cgp_auto_getter]
#[extend(HasScalarType)]
pub trait AutoRectangleFields {
fn width(&self) -> Self::Scalar;

fn height(&self) -> Self::Scalar;
}

#[cgp_getter(RectangleFieldsGetter)]
#[extend(HasScalarType)]
pub trait HasRectangleFields {
fn width(&self) -> Self::Scalar;

fn height(&self) -> Self::Scalar;
}
3 changes: 3 additions & 0 deletions crates/cgp-tests/tests/getter_tests/abstract_type/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod explicit;
pub mod import;
pub mod use_type;
22 changes: 22 additions & 0 deletions crates/cgp-tests/tests/getter_tests/abstract_type/use_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use cgp::prelude::*;

#[cgp_type]
pub trait HasScalarType {
type Scalar: Clone;
}

#[cgp_auto_getter]
#[use_type(HasScalarType::Scalar)]
pub trait AutoRectangleFields {
fn width(&self) -> Scalar;

fn height(&self) -> Scalar;
}

#[cgp_getter(RectangleFieldsGetter)]
#[use_type(HasScalarType::Scalar)]
pub trait HasRectangleFields {
fn width(&self) -> Scalar;

fn height(&self) -> Scalar;
}
Loading