From 1cafd62f7fc560b5c5f67372bc02071c32a9d940 Mon Sep 17 00:00:00 2001 From: Marvin Hansen Date: Sun, 29 Dec 2024 16:16:22 +0800 Subject: [PATCH] docs(cgp-component-macro-lib): add comprehensive documentation for macro components Addresses issue: https://github.com/contextgeneric/cgp/issues/45 Add detailed Rust docstrings to core macro implementation files, improving code understanding and maintainability. Documentation follows Rust best practices with clear examples and detailed explanations. Each file's documentation includes: - Clear overview and purpose - Detailed function/struct documentation - Arguments and return value descriptions - Practical code examples - Implementation notes and edge cases - Type parameter explanations where applicable All examples are marked with `ignore` where they depend on the full CGP framework context. Documentation has been verified with `cargo test --doc` and `cargo doc`. Part of the ongoing effort to improve CGP framework documentation and usability. Signed-off-by: Marvin Hansen --- .../src/delegate_components/ast.rs | 79 +++++++++++++++++++ .../src/delegate_components/define_struct.rs | 47 +++++++++++ .../src/delegate_components/delegate.rs | 17 ++++ .../src/delegate_components/delegates_to.rs | 43 ++++++++++ .../src/delegate_components/impl_delegate.rs | 28 +++++++ .../src/delegate_components/merge_generics.rs | 35 ++++++++ .../src/delegate_components/mod.rs | 32 ++++++++ .../src/derive_component/component_name.rs | 30 +++++++ .../src/derive_component/component_spec.rs | 37 +++++++++ .../src/derive_component/consumer_impl.rs | 41 ++++++++++ .../src/derive_component/delegate_fn.rs | 44 +++++++++++ .../src/derive_component/delegate_type.rs | 40 ++++++++++ .../src/derive_component/derive.rs | 35 ++++++++ .../src/derive_component/entry.rs | 35 ++++++++ .../src/derive_component/mod.rs | 6 ++ .../src/derive_component/provider_impl.rs | 40 ++++++++++ .../src/derive_component/provider_trait.rs | 46 +++++++++++ .../derive_component/replace_self_receiver.rs | 45 +++++++++++ .../src/derive_component/replace_self_type.rs | 65 +++++++++++++++ .../src/derive_component/signature_args.rs | 32 ++++++++ .../src/derive_component/snake_case.rs | 44 +++++++++++ .../src/for_each_replace.rs | 56 +++++++++++++ crates/cgp-component-macro-lib/src/lib.rs | 8 ++ .../cgp-component-macro-lib/src/preset/ast.rs | 31 ++++++++ .../src/preset/define_preset.rs | 36 +++++++++ .../src/preset/impl_is_preset.rs | 41 ++++++++++ .../cgp-component-macro-lib/src/preset/mod.rs | 44 +++++++++++ .../src/preset/substitution_macro.rs | 32 ++++++++ 28 files changed, 1069 insertions(+) diff --git a/crates/cgp-component-macro-lib/src/delegate_components/ast.rs b/crates/cgp-component-macro-lib/src/delegate_components/ast.rs index 2af0ca0..30ab405 100644 --- a/crates/cgp-component-macro-lib/src/delegate_components/ast.rs +++ b/crates/cgp-component-macro-lib/src/delegate_components/ast.rs @@ -1,3 +1,8 @@ +/// Abstract Syntax Tree (AST) structures for component delegation. +/// +/// This module provides the AST representation for parsing and processing +/// component delegation syntax in the CGP framework. + use core::iter; use proc_macro2::TokenStream; @@ -7,21 +12,57 @@ use syn::punctuated::Punctuated; use syn::token::{Bracket, Colon, Comma, Lt}; use syn::{braced, bracketed, Generics, Token, Type}; +/// Root AST node representing a complete component delegation specification. +/// +/// This structure captures the target type that will implement the delegated +/// components, its generic parameters, and the entries specifying which +/// components are delegated to which sources. +/// +/// # Fields +/// +/// * `target_type` - The type that will implement the delegated components +/// * `target_generics` - Generic parameters for the target type +/// * `delegate_entries` - Collection of delegation specifications pub struct DelegateComponentsAst { pub target_type: Type, pub target_generics: Generics, pub delegate_entries: DelegateEntriesAst, } +/// Collection of delegate entries in the AST. +/// +/// Represents a comma-separated list of delegate entries, where each entry +/// specifies which components are delegated to a particular source. +/// +/// # Fields +/// +/// * `entries` - Punctuated sequence of delegate entries pub struct DelegateEntriesAst { pub entries: Punctuated, } +/// Single delegation entry in the AST. +/// +/// Specifies a mapping between a set of components and their source type +/// for delegation. +/// +/// # Fields +/// +/// * `components` - List of components to be delegated +/// * `source` - The type that provides the component implementations pub struct DelegateEntryAst { pub components: Punctuated, pub source: Type, } +/// AST node representing a single component specification. +/// +/// Captures a component type and its associated generic parameters. +/// +/// # Fields +/// +/// * `component_type` - The type of the component being delegated +/// * `component_generics` - Generic parameters for the component #[derive(Clone)] pub struct ComponentAst { pub component_type: Type, @@ -29,6 +70,12 @@ pub struct ComponentAst { } impl DelegateEntriesAst { + /// Collects all components from all delegate entries into a single sequence. + /// + /// # Returns + /// + /// Returns a `Punctuated` sequence containing all components across all entries, + /// preserving their order of appearance. pub fn all_components(&self) -> Punctuated { self.entries .iter() @@ -37,6 +84,12 @@ impl DelegateEntriesAst { } } +/// Parse implementation for delegate components AST. +/// +/// Parses input in the format: +/// ```text +/// ? target_type { entries... } +/// ``` impl Parse for DelegateComponentsAst { fn parse(input: ParseStream) -> syn::Result { let target_generics = if input.peek(Lt) { @@ -57,6 +110,12 @@ impl Parse for DelegateComponentsAst { } } +/// Parse implementation for delegate entries. +/// +/// Parses input in the format: +/// ```text +/// { entry1, entry2, ... } +/// ``` impl Parse for DelegateEntriesAst { fn parse(input: ParseStream) -> syn::Result { let entries = { @@ -69,6 +128,16 @@ impl Parse for DelegateEntriesAst { } } +/// Parse implementation for a single delegate entry. +/// +/// Parses input in the format: +/// ```text +/// [comp1, comp2, ...]: source_type +/// ``` +/// or +/// ```text +/// comp: source_type +/// ``` impl Parse for DelegateEntryAst { fn parse(input: ParseStream) -> syn::Result { let components = if input.peek(Bracket) { @@ -88,6 +157,12 @@ impl Parse for DelegateEntryAst { } } +/// Parse implementation for component specification. +/// +/// Parses input in the format: +/// ```text +/// ? component_type +/// ``` impl Parse for ComponentAst { fn parse(input: ParseStream) -> syn::Result { let component_generics = if input.peek(Lt) { @@ -105,6 +180,10 @@ impl Parse for ComponentAst { } } +/// Token stream generation for component specifications. +/// +/// Converts a component specification into a token stream by concatenating +/// its generic parameters and component type. impl ToTokens for ComponentAst { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.extend(self.component_generics.to_token_stream()); diff --git a/crates/cgp-component-macro-lib/src/delegate_components/define_struct.rs b/crates/cgp-component-macro-lib/src/delegate_components/define_struct.rs index 707f55d..7e063ca 100644 --- a/crates/cgp-component-macro-lib/src/delegate_components/define_struct.rs +++ b/crates/cgp-component-macro-lib/src/delegate_components/define_struct.rs @@ -2,6 +2,53 @@ use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{parse_quote, GenericParam, Generics, Ident, ItemStruct, Type}; +/// Generates a struct definition with proper handling of generic parameters and lifetimes. +/// +/// This function creates a new struct definition based on the provided identifier and generic parameters. +/// It handles two cases: +/// - For structs without generic parameters: Creates a simple unit struct +/// - For structs with generic parameters: Creates a struct with a `PhantomData` field that properly +/// captures all type parameters and lifetimes +/// +/// The function ensures proper type safety by: +/// - Removing bounds from type parameters to avoid unnecessary constraints +/// - Converting lifetime parameters into reference types with appropriate lifetimes +/// - Using `PhantomData` to maintain variance without adding runtime overhead +/// +/// # Arguments +/// +/// * `ident` - The identifier for the new struct +/// * `generics` - The generic parameters specification, which may include type parameters, +/// lifetime parameters, and const generics +/// +/// # Returns +/// +/// Returns a [`syn::ItemStruct`] representing the complete struct definition with all +/// necessary generic parameters and phantom data fields. +/// +/// # Examples +/// +/// ```rust +/// # use syn::{parse_quote, Generics, Ident}; +/// # use cgp_component_macro_lib::delegate_components::define_struct::define_struct; +/// // Simple struct without generics +/// let simple_ident: Ident = parse_quote!(SimpleStruct); +/// let empty_generics: Generics = parse_quote!(); +/// let simple = define_struct(&simple_ident, &empty_generics); +/// // Results in: pub struct SimpleStruct; +/// +/// // Generic struct with type parameter and lifetime +/// let generic_ident: Ident = parse_quote!(GenericStruct); +/// let generics: Generics = parse_quote!(); +/// let generic = define_struct(&generic_ident, &generics); +/// // Results in: pub struct GenericStruct(pub ::core::marker::PhantomData<(T, &'a ())>); +/// ``` +/// +/// # Note +/// +/// The generated struct will always be public (`pub`) and will use `PhantomData` +/// to properly handle generic parameters without introducing runtime overhead. + pub fn define_struct(ident: &Ident, generics: &Generics) -> ItemStruct { if generics.params.is_empty() { parse_quote! { diff --git a/crates/cgp-component-macro-lib/src/delegate_components/delegate.rs b/crates/cgp-component-macro-lib/src/delegate_components/delegate.rs index e2c7c7e..68f5dcb 100644 --- a/crates/cgp-component-macro-lib/src/delegate_components/delegate.rs +++ b/crates/cgp-component-macro-lib/src/delegate_components/delegate.rs @@ -1,9 +1,26 @@ +/// Imports required for token stream processing and AST manipulation use proc_macro2::TokenStream; use quote::ToTokens; use crate::delegate_components::ast::DelegateComponentsAst; use crate::delegate_components::impl_delegate::impl_delegate_components; +/// Processes component delegation macro by generating the necessary trait implementations. +/// +/// # Arguments +/// * `body` - The input token stream containing the delegation specification +/// +/// # Returns +/// * `syn::Result` - The generated implementation code as a token stream +/// +/// # Example +/// This function handles macro invocations like: +/// ```ignore +/// #[delegate_components] +/// struct MyStruct { +/// delegate: DelegateType, +/// } +/// ``` pub fn delegate_components(body: TokenStream) -> syn::Result { let ast: DelegateComponentsAst = syn::parse2(body)?; diff --git a/crates/cgp-component-macro-lib/src/delegate_components/delegates_to.rs b/crates/cgp-component-macro-lib/src/delegate_components/delegates_to.rs index d922fdf..4205efd 100644 --- a/crates/cgp-component-macro-lib/src/delegate_components/delegates_to.rs +++ b/crates/cgp-component-macro-lib/src/delegate_components/delegates_to.rs @@ -1,9 +1,28 @@ +/// Functionality for defining delegate component trait bounds and trait implementations use syn::punctuated::Punctuated; use syn::token::Plus; use syn::{parse_quote, Generics, Ident, ItemImpl, ItemTrait, Type, TypeParamBound}; use crate::delegate_components::ast::DelegateEntriesAst; +/// Generates trait bounds for delegated components. +/// +/// This function creates a set of trait bounds that ensure each component +/// can be delegated to the target type. It processes all components in the +/// delegate entries and creates appropriate DelegateComponent bounds. +/// +/// # Arguments +/// * `target_type` - The type that components will delegate to +/// * `delegate_entries` - AST containing all component delegation specifications +/// +/// # Returns +/// * `Punctuated` - A sequence of trait bounds separated by '+' +/// +/// # Example +/// For a component of type `MyComponent` delegating to `TargetType`, generates: +/// ```ignore +/// DelegateComponent +/// ``` pub fn define_delegate_component_trait_bounds( target_type: &Type, delegate_entries: &DelegateEntriesAst, @@ -21,6 +40,30 @@ pub fn define_delegate_component_trait_bounds( trait_bounds } +/// Defines a trait and its implementation for component delegation. +/// +/// This function creates: +/// 1. A trait with bounds ensuring all components can delegate to the target type +/// 2. A generic implementation of this trait for any type meeting these bounds +/// +/// # Arguments +/// * `trait_name` - Name of the trait to define +/// * `target_type` - The type that components will delegate to +/// * `target_generics` - Generic parameters for the target type +/// * `delegate_entries` - AST containing all component delegation specifications +/// +/// # Returns +/// * `(ItemTrait, ItemImpl)` - Tuple containing the trait definition and its implementation +/// +/// # Example +/// For trait name `DelegatesTo`, generates something like: +/// ```ignore +/// pub trait DelegatesTo: DelegateComponent + DelegateComponent {} +/// impl DelegatesTo for Components +/// where +/// Components: DelegateComponent + DelegateComponent +/// {} +/// ``` pub fn define_delegates_to_trait( trait_name: &Ident, target_type: &Type, diff --git a/crates/cgp-component-macro-lib/src/delegate_components/impl_delegate.rs b/crates/cgp-component-macro-lib/src/delegate_components/impl_delegate.rs index b53a8e5..9f6696d 100644 --- a/crates/cgp-component-macro-lib/src/delegate_components/impl_delegate.rs +++ b/crates/cgp-component-macro-lib/src/delegate_components/impl_delegate.rs @@ -3,6 +3,18 @@ use syn::{parse_quote, Generics, ImplItem, ImplItemType, ItemImpl, Path, Type}; use crate::delegate_components::ast::{ComponentAst, DelegateEntriesAst}; use crate::delegate_components::merge_generics::merge_generics; +/// Generates implementation blocks for delegated components. +/// +/// This function creates the necessary trait implementations for each component +/// that is being delegated to another type. +/// +/// # Arguments +/// * `target_type` - The type that is delegating its components +/// * `target_generics` - Generic parameters of the target type +/// * `delegate_entries` - AST nodes describing the delegation relationships +/// +/// # Returns +/// A vector of implementation blocks for each delegated component pub fn impl_delegate_components( target_type: &Type, target_generics: &Generics, @@ -21,6 +33,22 @@ pub fn impl_delegate_components( .collect() } +/// Creates a single implementation block for a delegated component. +/// +/// # Arguments +/// * `target_type` - The type implementing the delegation +/// * `target_generics` - Generic parameters of the target type +/// * `component` - AST node describing the component being delegated +/// * `source` - The type that provides the component implementation +/// +/// # Returns +/// An implementation block (ItemImpl) that defines the delegation relationship +/// +/// # Implementation Details +/// This function: +/// 1. Constructs the DelegateComponent trait path +/// 2. Defines the associated Delegate type +/// 3. Merges generics from both the target and component pub fn impl_delegate_component( target_type: &Type, target_generics: &Generics, diff --git a/crates/cgp-component-macro-lib/src/delegate_components/merge_generics.rs b/crates/cgp-component-macro-lib/src/delegate_components/merge_generics.rs index afa9df1..ad8284e 100644 --- a/crates/cgp-component-macro-lib/src/delegate_components/merge_generics.rs +++ b/crates/cgp-component-macro-lib/src/delegate_components/merge_generics.rs @@ -2,6 +2,41 @@ use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{Generics, WhereClause, WherePredicate}; +/// Merges two sets of generic parameters into a single unified set. +/// +/// This function combines generic parameters and where clauses from two different +/// generic specifications into a single coherent set. It preserves all type parameters, +/// lifetime parameters, and where clause predicates from both inputs. +/// +/// # Arguments +/// +/// * `generics_a` - First set of generic parameters to merge +/// * `generics_b` - Second set of generic parameters to merge +/// +/// # Returns +/// +/// Returns a new [`syn::Generics`] instance containing: +/// - Combined generic parameters from both inputs +/// - Merged where clauses (if any exist in either input) +/// - Angle bracket tokens from the first input (`generics_a`) +/// +/// # Examples +/// +/// ```rust +/// # use syn::{parse_quote, Generics}; +/// # use cgp_component_macro_lib::delegate_components::merge_generics::merge_generics; +/// # use std::fmt::{Debug, Display}; +/// let generics_a: Generics = parse_quote!(); +/// let generics_b: Generics = parse_quote!(); +/// let merged = merge_generics(&generics_a, &generics_b); +/// // Results in: +/// ``` +/// +/// # Note +/// +/// The function preserves the angle bracket tokens (`lt_token` and `gt_token`) from +/// the first set of generics (`generics_a`). This is typically desirable as these +/// tokens usually carry the same span information throughout a macro expansion. pub fn merge_generics(generics_a: &Generics, generics_b: &Generics) -> Generics { let mut params = generics_a.params.clone(); params.extend(generics_b.params.clone()); diff --git a/crates/cgp-component-macro-lib/src/delegate_components/mod.rs b/crates/cgp-component-macro-lib/src/delegate_components/mod.rs index c7df58f..9f813c7 100644 --- a/crates/cgp-component-macro-lib/src/delegate_components/mod.rs +++ b/crates/cgp-component-macro-lib/src/delegate_components/mod.rs @@ -1,3 +1,35 @@ +/// Component delegation functionality for the CGP framework. +/// +/// This module provides the core functionality for delegating component implementations +/// in the Component-based Generic Programming (CGP) framework. It enables the creation +/// of composite components by delegating their functionality to underlying implementations. +/// +/// # Module Structure +/// +/// * [`ast`] - Abstract Syntax Tree definitions for parsing delegation syntax +/// * [`define_struct`] - Utilities for generating struct definitions with proper generic handling +/// * [`delegate`] - Core delegation implementation and macro expansion +/// * [`delegates_to`] - Trait definitions and bounds for delegation relationships +/// * [`impl_delegate`] - Implementation details for component delegation +/// * [`merge_generics`] - Utilities for combining generic parameters from multiple sources +/// +/// # Main Entry Point +/// +/// The primary entry point for component delegation is the [`delegate_components`] +/// function, which processes delegation specifications and generates the necessary +/// implementation code. +/// +/// # Example +/// +/// ```rust,ignore +/// #[delegate_components] +/// struct MyComposite { +/// inner: Inner +/// } +/// +/// // Delegates the Debug and Display components to the inner field +/// impl DelegatesTo<[Debug, Display], Inner> for MyComposite {} +/// ``` pub mod ast; pub mod define_struct; pub mod delegate; diff --git a/crates/cgp-component-macro-lib/src/derive_component/component_name.rs b/crates/cgp-component-macro-lib/src/derive_component/component_name.rs index dc8d430..f7fe92e 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/component_name.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/component_name.rs @@ -2,6 +2,36 @@ use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{parse_quote, Ident, ItemStruct}; +/// Generates a component name struct definition with optional generic parameters. +/// +/// This function creates a struct that represents a component's type name in the CGP framework. +/// For components without generic parameters, it generates a simple unit struct. +/// For generic components, it generates a struct with a `PhantomData` field to carry the generic parameters. +/// +/// # Arguments +/// +/// * `component_name` - The identifier for the component struct +/// * `component_params` - A comma-separated list of generic parameter identifiers +/// +/// # Returns +/// +/// A `syn::ItemStruct` representing either: +/// - A unit struct `struct ComponentName;` for non-generic components +/// - A generic struct `struct ComponentName(PhantomData<(T)>);` for generic components +/// +/// # Examples +/// +/// ```rust,ignore +/// // For a non-generic component +/// derive_component_name_struct(&parse_quote!(MyComponent), &Punctuated::new()) +/// // Generates: pub struct MyComponent; +/// +/// // For a generic component +/// let mut params = Punctuated::new(); +/// params.push(parse_quote!(T)); +/// derive_component_name_struct(&parse_quote!(MyComponent), ¶ms) +/// // Generates: pub struct MyComponent(pub PhantomData<(T)>); +/// ``` pub fn derive_component_name_struct( component_name: &Ident, component_params: &Punctuated, diff --git a/crates/cgp-component-macro-lib/src/derive_component/component_spec.rs b/crates/cgp-component-macro-lib/src/derive_component/component_spec.rs index d0c9a10..7ecad30 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/component_spec.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/component_spec.rs @@ -1,3 +1,4 @@ +/// Specification parsing for component attributes and names. use proc_macro2::Span; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; @@ -7,18 +8,44 @@ use syn::{Error, Ident}; use crate::derive_component::entry::Entries; +/// Specification for a component, containing all necessary information for generation. +/// +/// This structure holds the parsed information from a component attribute macro, +/// including provider details, context type, and component naming information. +#[derive(Debug)] pub struct ComponentSpec { + /// Name of the provider trait that will be generated pub provider_name: Ident, + /// Type of context used in the component pub context_type: Ident, + /// Name of the component struct that will be generated pub component_name: Ident, + /// Generic parameters for the component pub component_params: Punctuated, } +/// Specification for a component's name and its generic parameters. +/// +/// This structure represents the parsed form of a component name declaration, +/// which may include generic parameters. +#[derive(Debug)] pub struct ComponentNameSpec { + /// Name of the component pub component_name: Ident, + /// Generic parameters for the component pub component_params: Punctuated, } +/// Parser implementation for ComponentSpec +/// +/// Parses component specifications in the format: +/// ```ignore +/// #[component( +/// provider = MyProvider, +/// context = MyContext, +/// name = MyComponent +/// )] +/// ``` impl Parse for ComponentSpec { fn parse(input: ParseStream) -> syn::Result { let Entries { entries } = input.parse()?; @@ -67,6 +94,16 @@ impl Parse for ComponentSpec { } } +/// Parser implementation for ComponentNameSpec +/// +/// Parses component names in the format: +/// ```ignore +/// MyComponent +/// ``` +/// or just: +/// ```ignore +/// MyComponent +/// ``` impl Parse for ComponentNameSpec { fn parse(input: ParseStream) -> syn::Result { let component_name: Ident = input.parse()?; diff --git a/crates/cgp-component-macro-lib/src/derive_component/consumer_impl.rs b/crates/cgp-component-macro-lib/src/derive_component/consumer_impl.rs index ed7b393..8a047c9 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/consumer_impl.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/consumer_impl.rs @@ -1,3 +1,7 @@ +/// Implementation generation for component consumers. +/// +/// This module handles the generation of consumer implementations that allow +/// components to be used through a context type that has component capabilities. use syn::punctuated::Punctuated; use syn::token::{Brace, Comma, For, Impl, Plus}; use syn::{ @@ -8,6 +12,43 @@ use syn::{ use crate::derive_component::delegate_fn::derive_delegated_fn_impl; use crate::derive_component::delegate_type::derive_delegate_type_impl; +/// Derives an implementation of a consumer trait for a context type. +/// +/// This function generates the implementation that allows a context type to use +/// component functionality through its component storage. +/// +/// # Arguments +/// * `consumer_trait` - The trait defining the consumer interface +/// * `provider_name` - Name of the provider trait +/// * `context_type` - The context type that will implement the consumer trait +/// +/// # Returns +/// * `ItemImpl` - The generated implementation block +/// +/// # Generated Code Example +/// ```ignore +/// impl MyComponent for Context +/// where +/// Context: HasComponents, +/// Context::Components: MyComponentProvider +/// { +/// // Delegated function implementations +/// fn my_function(&self) -> Result<(), Error> { +/// self.components().my_function() +/// } +/// +/// // Delegated associated type implementations +/// type MyType = >::MyType; +/// } +/// ``` +/// +/// # Implementation Details +/// The function: +/// 1. Constructs generic parameters for the implementation +/// 2. Adds necessary trait bounds for component access +/// 3. Generates delegating implementations for all trait items +/// 4. Handles both associated functions and associated types +/// 5. Preserves and propagates any supertraits from the consumer trait pub fn derive_consumer_impl( consumer_trait: &ItemTrait, provider_name: &Ident, diff --git a/crates/cgp-component-macro-lib/src/derive_component/delegate_fn.rs b/crates/cgp-component-macro-lib/src/derive_component/delegate_fn.rs index bc71cea..0b235de 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/delegate_fn.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/delegate_fn.rs @@ -4,6 +4,50 @@ use syn::{parse_quote, ImplItemFn, Signature, TypePath, Visibility}; use crate::derive_component::signature_args::signature_to_args; +/// Generates a function implementation that delegates calls to another type. +/// +/// Creates an implementation of a function that forwards all its calls to a corresponding +/// function on the delegator type. Handles both synchronous and asynchronous functions, +/// automatically adding `.await` when needed. +/// +/// # Arguments +/// +/// * `sig` - The function signature to implement, containing name, arguments, and return type +/// * `delegator` - The type path to delegate the function calls to +/// +/// # Returns +/// +/// A `syn::ImplItemFn` representing the delegating function implementation with: +/// - The same signature as the input +/// - A body that forwards the call to the delegator +/// - Inherited visibility +/// - No attributes +/// +/// # Examples +/// +/// ```rust,ignore +/// // For a sync function +/// let sig = parse_quote!(fn process(&self, data: String) -> Result<(), Error>); +/// let delegator = parse_quote!(Inner); +/// derive_delegated_fn_impl(&sig, &delegator) +/// // Generates: fn process(&self, data: String) -> Result<(), Error> { +/// // Inner::process(data) +/// // } +/// +/// // For an async function +/// let sig = parse_quote!(async fn process(&self, data: String) -> Result<(), Error>); +/// derive_delegated_fn_impl(&sig, &delegator) +/// // Generates: async fn process(&self, data: String) -> Result<(), Error> { +/// // Inner::process(data).await +/// // } +/// ``` +/// +/// # Notes +/// +/// The generated implementation automatically: +/// - Preserves all function arguments and their order +/// - Handles async/await syntax when the source function is async +/// - Maintains the original function's signature including generics and where clauses pub fn derive_delegated_fn_impl(sig: &Signature, delegator: &TypePath) -> ImplItemFn { let fn_name = &sig.ident; diff --git a/crates/cgp-component-macro-lib/src/derive_component/delegate_type.rs b/crates/cgp-component-macro-lib/src/derive_component/delegate_type.rs index 3282390..e14f2eb 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/delegate_type.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/delegate_type.rs @@ -1,6 +1,46 @@ +/// Utilities for deriving associated type implementations for delegated components. +/// +/// This module provides functionality to create implementations of associated types +/// when delegating component traits to other types. use syn::token::Eq; use syn::{ImplItemType, TraitItemType, Type, Visibility}; +/// Derives an implementation of an associated type for a delegated component. +/// +/// Creates an implementation that sets a trait's associated type to the specified +/// delegated type, preserving attributes and generic parameters from the original +/// trait definition. +/// +/// # Arguments +/// +/// * `trait_type` - The associated type definition from the trait +/// * `delegated_type` - The concrete type to use in the implementation +/// +/// # Returns +/// +/// An `ImplItemType` representing the associated type implementation +/// +/// # Examples +/// +/// ```rust,ignore +/// // For a trait definition: +/// trait MyComponent { +/// type Output; +/// } +/// +/// // And a delegated type: +/// type DelegatedOutput = String; +/// +/// // This function generates: +/// type Output = DelegatedOutput; +/// ``` +/// +/// # Note +/// +/// The generated implementation: +/// - Inherits visibility from the trait +/// - Preserves all attributes from the trait definition +/// - Maintains generic parameters and where clauses pub fn derive_delegate_type_impl(trait_type: &TraitItemType, delegated_type: Type) -> ImplItemType { ImplItemType { attrs: trait_type.attrs.clone(), diff --git a/crates/cgp-component-macro-lib/src/derive_component/derive.rs b/crates/cgp-component-macro-lib/src/derive_component/derive.rs index f95307d..300b787 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/derive.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/derive.rs @@ -1,3 +1,7 @@ +/// Core functionality for deriving component traits and implementations. +/// +/// This module handles the generation of all necessary types and implementations +/// for component-based programming patterns. use proc_macro2::TokenStream; use quote::ToTokens; use syn::ItemTrait; @@ -8,6 +12,37 @@ use crate::derive_component::consumer_impl::derive_consumer_impl; use crate::derive_component::provider_impl::derive_provider_impl; use crate::derive_component::provider_trait::derive_provider_trait; +/// Derives a complete component implementation from a trait definition. +/// +/// This function is the main entry point for the component derivation process. +/// It generates all the necessary types and implementations for a component: +/// - A component name struct +/// - A provider trait +/// - Consumer implementations +/// - Provider implementations +/// +/// # Arguments +/// * `attr` - Attribute tokens containing component specification +/// * `item` - The input trait definition tokens +/// +/// # Returns +/// * `TokenStream` - Generated code containing all component implementations +/// +/// # Generated Items +/// For a component named 'MyComponent': +/// ```ignore +/// // Component name struct +/// pub struct MyComponent; +/// +/// // Provider trait +/// pub trait MyComponentProvider { ... } +/// +/// // Consumer implementation +/// impl> MyComponent for T { ... } +/// +/// // Provider implementation +/// impl MyComponentProvider for T where T: Provider { ... } +/// ``` pub fn derive_component(attr: TokenStream, item: TokenStream) -> TokenStream { let spec: ComponentSpec = syn::parse2(attr).unwrap(); diff --git a/crates/cgp-component-macro-lib/src/derive_component/entry.rs b/crates/cgp-component-macro-lib/src/derive_component/entry.rs index ad38eed..7a53fbb 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/entry.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/entry.rs @@ -1,3 +1,8 @@ +/// Parsing utilities for key-value entries in component specifications. +/// +/// This module provides structures and parsing implementations for handling +/// key-value pairs in component macro syntax, such as field specifications +/// and component configurations. use std::collections::BTreeMap; use syn::parse::{Parse, ParseStream}; @@ -5,6 +10,18 @@ use syn::punctuated::Punctuated; use syn::token::{Colon, Comma}; use syn::{Ident, Type}; +/// A single key-value entry in a component specification. +/// +/// # Fields +/// +/// * `key` - The identifier key of the entry +/// * `value` - The type associated with the key +/// +/// # Example +/// +/// ```rust,ignore +/// field_name: FieldType +/// ``` pub struct Entry { pub key: Ident, pub value: Type, @@ -20,6 +37,24 @@ impl Parse for Entry { } } +/// A collection of key-value entries stored in a sorted map. +/// +/// # Fields +/// +/// * `entries` - A BTreeMap storing entries sorted by their key identifiers +/// +/// # Example +/// +/// ```rust,ignore +/// field1: Type1, +/// field2: Type2, +/// field3: Type3 +/// ``` +/// +/// # Note +/// +/// Using BTreeMap ensures consistent ordering of entries, which is important +/// for deterministic code generation. pub struct Entries { pub entries: BTreeMap, } diff --git a/crates/cgp-component-macro-lib/src/derive_component/mod.rs b/crates/cgp-component-macro-lib/src/derive_component/mod.rs index cc61ec6..477a595 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/mod.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/mod.rs @@ -1,3 +1,9 @@ +/// Module for deriving component implementations. +/// +/// This module contains the core functionality for deriving component implementations +/// in the CGP (Component-based Generic Programming) framework. It handles both provider +/// and consumer implementations, along with various utility functions for processing +/// component specifications and type manipulations. pub mod component_name; pub mod component_spec; pub mod consumer_impl; diff --git a/crates/cgp-component-macro-lib/src/derive_component/provider_impl.rs b/crates/cgp-component-macro-lib/src/derive_component/provider_impl.rs index 658122c..2283a82 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/provider_impl.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/provider_impl.rs @@ -1,3 +1,7 @@ +/// Implementation generation for component providers. +/// +/// This module handles the generation of provider implementations that delegate +/// component functionality to their underlying implementations. use proc_macro2::Span; use syn::punctuated::Punctuated; use syn::token::{Brace, Comma, For, Impl, Plus}; @@ -9,6 +13,42 @@ use syn::{ use crate::derive_component::delegate_fn::derive_delegated_fn_impl; use crate::derive_component::delegate_type::derive_delegate_type_impl; +/// Derives an implementation of a provider trait for a component. +/// +/// This function generates the implementation that allows a component to delegate +/// its functionality to an underlying type that implements the provider trait. +/// +/// # Arguments +/// * `provider_trait` - The trait defining the provider interface +/// * `component_name` - Name of the component being implemented +/// * `component_params` - Generic parameters for the component +/// +/// # Returns +/// * `ItemImpl` - The generated implementation block +/// +/// # Generated Code Example +/// ```ignore +/// impl MyProvider for Component +/// where +/// Component: DelegateComponent>, +/// Component::Delegate: MyProvider +/// { +/// // Delegated function implementations +/// fn my_function(&self) -> Result<(), Error> { +/// self.delegate().my_function() +/// } +/// +/// // Delegated associated type implementations +/// type MyType = >::MyType; +/// } +/// ``` +/// +/// # Implementation Details +/// The function: +/// 1. Constructs generic parameters for the implementation +/// 2. Adds necessary trait bounds for delegation +/// 3. Generates delegating implementations for all trait items +/// 4. Handles both associated functions and associated types pub fn derive_provider_impl( provider_trait: &ItemTrait, component_name: &Ident, diff --git a/crates/cgp-component-macro-lib/src/derive_component/provider_trait.rs b/crates/cgp-component-macro-lib/src/derive_component/provider_trait.rs index 8a3addb..076aa37 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/provider_trait.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/provider_trait.rs @@ -1,3 +1,7 @@ +/// Provider trait generation and transformation. +/// +/// This module handles the generation of provider traits from consumer traits, +/// including the transformation of self types and receivers into context types. use syn::punctuated::Punctuated; use syn::{parse_quote, Ident, ItemTrait, TraitItem}; @@ -6,6 +10,48 @@ use crate::derive_component::replace_self_type::{ iter_parse_and_replace_self_type, parse_and_replace_self_type, }; +/// Derives a provider trait from a consumer trait definition. +/// +/// This function transforms a consumer trait into a provider trait by: +/// 1. Adding a context type parameter +/// 2. Converting self-type references to context type references +/// 3. Moving supertrait bounds to where clauses on the context type +/// +/// # Arguments +/// * `consumer_trait` - The original consumer trait to transform +/// * `provider_name` - Name for the generated provider trait +/// * `context_type` - Name of the context type parameter +/// +/// # Returns +/// * `syn::Result` - The generated provider trait +/// +/// # Example Transformation +/// From consumer trait: +/// ```ignore +/// trait MyComponent: SuperTrait { +/// fn my_method(&self) -> Self::Output; +/// type Output; +/// } +/// ``` +/// +/// To provider trait: +/// ```ignore +/// trait MyComponentProvider +/// where +/// Context: SuperTrait +/// { +/// fn my_method(&self, context: &Context) -> Self::Output; +/// type Output; +/// } +/// ``` +/// +/// # Implementation Details +/// The function performs these transformations: +/// 1. Adds the context type parameter +/// 2. Moves supertrait bounds to where clauses +/// 3. Replaces self type references with context type +/// 4. Transforms method signatures to accept context parameters +/// 5. Preserves associated types while updating their bounds pub fn derive_provider_trait( consumer_trait: &ItemTrait, provider_name: &Ident, diff --git a/crates/cgp-component-macro-lib/src/derive_component/replace_self_receiver.rs b/crates/cgp-component-macro-lib/src/derive_component/replace_self_receiver.rs index 27351b6..6923f35 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/replace_self_receiver.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/replace_self_receiver.rs @@ -1,8 +1,53 @@ +/// Utilities for replacing self receivers in trait function signatures. +/// +/// This module provides functionality to replace `self` receivers in trait methods +/// with explicit type parameters, preserving reference and mutability information. use proc_macro2::Ident; use syn::{parse_quote, FnArg, TraitItemFn}; use crate::derive_component::snake_case::to_snake_case_ident; +/// Replaces a self receiver in a trait function with an explicit type parameter. +/// +/// This function modifies a trait function's signature by replacing any self receiver +/// with an explicit parameter of the specified type, maintaining all reference, +/// lifetime, and mutability qualifiers. +/// +/// # Arguments +/// +/// * `func` - The trait function to modify +/// * `replaced_type` - The type to use instead of Self +/// +/// # Examples +/// +/// ```rust,ignore +/// // Before: +/// fn process(&self) -> Result<()> +/// +/// // After (with replaced_type = MyType): +/// fn process(my_type: &MyType) -> Result<()> +/// +/// // Before: +/// fn consume(self) -> Result<()> +/// +/// // After: +/// fn consume(my_type: MyType) -> Result<()> +/// +/// // Before: +/// fn modify(&mut self) -> Result<()> +/// +/// // After: +/// fn modify(my_type: &mut MyType) -> Result<()> +/// ``` +/// +/// # Note +/// +/// The function handles all combinations of: +/// - Owned self (self) +/// - Shared reference (&self) +/// - Mutable reference (&mut self) +/// - Named lifetimes (&'a self) +/// - Named mutable lifetimes (&'a mut self) pub fn replace_self_receiver(func: &mut TraitItemFn, replaced_type: &Ident) { if let Some(arg) = func.sig.inputs.first_mut() { if let FnArg::Receiver(receiver) = arg { diff --git a/crates/cgp-component-macro-lib/src/derive_component/replace_self_type.rs b/crates/cgp-component-macro-lib/src/derive_component/replace_self_type.rs index 6ee1006..527fda4 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/replace_self_type.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/replace_self_type.rs @@ -1,8 +1,28 @@ +/// Utilities for replacing Self type references in token streams. +/// +/// This module provides functionality to replace occurrences of the `Self` type +/// with a concrete type identifier while preserving associated type references. use itertools::Itertools; use proc_macro2::{Group, Ident, TokenStream, TokenTree}; use quote::{format_ident, ToTokens}; use syn::parse::Parse; +/// Processes a collection of items, replacing Self types in each item. +/// +/// # Arguments +/// +/// * `vals` - Collection of items to process +/// * `replaced_ident` - The identifier to replace Self with +/// * `local_assoc_types` - List of local associated type names to preserve +/// +/// # Returns +/// +/// A Result containing the processed collection with Self types replaced +/// +/// # Type Parameters +/// +/// * `I` - Collection type that can be converted to and from an iterator +/// * `T` - Item type that can be converted to tokens and parsed pub fn iter_parse_and_replace_self_type( vals: I, replaced_ident: &Ident, @@ -17,6 +37,21 @@ where .collect() } +/// Processes a single item, replacing Self types within it. +/// +/// # Arguments +/// +/// * `val` - The item to process +/// * `replaced_ident` - The identifier to replace Self with +/// * `local_assoc_types` - List of local associated type names to preserve +/// +/// # Returns +/// +/// A Result containing the processed item with Self types replaced +/// +/// # Type Parameters +/// +/// * `T` - Type that can be converted to tokens and parsed pub fn parse_and_replace_self_type( val: &T, replaced_ident: &Ident, @@ -29,6 +64,36 @@ where syn::parse2(stream) } +/// Replaces Self type references in a token stream. +/// +/// This function walks through a token stream and replaces occurrences of the +/// `Self` type with a specified identifier, while being careful to preserve +/// associated type expressions (e.g., `Self::AssocType`). +/// +/// # Arguments +/// +/// * `stream` - The token stream to process +/// * `replaced_ident` - The identifier to replace Self with +/// * `local_assoc_types` - List of local associated type names to preserve +/// +/// # Returns +/// +/// A new TokenStream with Self types replaced +/// +/// # Examples +/// +/// ```rust,ignore +/// let stream = quote!(fn process(input: Self) -> Self::Output); +/// let replaced = replace_self_type(stream, &format_ident!("MyType"), &vec![]); +/// // Results in: fn process(input: MyType) -> MyType::Output +/// ``` +/// +/// # Note +/// +/// The function is careful to handle: +/// - Associated type expressions (Self::Type) +/// - Local associated types that should not be replaced +/// - Nested token groups (parentheses, brackets, braces) pub fn replace_self_type( stream: TokenStream, replaced_ident: &Ident, diff --git a/crates/cgp-component-macro-lib/src/derive_component/signature_args.rs b/crates/cgp-component-macro-lib/src/derive_component/signature_args.rs index 2f6961e..5d34ce7 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/signature_args.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/signature_args.rs @@ -1,8 +1,40 @@ +/// Utilities for extracting and processing function signature arguments. use proc_macro2::Span; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{parse_quote, FnArg, Ident, Signature}; +/// Converts a function signature's arguments into a sequence of identifiers. +/// +/// This function processes a function's signature and extracts the names of all +/// its arguments, handling both self receivers and typed arguments. +/// +/// # Arguments +/// +/// * `sig` - The function signature to process +/// +/// # Returns +/// +/// A comma-separated sequence of identifiers representing the argument names. +/// For self receivers, returns the identifier "self". +/// For typed arguments, returns the pattern identifier. +/// +/// # Examples +/// +/// ```rust,ignore +/// let sig: Signature = parse_quote!(fn process(&self, data: String) -> Result<()>); +/// let args = signature_to_args(&sig); +/// // Results in: self, data +/// +/// let sig: Signature = parse_quote!(fn transform(input: i32, scale: f64) -> i32); +/// let args = signature_to_args(&sig); +/// // Results in: input, scale +/// ``` +/// +/// # Note +/// +/// This function is particularly useful when generating delegating implementations +/// where the argument names need to be forwarded to another function. pub fn signature_to_args(sig: &Signature) -> Punctuated { let args = sig .inputs diff --git a/crates/cgp-component-macro-lib/src/derive_component/snake_case.rs b/crates/cgp-component-macro-lib/src/derive_component/snake_case.rs index 6e82abc..6b03e57 100644 --- a/crates/cgp-component-macro-lib/src/derive_component/snake_case.rs +++ b/crates/cgp-component-macro-lib/src/derive_component/snake_case.rs @@ -1,6 +1,28 @@ +/// Utilities for converting identifiers to snake_case format. use proc_macro2::Span; use syn::Ident; +/// Converts a string to snake_case format. +/// +/// This function converts a camelCase or PascalCase string to snake_case by: +/// 1. Inserting underscores before uppercase letters (except at the start) +/// 2. Converting all characters to lowercase +/// +/// # Arguments +/// +/// * `val` - The string to convert +/// +/// # Returns +/// +/// A new String in snake_case format +/// +/// # Examples +/// +/// ``` +/// # use cgp_component_macro_lib::derive_component::snake_case::to_snake_case_str; +/// assert_eq!(to_snake_case_str("MyComponent"), "my_component"); +/// assert_eq!(to_snake_case_str("processData"), "process_data"); +/// ``` pub fn to_snake_case_str(val: &str) -> String { let mut acc = String::new(); let mut prev = '_'; @@ -16,6 +38,28 @@ pub fn to_snake_case_str(val: &str) -> String { acc.to_lowercase() } +/// Converts an identifier to its snake_case equivalent. +/// +/// Creates a new identifier with the same content as the input but converted +/// to snake_case format. The new identifier is created with the call site span. +/// +/// # Arguments +/// +/// * `val` - The identifier to convert +/// +/// # Returns +/// +/// A new `syn::Ident` in snake_case format +/// +/// # Examples +/// +/// ``` +/// # use syn::{parse_quote, Ident}; +/// # use cgp_component_macro_lib::derive_component::snake_case::to_snake_case_ident; +/// let ident: Ident = parse_quote!(MyComponent); +/// let snake = to_snake_case_ident(&ident); +/// assert_eq!(snake.to_string(), "my_component"); +/// ``` pub fn to_snake_case_ident(val: &Ident) -> Ident { Ident::new(&to_snake_case_str(&val.to_string()), Span::call_site()) } diff --git a/crates/cgp-component-macro-lib/src/for_each_replace.rs b/crates/cgp-component-macro-lib/src/for_each_replace.rs index b385379..9b1b314 100644 --- a/crates/cgp-component-macro-lib/src/for_each_replace.rs +++ b/crates/cgp-component-macro-lib/src/for_each_replace.rs @@ -9,12 +9,27 @@ use syn::{braced, Ident, Type}; use crate::delegate_components::ast::ComponentAst; +/// Specification for token replacement in a macro. +/// +/// This structure holds the information needed to perform token replacements +/// in a macro expansion, including the target identifier to replace, +/// the replacement tokens, and the body where replacements should occur. +#[derive(Debug)] pub struct ReplaceSpecs { + /// The identifier to be replaced in the body pub target_ident: Ident, + /// List of token streams that will replace the target identifier pub replacements: Vec, + /// The body of code where replacements will occur pub body: TokenStream, } +/// Parser implementation for ReplaceSpecs +/// +/// Parses the syntax: +/// ```ignore +/// [Type1, Type2, ...], [ExcludeType1, ExcludeType2, ...] | target_ident | { body } +/// ``` impl Parse for ReplaceSpecs { fn parse(input: ParseStream) -> syn::Result { let raw_replacements: Vec = { @@ -70,6 +85,13 @@ impl Parse for ReplaceSpecs { } } +/// Handles the for_each_replace macro expansion +/// +/// # Arguments +/// * `tokens` - Input token stream containing replacement specifications +/// +/// # Returns +/// * `syn::Result` - Expanded code with all replacements applied pub fn handle_for_each_replace(tokens: TokenStream) -> syn::Result { let specs: ReplaceSpecs = syn::parse2(tokens)?; @@ -80,6 +102,13 @@ pub fn handle_for_each_replace(tokens: TokenStream) -> syn::Result )) } +/// Handles the replace macro expansion for a single replacement +/// +/// # Arguments +/// * `tokens` - Input token stream containing replacement specification +/// +/// # Returns +/// * `syn::Result` - Expanded code with replacement applied pub fn handle_replace(tokens: TokenStream) -> syn::Result { let specs: ReplaceSpecs = syn::parse2(tokens)?; @@ -90,6 +119,15 @@ pub fn handle_replace(tokens: TokenStream) -> syn::Result { Ok(replace_stream(&specs.target_ident, &tokens, specs.body)) } +/// Performs multiple replacements in a body of code +/// +/// # Arguments +/// * `target_ident` - The identifier to replace +/// * `replacements` - List of token streams to use as replacements +/// * `body` - The code where replacements should occur +/// +/// # Returns +/// * `TokenStream` - The code with all replacements applied pub fn for_each_replace( target_ident: &Ident, replacements: &[TokenStream], @@ -101,6 +139,15 @@ pub fn for_each_replace( .collect() } +/// Replaces a target identifier with a replacement token stream in a body of code +/// +/// # Arguments +/// * `target_ident` - The identifier to replace +/// * `replacement` - The token stream to use as replacement +/// * `body` - The code where replacement should occur +/// +/// # Returns +/// * `TokenStream` - The code with replacement applied pub fn replace_stream( target_ident: &Ident, replacement: &TokenStream, @@ -111,6 +158,15 @@ pub fn replace_stream( .collect() } +/// Replaces a target identifier with a replacement token stream in a single token tree +/// +/// # Arguments +/// * `target_ident` - The identifier to replace +/// * `replacement` - The token stream to use as replacement +/// * `body` - The token tree where replacement should occur +/// +/// # Returns +/// * `TokenStream` - The token tree with replacement applied pub fn replace_tree( target_ident: &Ident, replacement: &TokenStream, diff --git a/crates/cgp-component-macro-lib/src/lib.rs b/crates/cgp-component-macro-lib/src/lib.rs index 4267725..f1f6794 100644 --- a/crates/cgp-component-macro-lib/src/lib.rs +++ b/crates/cgp-component-macro-lib/src/lib.rs @@ -3,6 +3,14 @@ proc macros for `cgp-component` as a library, so that it can be more easily tested. The constructs are then re-exported as proc macros in the `cgp-component-macro` crate, which is defined as a proc macro crate. + + # Overview + This crate provides the core implementation for component-based programming macros. + It includes functionality for: + - Delegating component implementations + - Deriving component traits + - Pattern replacement utilities + - Preset component definitions */ pub mod delegate_components; diff --git a/crates/cgp-component-macro-lib/src/preset/ast.rs b/crates/cgp-component-macro-lib/src/preset/ast.rs index 9f735a3..9795048 100644 --- a/crates/cgp-component-macro-lib/src/preset/ast.rs +++ b/crates/cgp-component-macro-lib/src/preset/ast.rs @@ -1,15 +1,46 @@ +/// Abstract Syntax Tree definitions for preset parsing. +/// +/// This module provides the AST structures necessary for parsing preset definitions +/// in the CGP framework. use syn::parse::{Parse, ParseStream}; use syn::token::Lt; use syn::{Generics, Ident}; use crate::delegate_components::ast::DelegateEntriesAst; +/// AST node representing a complete preset definition. +/// +/// Captures all the necessary information for defining a preset, including its +/// identifier, generic parameters, and delegation specifications. +/// +/// # Fields +/// +/// * `preset_ident` - The identifier for the preset being defined +/// * `preset_generics` - Generic parameters associated with the preset +/// * `delegate_entries` - Specifications for component delegations within the preset +/// +/// # Examples +/// +/// ```text +/// MyPreset { +/// [ComponentA, ComponentB]: Inner +/// } +/// ``` pub struct DefinePresetAst { pub preset_ident: Ident, pub preset_generics: Generics, pub delegate_entries: DelegateEntriesAst, } +/// Parse implementation for preset definitions. +/// +/// Parses input in the format: +/// ```text +/// preset_name? { delegate_entries } +/// ``` +/// +/// The generic parameters are optional, and delegate entries follow the same +/// format as in component delegation. impl Parse for DefinePresetAst { fn parse(input: ParseStream) -> syn::Result { let preset_ident: Ident = input.parse()?; diff --git a/crates/cgp-component-macro-lib/src/preset/define_preset.rs b/crates/cgp-component-macro-lib/src/preset/define_preset.rs index a12bb50..c07d5d9 100644 --- a/crates/cgp-component-macro-lib/src/preset/define_preset.rs +++ b/crates/cgp-component-macro-lib/src/preset/define_preset.rs @@ -1,3 +1,7 @@ +/// Functions for defining component presets in the CGP framework. +/// +/// This module provides the core functionality for defining presets, which are +/// reusable component configurations that can be applied to different types. use proc_macro2::{Span, TokenStream}; use quote::ToTokens; use syn::{parse_quote, Ident, ItemTrait}; @@ -10,6 +14,38 @@ use crate::preset::ast::DefinePresetAst; use crate::preset::impl_is_preset::impl_components_is_preset; use crate::preset::substitution_macro::define_substitution_macro; +/// Defines a new component preset. +/// +/// This function processes a preset definition and generates all the necessary +/// code for implementing the preset, including: +/// - The preset struct definition +/// - The preset trait and its implementations +/// - Delegation trait implementations +/// - Helper macros for working with the preset +/// +/// # Arguments +/// +/// * `body` - Token stream containing the preset definition +/// +/// # Returns +/// +/// Returns a `Result` containing the generated token stream if successful, +/// or a syntax error if parsing fails. +/// +/// # Examples +/// +/// For a preset definition like: +/// ```text +/// MyPreset { +/// [ComponentA, ComponentB]: Inner +/// } +/// ``` +/// +/// This function generates: +/// - A struct `MyPreset` +/// - A trait `IsMyPreset` +/// - Implementation of component delegation +/// - A `with_my_preset` macro for type substitution pub fn define_preset(body: TokenStream) -> syn::Result { let ast: DefinePresetAst = syn::parse2(body)?; diff --git a/crates/cgp-component-macro-lib/src/preset/impl_is_preset.rs b/crates/cgp-component-macro-lib/src/preset/impl_is_preset.rs index 3fcdcc1..db8691d 100644 --- a/crates/cgp-component-macro-lib/src/preset/impl_is_preset.rs +++ b/crates/cgp-component-macro-lib/src/preset/impl_is_preset.rs @@ -1,7 +1,27 @@ +/// Implementation generation for preset trait bounds. +/// +/// This module provides functionality for generating trait implementations that +/// establish the relationship between presets and their component types. use syn::{parse_quote, Generics, Ident, ItemImpl, Type}; use crate::delegate_components::ast::{ComponentAst, DelegateEntriesAst}; +/// Generates implementations of the preset trait for all components. +/// +/// Creates trait implementations that establish which components are part +/// of a preset, allowing the preset to be used with those component types. +/// +/// # Arguments +/// +/// * `trait_name` - Name of the preset trait (e.g., `IsMyPreset`) +/// * `preset_type` - Type of the preset +/// * `preset_generics` - Generic parameters for the preset +/// * `delegate_entries` - Component delegation specifications +/// +/// # Returns +/// +/// Returns a vector of trait implementations, one for each component in +/// the preset's delegation specifications. pub fn impl_components_is_preset( trait_name: &Ident, preset_type: &Type, @@ -19,6 +39,27 @@ pub fn impl_components_is_preset( .collect() } +/// Generates a single preset trait implementation for a component. +/// +/// Creates the implementation that establishes that a specific component +/// type can be used with the preset. +/// +/// # Arguments +/// +/// * `trait_name` - Name of the preset trait +/// * `_preset_type` - Type of the preset (currently unused) +/// * `_preset_generics` - Generic parameters for the preset (currently unused) +/// * `component` - The component to implement the preset trait for +/// +/// # Returns +/// +/// Returns an implementation of the preset trait for the specified component. +/// +/// # Note +/// +/// The preset generic parameter may be absent if it is used as part of the +/// component name's generic parameters. This is a known limitation that +/// needs to be addressed in future updates. pub fn impl_component_is_preset( trait_name: &Ident, _preset_type: &Type, diff --git a/crates/cgp-component-macro-lib/src/preset/mod.rs b/crates/cgp-component-macro-lib/src/preset/mod.rs index baf977a..de1aad1 100644 --- a/crates/cgp-component-macro-lib/src/preset/mod.rs +++ b/crates/cgp-component-macro-lib/src/preset/mod.rs @@ -1,3 +1,47 @@ +/// Component preset system for the CGP framework. +/// +/// This module provides a powerful preset system that allows defining reusable +/// component configurations. Presets enable the creation of common component +/// patterns that can be applied to different types, reducing code duplication +/// and promoting consistent component usage patterns. +/// +/// # Module Structure +/// +/// * [`ast`] - Abstract Syntax Tree definitions for parsing preset specifications +/// * [`mod@define_preset`] - Core functionality for defining new presets +/// * [`impl_is_preset`] - Trait implementations for preset type relationships +/// * [`substitution_macro`] - Macro utilities for type substitution in presets +/// +/// # Usage +/// +/// Presets are typically defined using the `define_preset` macro: +/// +/// ```rust,ignore +/// define_preset! { +/// MyPreset { +/// [Debug, Display]: Inner +/// } +/// } +/// ``` +/// +/// This generates: +/// - A struct `MyPreset` +/// - A trait `IsMyPreset` +/// - Delegation implementations +/// - A `with_my_preset` macro for type substitution +/// +/// The preset can then be used to apply common component patterns: +/// +/// ```rust,ignore +/// #[derive(Debug, Display)] +/// struct Inner(T); +/// +/// struct Wrapper { +/// inner: Inner +/// } +/// +/// impl DelegatesTo, Inner> for Wrapper {} +/// ``` pub mod define_preset; pub use define_preset::define_preset; pub mod ast; diff --git a/crates/cgp-component-macro-lib/src/preset/substitution_macro.rs b/crates/cgp-component-macro-lib/src/preset/substitution_macro.rs index 918ca55..ec8732a 100644 --- a/crates/cgp-component-macro-lib/src/preset/substitution_macro.rs +++ b/crates/cgp-component-macro-lib/src/preset/substitution_macro.rs @@ -1,7 +1,39 @@ +/// Macro generation utilities for type substitution in presets. +/// +/// This module provides functionality for creating macros that perform +/// type substitution when working with presets. use proc_macro2::TokenStream; use quote::quote; use syn::Ident; +/// Defines a macro for component type substitution. +/// +/// Creates a macro that can substitute component types in a preset with +/// their concrete implementations. This is useful for applying preset +/// configurations to specific types. +/// +/// # Arguments +/// +/// * `macro_name` - Name of the macro to generate +/// * `substitution` - Token stream containing the types to substitute +/// +/// # Returns +/// +/// Returns a token stream containing the macro definition. +/// +/// # Examples +/// +/// For a preset with components `[ComponentA, ComponentB]`, this generates: +/// ```text +/// macro_rules! with_my_preset { +/// ($($body:tt)*) => { +/// replace_with! { +/// [ComponentA, ComponentB], +/// $($body)* +/// } +/// }; +/// } +/// ``` pub fn define_substitution_macro(macro_name: &Ident, substitution: &TokenStream) -> TokenStream { quote! { #[macro_export]