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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/cgp-core/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ pub use cgp_field::types::{
};
pub use cgp_macro::{
BuildField, CgpData, CgpRecord, CgpVariant, ExtractField, FromVariant, HasField, HasFields,
Product, Sum, Symbol, cgp_auto_getter, cgp_component, cgp_context, cgp_getter, cgp_impl,
cgp_inherit, cgp_new_provider, cgp_preset, cgp_provider, cgp_type, check_components,
Product, Sum, Symbol, cgp_auto_getter, cgp_component, cgp_context, cgp_fn, cgp_getter,
cgp_impl, cgp_inherit, cgp_new_provider, cgp_preset, cgp_provider, cgp_type, check_components,
delegate_and_check_components, delegate_components, product, re_export_imports, replace_with,
};
pub use cgp_type::{HasType, ProvideType, UseType};
1 change: 1 addition & 0 deletions crates/cgp-extra-macro-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ default = []
syn = { version = "2.0.95", features = [ "full", "extra-traits" ] }
quote = "1.0.38"
proc-macro2 = "1.0.92"
cgp-macro-lib = { workspace = true }
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::BTreeSet;

use cgp_macro_lib::utils::to_camel_case_str;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::punctuated::Punctuated;
Expand All @@ -10,8 +11,6 @@ use syn::{
ReturnType, TraitItemFn, Type, Visibility, parse2,
};

use crate::utils::to_camel_case_str;

pub fn cgp_auto_dispatch(_attr: TokenStream, mut out: TokenStream) -> syn::Result<TokenStream> {
let item_trait: ItemTrait = parse2(out.clone())?;

Expand Down
2 changes: 1 addition & 1 deletion crates/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use cgp_macro_lib::utils::to_camel_case_str;
use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use syn::punctuated::Punctuated;
Expand All @@ -6,7 +7,6 @@ use syn::token::Comma;
use syn::{FnArg, Ident, ItemFn, ItemImpl, ReturnType, Type, parse2};

use crate::parse::MaybeResultType;
use crate::utils::to_camel_case_str;

pub fn cgp_computer(attr: TokenStream, body: TokenStream) -> syn::Result<TokenStream> {
let item_fn: ItemFn = parse2(body)?;
Expand Down
3 changes: 1 addition & 2 deletions crates/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use cgp_macro_lib::utils::to_camel_case_str;
use proc_macro2::TokenStream;
use quote::quote;
use syn::spanned::Spanned;
use syn::{Ident, ItemFn, ItemImpl, ReturnType, parse2};

use crate::utils::to_camel_case_str;

pub fn cgp_producer(attr: TokenStream, body: TokenStream) -> syn::Result<TokenStream> {
let item_fn: ItemFn = parse2(body)?;

Expand Down
1 change: 0 additions & 1 deletion crates/cgp-extra-macro-lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
mod entrypoints;
pub(crate) mod parse;
pub(crate) mod utils;

pub use entrypoints::*;
40 changes: 40 additions & 0 deletions crates/cgp-macro-lib/src/cgp_fn/attributes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use core::mem;

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

use crate::cgp_fn::{FunctionAttributes, UseTypeSpec};
use crate::parse::SimpleType;

pub fn parse_function_attributes(
attributes: &mut Vec<Attribute>,
) -> syn::Result<FunctionAttributes> {
let mut parsed_attributes = FunctionAttributes::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 == "uses" {
let uses =
attribute.parse_args_with(Punctuated::<SimpleType, Comma>::parse_terminated)?;
parsed_attributes.uses.extend(uses);
} else if ident == "use_type" {
let use_type = attribute
.parse_args_with(Punctuated::<UseTypeSpec, Comma>::parse_terminated)?;
parsed_attributes.use_type.extend(use_type);
} else {
attributes.push(attribute);
}
} else {
attributes.push(attribute);
}
}

Ok(parsed_attributes)
}
24 changes: 24 additions & 0 deletions crates/cgp-macro-lib/src/cgp_fn/constraint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// pub fn derive_implicit_arg_constraint(
// field: &ImplicitArgField,
// ) -> syn::Result<TypeParamBound> {
// let field_symbol = &field.field_name;
// let field_type = &field.field_type;

// let constraint = if field.field_mut.is_none() {
// if let FieldMode::Slice = field.field_mode {
// quote! {
// HasField< #field_symbol, Value: AsRef< [ #field_type ] > + 'static >
// }
// } else {
// quote! {
// HasField< #field_symbol, Value = #field_type >
// }
// }
// } else {
// quote! {
// HasFieldMut< #field_symbol, Value = #field_type >
// }
// };

// parse2(constraint)
// }
50 changes: 50 additions & 0 deletions crates/cgp-macro-lib/src/cgp_fn/derive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use core::mem;

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_implicits_args, parse_function_attributes};

pub fn derive_cgp_fn(trait_ident: &Ident, mut item_fn: ItemFn) -> syn::Result<TokenStream> {
let receiver = match item_fn.sig.inputs.first() {
Some(syn::FnArg::Receiver(receiver)) => receiver.clone(),
_ => {
return Err(syn::Error::new_spanned(
&item_fn.sig.inputs,
"First argument must be self",
));
}
};

let implicit_args = extract_implicits_args(&receiver, &mut item_fn.sig.inputs)?;

let attributes = parse_function_attributes(&mut item_fn.attrs)?;

item_fn.vis = Visibility::Inherited;

inject_implicit_args(&implicit_args, &mut item_fn.block)?;

let generics = mem::take(&mut item_fn.sig.generics);

let item_trait = derive_item_trait(trait_ident, &item_fn, &generics, &attributes)?;

let item_impl = derive_item_impl(
trait_ident,
&item_fn,
&implicit_args,
&generics,
&attributes,
)?;

let output = quote! {
#item_trait

#item_impl
};

Ok(output)
}
39 changes: 39 additions & 0 deletions crates/cgp-macro-lib/src/cgp_fn/fn_body.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
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(())
}

pub fn inject_implicit_arg(arg: &ImplicitArgField, body: &mut Block) -> syn::Result<()> {
let field_name = &arg.field_name;

let field_symbol = symbol_from_string(&field_name.to_string());

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

body.stmts.insert(0, statement);

Ok(())
}
81 changes: 81 additions & 0 deletions crates/cgp-macro-lib/src/cgp_fn/item_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use quote::{ToTokens, quote};
use syn::punctuated::Punctuated;
use syn::token::Plus;
use syn::{Generics, Ident, ItemFn, ItemImpl, TypeParamBound, parse2};

use crate::cgp_fn::{FunctionAttributes, ImplicitArgField, substitute_abstract_type};
use crate::derive_getter::derive_getter_constraint;
use crate::symbol::symbol_from_string;

pub fn derive_item_impl(
trait_ident: &Ident,
item_fn: &ItemFn,
implicit_args: &[ImplicitArgField],
generics: &Generics,
attributes: &FunctionAttributes,
) -> syn::Result<ItemImpl> {
let type_generics = generics.split_for_impl().1;

let mut item_impl: ItemImpl = parse2(quote! {
impl #trait_ident #type_generics for __Context__ {
#item_fn
}
})?;

item_impl.generics = generics.clone();
item_impl
.generics
.params
.insert(0, parse2(quote! { __Context__ })?);

let mut bounds: Punctuated<TypeParamBound, Plus> = Punctuated::default();
bounds.extend(attributes.extend.clone());

for import in attributes.uses.iter() {
bounds.push(parse2(quote! { #import })?);
}

{
let where_clause = item_impl.generics.make_where_clause();

for arg in implicit_args {
let field_symbol = symbol_from_string(&arg.field_name.to_string());

let constraint = derive_getter_constraint(
&arg.field_type,
&arg.field_mut,
&arg.field_mode,
field_symbol.to_token_stream(),
&None,
)?;

where_clause.predicates.push(parse2(quote! {
Self: #constraint
})?);
}
}

if !attributes.use_type.is_empty() {
for use_type in attributes.use_type.iter() {
bounds.push(parse2(use_type.trait_path.to_token_stream())?);
}

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

if !bounds.is_empty() {
item_impl
.generics
.make_where_clause()
.predicates
.push(parse2(quote! {
Self: #bounds
})?);
}

Ok(item_impl)
}
50 changes: 50 additions & 0 deletions crates/cgp-macro-lib/src/cgp_fn/item_trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use quote::{ToTokens, quote};
use syn::punctuated::Punctuated;
use syn::token::Plus;
use syn::{Generics, Ident, ItemFn, ItemTrait, TraitItemFn, TypeParamBound, parse2};

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

pub fn derive_item_trait(
trait_ident: &Ident,
item_fn: &ItemFn,
generics: &Generics,
attributes: &FunctionAttributes,
) -> syn::Result<ItemTrait> {
let trait_item_fn = TraitItemFn {
attrs: item_fn.attrs.clone(),
sig: item_fn.sig.clone(),
default: None,
semi_token: None,
};

let (_, type_generics, _) = generics.split_for_impl();

let mut item_trait: ItemTrait = parse2(quote! {
pub trait #trait_ident #type_generics {
#trait_item_fn
}
})?;

let mut bounds: Punctuated<TypeParamBound, Plus> = Punctuated::default();

for extend in &attributes.extend {
bounds.push(extend.clone());
}

if !attributes.use_type.is_empty() {
for use_type in attributes.use_type.iter() {
bounds.push(parse2(use_type.trait_path.to_token_stream())?);
}

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

item_trait.supertraits.extend(bounds);

Ok(item_trait)
}
17 changes: 17 additions & 0 deletions crates/cgp-macro-lib/src/cgp_fn/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
mod attributes;
mod constraint;
mod derive;
mod fn_body;
mod item_impl;
mod item_trait;
mod parse_implicits;
mod spec;
mod substitute_type;
mod use_type;

pub use attributes::*;
pub use derive::*;
pub use parse_implicits::*;
pub use spec::*;
pub use substitute_type::*;
pub use use_type::*;
Loading
Loading