Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add minimal documentation to CGP framework #46

Closed
wants to merge 6 commits into from

Conversation

marvin-hansen
Copy link

Addresses issue #45

Add detailed Rust documentation across multiple CGP crates:

cgp-component-macro:

  • Document all procedural macros with examples
  • Improve type parameter naming conventions
  • Add clear usage patterns and best practices

cgp-field:

  • Document core traits and type system
  • Add field access and manipulation examples
  • Improve type-level documentation

cgp-field-macro-lib:

  • Document internal macro implementations
  • Add type construction patterns
  • Provide detailed expansion examples

All documentation follows Rust best practices including:

  • Clear descriptions and examples
  • Proper cross-references
  • Type parameter documentation
  • Implementation notes

Changes are documentation-only, improving code clarity without
modifying functionality.

…cro components

Addresses issue:
contextgeneric#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 <[email protected]>
…nent

Change the type parameter name from `N` to `Name` in DelegateComponent trait
to better reflect its purpose as the component type being delegated. This
makes the code more self-documenting and follows Rust naming conventions
for type parameters.

The change is purely cosmetic and does not affect functionality:
- Improves code readability
- Better communicates parameter purpose
- Maintains backward compatibility
- Follows Rust type parameter naming guidelines

 Signed-off-by: Marvin Hansen <[email protected]>
Add detailed documentation for all procedural macros in the CGP component
system. The documentation follows Rust's best practices and includes:

Crate Level:
- Overview of macro functionality and purpose
- Organized sections for different macro categories
- Complete examples for each macro type

Individual Macros:
- cgp_component: Attribute macro for component definition
- delegate_components: Macro for component delegation
- cgp_preset: Macro for component configuration presets
- for_each_replace: Utility for type replacement iteration
- replace_with: Utility for type substitution

Each macro is documented with:
- Clear descriptions of functionality
- Practical usage examples
- Proper macro linking syntax using macro@
- Implementation notes and best practices

Fixed documentation warnings:
- Corrected ambiguous macro references in doc links
- Added proper macro@ prefix for attribute macros
- Ensured consistent formatting across all examples

Part of the ongoing effort to improve CGP framework documentation.

 Signed-off-by: Marvin Hansen <[email protected]>
Add detailed documentation throughout the cgp-field crate to improve
usability and understanding. This includes:

Core Types:
- Field: Type-safe field representation with phantom types
- Char: Type-level character representation for field names
- Index: Type-safe indexing with const generics
- Either/Void: Sum types for variant handling
- Cons/Nil: Product types for heterogeneous lists

Traits:
- HasField/FieldGetter: Read-only field access traits
- HasFieldMut/MutFieldGetter: Mutable field access traits

Implementations:
- UseField: Type provider pattern for field access
- WithField: Provider-wrapped field access utilities

Module Documentation:
- types/: Type definitions and constructors
- traits/: Field access trait definitions
- impls/: Concrete implementations and providers

Each component is documented with:
- Clear descriptions of purpose and functionality
- Type parameter explanations
- Practical usage examples
- Implementation details
- Cross-references between related items

Also fixes documentation link in types/mod.rs to use proper mod@ prefix
for module references.

Part of the ongoing effort to improve CGP framework documentation.

 Signed-off-by: Marvin Hansen <[email protected]>
Add detailed documentation to the internal macro implementation crate,
explaining the core functionality and implementation details:

Core Components:
- field: Field access trait derivation with type-safe accessors
- product: Product and sum type construction utilities
- symbol: Type-level symbol generation from strings

Key Features Documented:
- Trait derivation implementation for HasField and HasFieldMut
- Nested type construction for product and sum types
- Type-level symbol generation with character-level precision
- Parser implementations for macro input processing

Implementation Details:
- Clear explanation of token stream handling
- Type generation and manipulation patterns
- Integration with syn and quote for macro expansion
- Error handling and edge cases

Each module and function includes:
- Purpose and functionality description
- Type parameter documentation
- Return value specifications
- Practical usage examples
- Implementation notes

This documentation helps maintainers understand the internal workings
of the CGP field macros while keeping the code itself unchanged.

 Signed-off-by: Marvin Hansen <[email protected]>
Copy link
Collaborator

@soareschen soareschen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marvin-hansen I just saw your pull request. Thanks a lot on the effort you put in to help document the crate!

I have looked through some of your documentation, however it seems like there are quite a number of misunderstanding on the use of the constructs, especially when they are not yet covered by the book that I am writing. Also, the PR is pretty large and can be challenging to discuss and approve everything together.

I'd suggest that you break down the pull requests by topics covered by each chapter in the book. As for the constructs that are not yet covered by the book, I think it might be better if you hold off the documentation until the relevant chapter is ready.

///
/// ```rust,ignore
/// cgp_preset! {
/// struct LoggingPreset {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no struct keyword in front of the preset name.

/// cgp_preset! {
/// struct LoggingPreset {
/// logger: ConsoleLogger,
/// metrics: PrometheusMetrics,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example mapping here should follow the same naming convention for the name type of CGP components. i.e.:

cgp_preset! {
    LoggerComponent: LogToConsole,
    MetricsComponent: UsePrometheusMetrics,
}

/// [T] in [String, i32, bool] {
/// fn process(value: T) -> T { value }
/// }
/// }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual syntax for this macro is:

for_each_replace! {
    [ FooComponent, BarComponent, BazComponent ],
    | Component | {
        impl DelegateComponent<Component> for TargetProvider {
            type Delegate = SourceProvider;
        }
    }
}

which would be expanded to:

impl DelegateComponent<FooComponent> for TargetProvider {
    type Delegate = SourceProvider;
}

impl DelegateComponent<BarComponent> for TargetProvider {
    type Delegate = SourceProvider;
}

impl DelegateComponent<BazComponent> for TargetProvider {
    type Delegate = SourceProvider;
}

///
/// ```rust,ignore
/// replace_with! {
/// type NewType = OldType<String>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual syntax for this macro is:

replace_with! {
    [ FooComponent, BarComponent, BazComponent ],
    | Components | {
        delegate_components! {
            TargetProvider {
                Components: SourceProvider,
            }
        }
    }
}

Which would be expanded into:

delegate_components! {
    TargetProvider {
        [ FooComponent, BarComponent, BazComponent ]: 
            SourceProvider,
    }
}

/// println!("[{}] {}", self.context, message);
/// }
/// }
/// ```
pub struct UseContext;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the UseContext pattern is used for implementing a provider that simply uses the context to provide the implementation. Something like:

#[cgp_component {
    provider: RequestHandler,
}]
pub trait CanHandleRequest {
    fn handle_request(&self, request: &Request) -> Response;
}

impl<Context> RequestHandler<Context> for UseContext 
where
    Context: CanHandleRequest,
{
    fn handle_request(context: &Context, request: &Request) -> Response {
        context.handle_request
    }
}

The main use is for higher-order providers, where providers are passed explitly as "arguments" via generic parameters, which we have not covered in the book. In that case, the UseContext provider means that we want to provide the implementation via the context, instead of via the custom provider argument.

///
/// ```rust,ignore
/// let name_symbol = symbol!(name);
/// let age_symbol = symbol!(age);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The symbol! macro is a way to lift string values to the type level. So something like symbol!("foo") is a type that uniquely represents the string "foo".

/// # Examples
///
/// ```rust,ignore
/// Product! {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Product! macro generates anonymous structs as type-level lists. So something like Product![String, u32, bool] is desugared to Cons<String, Cons<u32, Cons<bool, Nil>>>.

/// match shape {
/// Shape::Circle(r) => println!("Circle with radius {}", r),
/// Shape::Rectangle(w, h) => println!("Rectangle {}x{}", w, h),
/// }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Sum! macro is similar to Product! that it generates anonymous sum types. So something like Sum![String, u32, bool] is desugared to Either<String, Either<u32, Either<bool, Void>>>.

/// y: 2.0,
/// }
/// };
/// ```
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The product! macro is used for value-level pattern matching and construction of product values. So something like product![foo, bar, baz] is desugared to Cons(foo, Cons(bar, Cons(baz, Nil))).

///
/// struct Name;
/// let provider = UseField(PhantomData::<Name>);
/// ```
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UseField pattern is used for implementing getter traits using HasField. Something like:

#[cgp_component {
    provider: NameGetter,
}]
pub trait HasName {
    fn get_name(&self) -> &String;
}

impl<Context, Tag> NameGetter<Context> for UseField<Tag>
where
    Context: HasField<Tag, Value = String>,
{
    fn get_name(context: &Context) -> &String {
        context.get_field(PhantomData)
    }
}

pub type GetNameFromNameField = UseField<symbol!("name")>;

We will cover the pattern in later chapters of the book.

@marvin-hansen
Copy link
Author

No problem.

I close this PR for good, and then gradually re-submit one crate at a time with the docs and your suggestions and probably add applicable references to the book

@marvin-hansen I just saw your pull request. Thanks a lot on the effort you put in to help document the crate!

I have looked through some of your documentation, however it seems like there are quite a number of misunderstanding on the use of the constructs, especially when they are not yet covered by the book that I am writing. Also, the PR is pretty large and can be challenging to discuss and approve everything together.

I'd suggest that you break down the pull requests by topics covered by each chapter in the book. As for the constructs that are not yet covered by the book, I think it might be better if you hold off the documentation until the relevant chapter is ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants