From a491e4b2d9bfdc789fdf292ed690ce50d16e6425 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 2 Jul 2026 00:25:15 +0200 Subject: [PATCH 1/3] Scaffold initial implementation docs --- crates/macros/cgp-macro-core/CLAUDE.md | 10 +++ .../delegated_impls/provider_trait.rs | 2 + .../functions/delegated_impls/trait_items.rs | 2 + .../src/functions/is_provider_params.rs | 5 ++ .../src/functions/parse_internal.rs | 3 + .../cgp-macro-core/src/macros/keyword.rs | 2 + .../macros/cgp-macro-core/src/macros/parse.rs | 3 + .../cgp_component/args/component_args.rs | 3 + .../src/types/cgp_component/args/raw.rs | 3 + .../src/types/cgp_component/evaluated/item.rs | 7 ++ .../evaluated/to_redirect_lookup_impl.rs | 5 ++ .../evaluated/to_use_context_impl.rs | 2 + .../src/types/cgp_component/item.rs | 3 + .../types/cgp_component/preprocessed/item.rs | 6 ++ .../preprocessed/to_consumer_impl.rs | 2 + .../preprocessed/to_provider_blanket_impl.rs | 3 + .../preprocessed/to_provider_trait.rs | 3 + .../macros/cgp-macro-lib/src/cgp_component.rs | 2 + crates/tests/CLAUDE.md | 39 ++++++---- .../tests/parser_rejections/cgp_component.rs | 3 +- .../tests/basic_delegation/component_macro.rs | 4 +- .../tests/basic_delegation/default_methods.rs | 5 +- .../generic_components/component_lifetime.rs | 4 +- docs/CLAUDE.md | 12 ++- docs/implementation/CLAUDE.md | 57 +++++++++++++++ docs/implementation/README.md | 49 +++++++++++++ docs/implementation/asts/cgp_component.md | 39 ++++++++++ .../entrypoints/cgp_component.md | 73 +++++++++++++++++++ .../functions/derive/delegated_impls.md | 27 +++++++ .../functions/parse/is_provider_params.md | 21 ++++++ docs/implementation/macros/define_keyword.md | 17 +++++ docs/implementation/macros/parse_internal.md | 21 ++++++ docs/reference/README.md | 2 +- docs/reference/macros/cgp_component.md | 4 +- 34 files changed, 419 insertions(+), 24 deletions(-) create mode 100644 docs/implementation/CLAUDE.md create mode 100644 docs/implementation/README.md create mode 100644 docs/implementation/asts/cgp_component.md create mode 100644 docs/implementation/entrypoints/cgp_component.md create mode 100644 docs/implementation/functions/derive/delegated_impls.md create mode 100644 docs/implementation/functions/parse/is_provider_params.md create mode 100644 docs/implementation/macros/define_keyword.md create mode 100644 docs/implementation/macros/parse_internal.md diff --git a/crates/macros/cgp-macro-core/CLAUDE.md b/crates/macros/cgp-macro-core/CLAUDE.md index fe2d3921..6829d6f5 100644 --- a/crates/macros/cgp-macro-core/CLAUDE.md +++ b/crates/macros/cgp-macro-core/CLAUDE.md @@ -78,3 +78,13 @@ into the existing stage rather than collapsing the pipeline. **5. Custom keywords go through `define_keyword!` + `IsKeyword`** (see [src/macros/keyword.rs](src/macros/keyword.rs) and `types/keyword*.rs`). + +**6. Keep inline docs brief and current as you go.** When you review a file — whether to change it +or to write its [implementation document](../../../docs/implementation/README.md) — improve the +inline docs in the same pass. Add a one-line `///` to any public struct, trait, or function that +lacks one, saying what it is or does (for a pipeline stage, its role in the sequence); prefer naming +the *why* or a corner case over restating the signature. Fix a doc that no longer matches the code, +and clarify genuinely confusing code (for example, why `generic_params_to_path` keeps only type +parameters) with a short comment. Keep them terse: delete a comment that only restates obvious code, +and do not narrate line by line. Deep mechanics belong in the implementation document, not in a wall +of inline prose — link to it rather than duplicating it. diff --git a/crates/macros/cgp-macro-core/src/functions/delegated_impls/provider_trait.rs b/crates/macros/cgp-macro-core/src/functions/delegated_impls/provider_trait.rs index 2f57ea1b..7f854abe 100644 --- a/crates/macros/cgp-macro-core/src/functions/delegated_impls/provider_trait.rs +++ b/crates/macros/cgp-macro-core/src/functions/delegated_impls/provider_trait.rs @@ -3,6 +3,8 @@ use syn::{ImplItem, ItemTrait, Type}; use crate::functions::trait_items_to_delegated_impl_items; use crate::parse_internal; +/// Forward a provider trait's own items to `delegate_type`, reconstructing the +/// trait path from the trait itself (for impls whose trait *is* the provider trait). pub fn provider_trait_to_impl_items( item_trait: &ItemTrait, delegate_type: &Type, diff --git a/crates/macros/cgp-macro-core/src/functions/delegated_impls/trait_items.rs b/crates/macros/cgp-macro-core/src/functions/delegated_impls/trait_items.rs index 811c69c9..d1ebbeb0 100644 --- a/crates/macros/cgp-macro-core/src/functions/delegated_impls/trait_items.rs +++ b/crates/macros/cgp-macro-core/src/functions/delegated_impls/trait_items.rs @@ -7,6 +7,8 @@ use crate::functions::{ parse_internal, signature_to_delegated_impl_item_fn, trait_to_impl_item_type, }; +/// Build impl items that forward each trait item (method, associated type, or +/// const) to `delegate_type`, projecting types/consts through `provider_trait_path`. pub fn trait_items_to_delegated_impl_items( trait_items: &[TraitItem], delegate_type: &Type, diff --git a/crates/macros/cgp-macro-core/src/functions/is_provider_params.rs b/crates/macros/cgp-macro-core/src/functions/is_provider_params.rs index 1eeaaa13..79e93c45 100644 --- a/crates/macros/cgp-macro-core/src/functions/is_provider_params.rs +++ b/crates/macros/cgp-macro-core/src/functions/is_provider_params.rs @@ -6,6 +6,11 @@ use crate::exports::Life; use crate::parse_internal; use crate::types::generics::TypeGenerics; +/// Convert a trait's generics into the `Params` tuple types of an `IsProviderFor` +/// bound: type params pass through, lifetimes are lifted into `Life<'a>`. +/// +/// Panics on a const generic parameter — see the const-generic limitation in +/// docs/implementation/entrypoints/cgp_component.md. pub fn parse_is_provider_params(generics: &Generics) -> syn::Result> { let params = TypeGenerics::try_from(generics)?.generics.params; diff --git a/crates/macros/cgp-macro-core/src/functions/parse_internal.rs b/crates/macros/cgp-macro-core/src/functions/parse_internal.rs index 1583e161..89ec0f22 100644 --- a/crates/macros/cgp-macro-core/src/functions/parse_internal.rs +++ b/crates/macros/cgp-macro-core/src/functions/parse_internal.rs @@ -8,6 +8,9 @@ use syn::{Error, parse2}; use crate::functions::strip_macro_prelude; pub use crate::macros::parse_internal; +/// Parse a token stream into a `syn` type `T`, attaching an error that names both +/// `T` and the offending tokens (prelude prefix stripped) on failure. Usually +/// invoked through the `parse_internal!` macro. pub fn parse_internal(body: TokenStream) -> Result where T: Parse, diff --git a/crates/macros/cgp-macro-core/src/macros/keyword.rs b/crates/macros/cgp-macro-core/src/macros/keyword.rs index a94e4241..da0d5d86 100644 --- a/crates/macros/cgp-macro-core/src/macros/keyword.rs +++ b/crates/macros/cgp-macro-core/src/macros/keyword.rs @@ -1,3 +1,5 @@ +/// Declare a custom-keyword marker: a zero-sized struct plus its `IsKeyword` impl +/// carrying the keyword's spelling, which the parsers peek against. #[macro_export] macro_rules! define_keyword { ( $struct_ident:ident, $value:literal ) => { diff --git a/crates/macros/cgp-macro-core/src/macros/parse.rs b/crates/macros/cgp-macro-core/src/macros/parse.rs index ca65e2b6..265ce5d9 100644 --- a/crates/macros/cgp-macro-core/src/macros/parse.rs +++ b/crates/macros/cgp-macro-core/src/macros/parse.rs @@ -1,3 +1,6 @@ +/// Quasi-quote tokens and parse them into an inferred `syn` type via the +/// `parse_internal` function. Expands to a `?` expression, so it must be called +/// inside a `syn::Result`-returning function. #[macro_export] macro_rules! parse_internal { ( $($body:tt)* ) => { diff --git a/crates/macros/cgp-macro-core/src/types/cgp_component/args/component_args.rs b/crates/macros/cgp-macro-core/src/types/cgp_component/args/component_args.rs index 1d4d2381..6b77e8b8 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_component/args/component_args.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_component/args/component_args.rs @@ -5,6 +5,9 @@ use syn::{Error, Ident}; use crate::types::cgp_component::CgpComponentRawArgs; use crate::types::ident::IdentWithTypeGenerics; +/// The `#[cgp_component]` attribute args with defaults applied: the context type +/// identifier (`__Context__` by default), the required provider trait name, and +/// the component marker name (`{Provider}Component` by default). #[derive(Clone)] pub struct CgpComponentArgs { pub context_ident: Ident, diff --git a/crates/macros/cgp-macro-core/src/types/cgp_component/args/raw.rs b/crates/macros/cgp-macro-core/src/types/cgp_component/args/raw.rs index 29f00589..4f44c9b1 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_component/args/raw.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_component/args/raw.rs @@ -4,6 +4,9 @@ use syn::{Error, Ident}; use crate::types::ident::IdentWithTypeGenerics; +/// The attribute args exactly as written, before defaults are applied. Parses +/// either a bare provider identifier or the `key: value` form; [`CgpComponentArgs`] +/// resolves the defaults via `TryFrom`. #[derive(Default)] pub struct CgpComponentRawArgs { pub context_ident: Option, diff --git a/crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/item.rs b/crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/item.rs index b79c216f..3f0b7692 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/item.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/item.rs @@ -5,6 +5,9 @@ use crate::types::cgp_component::CgpComponentArgs; use crate::types::empty_struct::EmptyStruct; use crate::types::provider_impl::{ItemProviderImpl, ItemProviderImpls}; +/// Final pipeline stage: all derived items, plus the args and attributes needed +/// to render the standard provider impls (`UseContext`, `RedirectLookup`, and the +/// per-attribute `UseDelegate`/prefix impls). pub struct EvaluatedCgpComponent { pub component_struct: EmptyStruct, pub consumer_trait: ItemTrait, @@ -16,6 +19,8 @@ pub struct EvaluatedCgpComponent { } impl EvaluatedCgpComponent { + /// Emit the five core items in fixed order (consumer trait, consumer impl, + /// provider trait, provider impl, marker struct), then the provider impls. pub fn to_items(&self) -> syn::Result> { let mut items = vec![ Item::Trait(self.consumer_trait.clone()), @@ -55,6 +60,7 @@ impl EvaluatedCgpComponent { Ok(provider_impls) } + /// One `UseDelegate` provider impl per `#[derive_delegate]` attribute. pub fn to_use_delegate_impls(&self) -> syn::Result { let provider_trait = &self.provider_trait; let component_type = self.args.component_name.to_type(); @@ -71,6 +77,7 @@ impl EvaluatedCgpComponent { Ok(provider_impls) } + /// One namespace prefix impl per `#[prefix]` attribute (from `#[cgp_namespace]`). pub fn to_prefix_impls(&self) -> syn::Result> { let component_name = &self.args.component_name; let mut provider_impls = Vec::new(); diff --git a/crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs b/crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs index def64433..5050ba0b 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs @@ -8,6 +8,8 @@ use crate::types::path::{PathElement, UniPath}; use crate::types::provider_impl::ItemProviderImpl; impl EvaluatedCgpComponent { + /// Build the `RedirectLookup` provider impl used by namespaces and `open`. A + /// component's type parameters extend the lookup path via `ConcatPath`. pub fn to_redirect_lookup_impl(&self) -> syn::Result { let consumer_trait = &self.consumer_trait; let provider_trait = &self.provider_trait; @@ -76,6 +78,9 @@ impl EvaluatedCgpComponent { } } +/// Collect the component's *type* parameters into a lookup path. Lifetimes and +/// const params are deliberately excluded (only types key the redirect path), +/// so this returns `None` when the component has no type parameters. fn generic_params_to_path(generics: &Generics) -> syn::Result> { let type_params = generics .params diff --git a/crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_use_context_impl.rs b/crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_use_context_impl.rs index 141ea0a9..362952f1 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_use_context_impl.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_use_context_impl.rs @@ -6,6 +6,8 @@ use crate::types::cgp_component::EvaluatedCgpComponent; use crate::types::provider_impl::ItemProviderImpl; impl EvaluatedCgpComponent { + /// Build the `UseContext` provider impl, which satisfies the provider trait by + /// routing back through the context's own consumer-trait impl. pub fn to_use_context_impl(&self) -> syn::Result { let component_name = &self.args.component_name; let context_type_ident = &self.args.context_ident; diff --git a/crates/macros/cgp-macro-core/src/types/cgp_component/item.rs b/crates/macros/cgp-macro-core/src/types/cgp_component/item.rs index b5aad5a5..daeefb0a 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_component/item.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_component/item.rs @@ -3,12 +3,15 @@ use syn::ItemTrait; use crate::types::attributes::CgpComponentAttributes; use crate::types::cgp_component::{CgpComponentArgs, PreprocessedCgpComponent}; +/// Raw input stage: the parsed attribute args and trait, before CGP attributes +/// are stripped. First stage of the `#[cgp_component]` pipeline. pub struct ItemCgpComponent { pub args: CgpComponentArgs, pub item_trait: ItemTrait, } impl ItemCgpComponent { + /// Split the CGP modifier attributes off the trait, yielding the next stage. pub fn preprocess(&self) -> syn::Result { let (attributes, item_trait) = CgpComponentAttributes::preprocess(&self.item_trait)?; diff --git a/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/item.rs b/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/item.rs index ce419b64..8ae22419 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/item.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/item.rs @@ -4,6 +4,9 @@ use crate::types::attributes::CgpComponentAttributes; use crate::types::cgp_component::{CgpComponentArgs, EvaluatedCgpComponent}; use crate::types::empty_struct::EmptyStruct; +/// Pipeline stage after preprocessing: the plain trait plus the CGP modifier +/// attributes, carrying the methods that derive the provider trait, the blanket +/// impls, and the component marker. pub struct PreprocessedCgpComponent { pub args: CgpComponentArgs, pub item_trait: ItemTrait, @@ -11,6 +14,7 @@ pub struct PreprocessedCgpComponent { } impl PreprocessedCgpComponent { + /// Build the zero-sized `{Provider}Component` marker struct. pub fn to_component_struct(&self) -> EmptyStruct { let component_name = &self.args.component_name; EmptyStruct { @@ -19,6 +23,8 @@ impl PreprocessedCgpComponent { } } + /// Derive the marker struct, provider trait, and both blanket impls, yielding + /// the final stage. pub fn eval(&self) -> syn::Result { let component_struct = self.to_component_struct(); diff --git a/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/to_consumer_impl.rs b/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/to_consumer_impl.rs index d5767b9d..00a2f85c 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/to_consumer_impl.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/to_consumer_impl.rs @@ -6,6 +6,8 @@ use crate::types::cgp_component::PreprocessedCgpComponent; use crate::types::generics::TypeGenerics; impl PreprocessedCgpComponent { + /// Build the consumer blanket impl: any context implementing the provider + /// trait for itself gets the consumer trait, forwarding each method to it. pub fn to_consumer_item_impl(&self) -> syn::Result { let consumer_trait = &self.item_trait; let provider_ident = &self.args.provider_ident; diff --git a/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/to_provider_blanket_impl.rs b/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/to_provider_blanket_impl.rs index b94c5724..748afd64 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/to_provider_blanket_impl.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/to_provider_blanket_impl.rs @@ -9,6 +9,9 @@ use crate::functions::{parse_internal, parse_is_provider_params, provider_trait_ use crate::types::cgp_component::PreprocessedCgpComponent; impl PreprocessedCgpComponent { + /// Build the provider trait together with its blanket impl for `__Provider__`, + /// which inherits the provider trait from whatever `DelegateComponent` names. + /// Returns both so they share one construction of the provider trait. pub fn to_provider_trait_and_blanket_impl(&self) -> syn::Result<(ItemTrait, ItemImpl)> { let consumer_trait = &self.item_trait; let context_type = &self.args.context_ident; diff --git a/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/to_provider_trait.rs b/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/to_provider_trait.rs index 60e6230c..28ee7c42 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/to_provider_trait.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/to_provider_trait.rs @@ -10,6 +10,9 @@ use crate::visitors::{ }; impl PreprocessedCgpComponent { + /// Derive the provider trait from the consumer trait: insert the leading + /// `Context` parameter, lower supertraits to a `Context` where-bound, set the + /// `IsProviderFor` supertrait, and rewrite `self`/`Self` to the context. pub fn to_provider_trait(&self) -> syn::Result { let component_name = &self.args.component_name; let provider_name = &self.args.provider_ident; diff --git a/crates/macros/cgp-macro-lib/src/cgp_component.rs b/crates/macros/cgp-macro-lib/src/cgp_component.rs index 4fa1e5e7..17b327df 100644 --- a/crates/macros/cgp-macro-lib/src/cgp_component.rs +++ b/crates/macros/cgp-macro-lib/src/cgp_component.rs @@ -3,6 +3,8 @@ use proc_macro2::TokenStream; use quote::quote; use syn::ItemTrait; +/// `#[cgp_component]` entry point: parse the attribute args and the trait, then +/// run the `preprocess → eval → to_items` pipeline and emit the derived items. pub fn cgp_component(attr: TokenStream, item: TokenStream) -> syn::Result { let args: CgpComponentArgs = syn::parse2(attr)?; let item_trait: ItemTrait = syn::parse2(item)?; diff --git a/crates/tests/CLAUDE.md b/crates/tests/CLAUDE.md index 2f417ee3..2098f79e 100644 --- a/crates/tests/CLAUDE.md +++ b/crates/tests/CLAUDE.md @@ -66,10 +66,13 @@ that test exercises. ## Explain what each test covers Open every test file with a brief comment stating **what behavior it exercises**, -and annotate individual tricky cases inline. Where it helps a reader, link to the -owning reference document (for example `// see docs/reference/macros/cgp_impl.md`). -Tests link **to** the documentation; the documentation never links back to a test -(per `docs/CLAUDE.md`). +and annotate individual tricky cases inline. Link to the owning **implementation +document** — the one under `docs/implementation/` whose Tests and Snapshots +sections index this test (for example `// see docs/implementation/entrypoints/cgp_impl.md`); +that document is where test pointers live, since a reference document never links +to a test (per `docs/CLAUDE.md`). You may additionally link to a reference +document when a reader needs the user-facing semantics. Tests link **to** the +documentation; the reference documents never link back to a test. ## Use macro snapshots sparingly @@ -117,19 +120,27 @@ failure-case target: would not), and add a code comment explaining **why** the output is wrong and **what the correct output should be**. -Every failure case must also be recorded in the reference document that owns the -construct, under its `## Known issues` section (the heading `docs/CLAUDE.md` -mandates), describing the behavior without referring to the test. Put a link from -the test's comment to that reference document. +Every failure case must also be recorded in the construct's **implementation +document** under `docs/implementation/`, in its `## Known issues` section and +indexed from its `## Tests` section, describing the behavior without referring to +the test. When the failure has a user-visible consequence, note that in the +reference document's `## Known issues` section too and cross-link the two. Put a +link from the test's comment to the implementation document. ## Keep the docs in sync -This suite is one of the four views of CGP's truth, alongside the macro -implementation in `cgp-macro-core`, the reference documents in `docs/reference`, and -the `/cgp` skill (see `docs/CLAUDE.md`). When a test reveals or pins a behavior -worth documenting, update the reference document to explain that behavior directly — -without referring to the test. When you move a test that a reference document's -`## Source` section links to, update the link in the same change. +This suite is one of the views of CGP's truth, alongside the macro implementation +in `cgp-macro-core`, the reference documents in `docs/reference`, the +implementation documents in `docs/implementation`, and the `/cgp` skill (see +`docs/CLAUDE.md`). The implementation documents are the ones tightly coupled to +this suite: each macro's implementation document has a `## Tests` section linking +every behavioral test and failure case that exercises it, and every entrypoint +document a `## Snapshots` section indexing the expansion snapshots and calling out +which variants are still missing. When a test reveals or pins a behavior worth +documenting, update the implementation document to explain that behavior directly — +and the reference document when the behavior is user-facing — without referring to +the test. When you add, move, or rename a test, update the implementation +document's Tests or Snapshots section in the same change. ## Running the suite diff --git a/crates/tests/cgp-macro-tests/tests/parser_rejections/cgp_component.rs b/crates/tests/cgp-macro-tests/tests/parser_rejections/cgp_component.rs index 84d83f07..d7f8665b 100644 --- a/crates/tests/cgp-macro-tests/tests/parser_rejections/cgp_component.rs +++ b/crates/tests/cgp-macro-tests/tests/parser_rejections/cgp_component.rs @@ -1,7 +1,8 @@ //! `#[cgp_component]` must be applied to a trait; applying it to another item //! is rejected at parse time. //! -//! See docs/reference/macros/cgp_component.md. +//! See docs/implementation/entrypoints/cgp_component.md (Tests) for this failure +//! case, and docs/reference/macros/cgp_component.md for the user-facing semantics. use quote::quote; diff --git a/crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs b/crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs index 54f98ef4..3e1a9612 100644 --- a/crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs +++ b/crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs @@ -7,7 +7,9 @@ //! This is the reference snapshot for that expansion; other concepts reuse //! `#[cgp_component]` without re-snapshotting it. //! -//! See docs/reference/macros/cgp_component.md. +//! See docs/implementation/entrypoints/cgp_component.md (Snapshots) for the index +//! of `#[cgp_component]` expansion snapshots, and docs/reference/macros/cgp_component.md +//! for the user-facing expansion. use cgp_macro_test_util::snapshot_cgp_component; diff --git a/crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs b/crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs index a6511957..cf1c0def 100644 --- a/crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs +++ b/crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs @@ -5,8 +5,9 @@ //! the distinct component-expansion variant with a supertrait bound and a default //! method, kept alongside the plain snapshot in `component_macro`. //! -//! See docs/reference/macros/cgp_component.md and -//! docs/reference/attributes/extend.md. +//! See docs/implementation/entrypoints/cgp_component.md (Snapshots) for this +//! supertrait-plus-default-method variant, and docs/reference/macros/cgp_component.md +//! and docs/reference/attributes/extend.md for the user-facing semantics. use cgp::prelude::*; use cgp_macro_test_util::snapshot_cgp_component; diff --git a/crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs b/crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs index ed58a455..3776582a 100644 --- a/crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs +++ b/crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs @@ -9,7 +9,9 @@ //! `delegate_components!`, and `check_components!` wiring below is written plainly //! (its expansion is owned by the `basic_delegation` and `checking` concepts). //! -//! See docs/reference/macros/cgp_component.md and docs/reference/types/life.md. +//! See docs/implementation/entrypoints/cgp_component.md (Snapshots) for this +//! lifetime-and-type-parameter variant, and docs/reference/macros/cgp_component.md +//! and docs/reference/types/life.md for the user-facing semantics. use cgp::prelude::*; use cgp_macro_test_util::{snapshot_cgp_component, snapshot_cgp_provider}; diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md index 714573c7..fc72349a 100644 --- a/docs/CLAUDE.md +++ b/docs/CLAUDE.md @@ -10,7 +10,7 @@ This directory is the CGP knowledge base — agent-maintained documentation whos This rule applies in both directions. If you add a new construct, add its reference document and register it in the [reference index](reference/README.md). If you remove a construct, remove or supersede its document and update the index. If you change a construct's expansion, revise the "Expansion" section of its document so the desugaring shown still matches what the macro emits. -The implementation in [crates/macros/cgp-macro-core](../crates/macros/cgp-macro-core), the expansion snapshots in [crates/tests/cgp-macro-tests](../crates/tests/cgp-macro-tests), the reference documents here, and the agent skill under [skills/](skills/README.md) are four views of the same truth. When they disagree, that disagreement is a defect. The snapshots are the most mechanical check on whether a document's "Expansion" section is honest — when you doubt what a macro emits, generate or read the snapshot rather than guessing. The skill is the most distilled view, so a change to a construct's behavior must propagate all the way out to it; see [the skills directory](#the-skills-directory) for how to keep it in sync. +The implementation in [crates/macros/cgp-macro-core](../crates/macros/cgp-macro-core), the expansion snapshots in [crates/tests/cgp-macro-tests](../crates/tests/cgp-macro-tests), the reference documents here, the implementation documents under [implementation/](implementation/README.md), and the agent skill under [skills/](skills/README.md) are views of the same truth. When they disagree, that disagreement is a defect. The snapshots are the most mechanical check on whether a document's "Expansion" section is honest — when you doubt what a macro emits, generate or read the snapshot rather than guessing. The skill is the most distilled view, so a change to a construct's behavior must propagate all the way out to it; see [the skills directory](#the-skills-directory) for how to keep it in sync. ## Authoring conventions @@ -46,6 +46,12 @@ Two constraints are unique to the skill because it is deployed on its own, copie Verify the skill against the source the same way you verify a reference document: every snippet must reflect current v0.7.0 syntax, and when you doubt a form, compile a representative snippet against the crates (a scratch test under [crates/tests/cgp-tests](../crates/tests/cgp-tests) is the quickest check) rather than trusting memory or an older draft. The skill ships with an eval set under `skills/cgp/evals/` and a workspace of benchmark runs; when a change alters what good CGP code looks like, re-run or extend the evals so the skill's quality stays measured rather than assumed. +## The implementation directory + +The [implementation/](implementation/README.md) directory documents the *internals* of the CGP macros — how each macro is built, as opposed to what it does for a user. It is the counterpart to this reference: where a reference document explains a construct's syntax and expansion and points only at library source, an implementation document explains the macro's pipeline, the AST types it parses into, the functions that synthesize each generated item, its corner-case handling, and its known limitations, and it is the sole home for every pointer into the [test suite](../crates/tests). An agent asked to review, debug, or extend the macro source reads the implementation document first. The tree is organized into `entrypoints/` (one document per user-facing macro), `asts/` (the `cgp-macro-core` types that implement `Parse`/`ToTokens`, grouped by evaluation stack), `functions/` (standalone helpers, split into `parse/` and `derive/`), and `macros/` (internal `macro_rules!` such as `parse_internal!`). Its own [implementation/CLAUDE.md](implementation/CLAUDE.md) carries the authoring rules and document templates for that tree, and [implementation/README.md](implementation/README.md) is the catalog you register a new implementation document in. + +The two trees are bound together and must not drift or duplicate. When you change a macro, update both views in the same change: the reference document's Expansion for the user-facing contract, and the implementation document's Pipeline and Generated items for the mechanics. Every reference document's Source section links to its implementation counterpart, and the implementation document links back to the reference for the user-facing semantics rather than re-deriving them; corner-case behavior a reference document does not want to explain in full is elaborated in the implementation document instead. Because all test and snapshot pointers now live under `implementation/`, moving or renaming a test updates the implementation document's Tests or Snapshots section, never a reference document. + ## Document structure Each reference document follows the same shape so readers can navigate any of them by habit. Open with a level-one heading naming the construct and a one-sentence summary of what it is. Then proceed through these sections, using the same headings: @@ -57,7 +63,7 @@ Each reference document follows the same shape so readers can navigate any of th - **Examples** — at least one realistic, self-contained example showing the construct in use. - **Related constructs** — links to the reference documents for constructs commonly used with this one, with a phrase explaining each relationship. - **Known issues** — optional; present only when the construct has corner cases, surprising behavior, or open bugs worth warning a reader about. Omit the heading entirely when there is nothing to record. See the review workflow below for what belongs here. -- **Source** — pointers to the implementing modules in `cgp-macro-core` and the relevant tests, so a reader can drop from prose into code. +- **Source** — pointers to the implementing modules in `cgp-macro-core` and `cgp-macro-lib`, and a link to the construct's implementation document under [implementation/](implementation/README.md), so a reader can drop from prose into the code and its internal walkthrough. A reference document never points at a test file; all test pointers live in the implementation document instead. Place each document in the subdirectory that matches what the construct is. The reference is organized into `macros/` (procedural macros a programmer invokes, including the type-level construction macros), `derives/` (the `#[derive(...)]` family), `attributes/` (modifier attributes consumed by a host macro), `components/` (the built-in CGP components — consumer/provider trait pairs defined with `#[cgp_component]`/`#[cgp_type]`/`#[cgp_getter]`), `providers/` (the zero-sized provider structs a context delegates to), `traits/` (capability and mechanism traits that are *not* themselves components), and `types/` (the type-level building-block types). A trait belongs in `components/` rather than `traits/` precisely when it is a CGP component with a generated provider trait and `…Component` marker. The high-level conceptual overviews that tie several constructs together are not per-construct reference documents; they live in the sibling top-level [concepts/](concepts/) directory and are cataloged in the [concepts index](concepts/README.md). The [reference index](reference/README.md) describes the reference layout in full and is the catalog you register a new reference document in. Because documents live in different subdirectories, a cross-link between two of them is a relative path — a sibling in the same directory is `name.md`, and a document in another directory is `../that-dir/name.md`. @@ -82,7 +88,7 @@ Reviewing a document means checking it against the code and then improving it, n The source code is the single source of truth, above the skill and above the documents themselves. When the document, the `/cgp` skill, and the implementation disagree, the implementation wins every time: correct the document to match the code, and do not let the skill's teaching examples or the document's prior wording override what the macro actually does. The skill is a teaching aid whose simplified examples can lag the parser, so confirm any contested detail — an accepted syntax form, a default name, the shape of an expansion — directly against `cgp-macro-core`. Treat such a conflict as a defect in whichever artifact disagrees with the code, and prefer fixing the document you are reviewing. -Verify specific behavior against the tests and the macro snapshots, then state the behavior in your own words without citing the test. The behavioral tests in [crates/tests/cgp-tests](../crates/tests/cgp-tests) and the expansion snapshots in [crates/tests/cgp-macro-tests](../crates/tests/cgp-macro-tests) are the most reliable evidence of what a macro does in a corner case — read them to confirm how a construct behaves, what it generates, and where it errors. The document, however, explains the behavior itself, not the test: write "a tuple struct keys its fields by `Index`," never "the test `tuple_struct.rs` shows that…". A reader of the reference should learn the semantics directly; the test is your evidence, not theirs, and pointers into test files belong only in the Source section. +Verify specific behavior against the tests and the macro snapshots, then state the behavior in your own words without citing the test. The behavioral tests in [crates/tests/cgp-tests](../crates/tests/cgp-tests) and the expansion snapshots in [crates/tests/cgp-macro-tests](../crates/tests/cgp-macro-tests) are the most reliable evidence of what a macro does in a corner case — read them to confirm how a construct behaves, what it generates, and where it errors. The document, however, explains the behavior itself, not the test: write "a tuple struct keys its fields by `Index`," never "the test `tuple_struct.rs` shows that…". A reader of the reference should learn the semantics directly; the test is your evidence, not theirs. A reference document does not link to test files at all — the pointers into `crates/tests` (behavioral tests, failure cases, and expansion snapshots) belong in the construct's [implementation document](implementation/README.md), whose Tests and Snapshots sections are the canonical index of coverage. Link the reference's Source section to that implementation document rather than to any test. Record corner cases and confirmed bugs under the document's **Known issues** section. When a review uncovers behavior that is surprising, a sharp edge a user could trip on, or an outright bug in the construct, add a short prose note there describing what happens and, for a bug, what the correct behavior would be. Add the heading if the document does not yet have one, and place it just before Source. A known issue is documentation of reality, so describe the behavior as it currently is even when it is wrong — and when the bug is later fixed in the code, remove the note in the same change, per the synchronization rule. diff --git a/docs/implementation/CLAUDE.md b/docs/implementation/CLAUDE.md new file mode 100644 index 00000000..15e32f2e --- /dev/null +++ b/docs/implementation/CLAUDE.md @@ -0,0 +1,57 @@ +# CLAUDE.md — the CGP implementation documentation + +This directory documents the *internals* of the CGP macros — how each macro is implemented, not how a programmer uses it. Read [README.md](README.md) for the catalog and the map of what lives where. The rules below govern how to keep these documents correct and useful, and they assume you have already read the knowledge-base-wide rules in [../CLAUDE.md](../CLAUDE.md); this file adds the rules specific to the implementation tree. + +Invoke the `/cgp` skill before writing or revising any document here, exactly as the reference documents require, and write in the dual-reader prose style (the `/dual-reader-prose` skill). An implementation document is read both by an agent scanning for one detail of a parser and by an agent reading a macro's pipeline start to finish, so every section opens with a self-contained topic sentence and frames any list with a sentence before and after. + +## What these documents are for + +The implementation documents are the working notes an agent needs to review, debug, or extend the CGP macro source, written so that an agent can pick up a construct's implementation from exactly where the last one left off. Where a [reference document](../reference/README.md) explains what a construct *does* for a user — its accepted syntax and the code it expands to — an implementation document explains how the macro *produces* that behavior: the AST types it parses into, the pipeline stages it moves through, the functions that synthesize each generated item, the corner cases the code handles or mishandles, and the known limitations and bugs. When an agent is asked to fix a macro, this is the document it should open first, because it records the current state of the code in one place rather than making the agent reconstruct it from the source. + +These documents are the home for everything about the *test suite* that the reference documents deliberately exclude. A reference document points only at library source and never at a test; every pointer into [crates/tests](../../crates/tests) — behavioral tests, failure cases, and macro-expansion snapshots — lives here instead, in the Tests and Snapshots sections described below. This split keeps the reference focused on user-facing semantics while making the implementation documents the single index an agent consults to learn what is tested, what is pinned by a snapshot, and what coverage is still missing. + +## The synchronization rule applies here too + +An implementation document must stay in sync with the code, and keeping it in sync is part of the change, not a follow-up. The source in [crates/macros/cgp-macro-core](../../crates/macros/cgp-macro-core) and [crates/macros/cgp-macro-lib](../../crates/macros/cgp-macro-lib) is the single source of truth, above both this document and the reference. When you change a parser, a pipeline stage, the set of generated items, or an error path, revise the matching implementation document in the same change; when you add or remove a test or a snapshot, update the Tests or Snapshots section that indexes it. A document that describes a pipeline the code no longer has is worse than no document, because the next agent will trust it. Verify every claim against the source before writing it — read the `types//` modules, the `functions/` helpers, and the tests — rather than transcribing the reference or working from memory. + +Document the present, not the history, following [../CLAUDE.md](../CLAUDE.md): describe how the code works now, record current limitations under Known issues, and delete superseded wording outright rather than leaving "previously" or "renamed from" traces. + +Improving the code's inline docs is part of writing an implementation document, not a separate task. Reading a macro's source closely enough to document it is exactly when to fix its inline docs, so in the same pass add a brief `///` to any public struct, trait, or function that lacks one, correct a comment that no longer matches the code, clarify genuinely confusing code, and delete comments that only restate the obvious — the convention recorded in [cgp-macro-core/CLAUDE.md](../../crates/macros/cgp-macro-core/CLAUDE.md). Keep the inline docs terse and leave the deep mechanics to the implementation document; a one-line inline doc that links out to the document beats a paragraph inlined in the source. + +## Directory layout + +The tree is organized by *what kind of source construct* a document describes, so an agent looking for "the macro entry point", "the AST type behind a stage", "a shared helper function", or "an internal `macro_rules!`" each has an obvious place to start. Every document registers itself in [README.md](README.md) in the same change that creates it. + +The [entrypoints/](entrypoints/) directory holds one document per CGP macro — the top-level procedural macro a programmer invokes. Each names the `cgp-macro-lib` entry function, walks the transform pipeline it drives, enumerates the items the macro emits and the function that produces each, and records the macro's corner cases, known issues, tests, and snapshots. This is the document an agent maintaining a specific macro opens first. + +The [asts/](asts/) directory holds one document per *evaluation stack* of AST constructs — the types in `cgp-macro-core` that implement `syn::parse::Parse` or `quote::ToTokens`, or that serve as an intermediate representation between the two. Multiple AST types that belong to the same stack share one document: the `cgp_component` stack, for example, documents `ItemCgpComponent`, `PreprocessedCgpComponent`, and `EvaluatedCgpComponent` together, along with the argument types they parse from, because they are stages of one pipeline and are only understood as a sequence. + +The [functions/](functions/) directory holds the standalone helper functions that are not organized as AST types — the free functions in `cgp-macro-core/src/functions`. It is split into subdirectories by what the functions do: [functions/parse/](functions/parse/) groups the parsing helpers (functions that consume tokens or a `syn` node into a more specific form), and [functions/derive/](functions/derive/) groups the derivation helpers (functions that synthesize generated `syn` items from a parsed construct). Add a further subdirectory when a distinct family of helpers grows large enough — case conversion or generics merging, for instance — rather than letting one directory sprawl. + +The [macros/](macros/) directory holds the internal `macro_rules!` macros that the CGP macro implementation itself relies on — `parse_internal!`, `define_keyword!`, the `export_construct(s)!` family — as opposed to the user-facing procedural macros documented under `entrypoints/`. These are the building blocks the codegen is written in, and a document here explains what the macro expands to and how the rest of the implementation uses it. + +Because documents live in different subdirectories, a cross-link between two of them is a relative path — a sibling is `name.md`, and a document in another directory is `../that-dir/name.md`. Link generously between an entrypoint and the AST stack, functions, and internal macros it uses, so an agent can follow a macro from its entry function down into every helper it calls. + +## Document structure + +Each kind of document follows a shape so an agent can navigate any of them by habit. All kinds share the same opening — a level-one heading naming the construct and a one-sentence summary — and the same closing pair of a **Tests** section and a **Source** section. The middle sections differ by kind. + +An **entrypoint document** (`entrypoints/.md`) proceeds through: **Entry point** — the `cgp-macro-lib` function, what it parses the attribute and item into, and the pipeline call it drives; **Pipeline** — each stage in order (for `cgp_component`, `preprocess → eval → to_items`), what AST type it produces, and a link to the [asts/](asts/) document that owns those types; **Generated items** — the exact list of items the macro emits, in emission order, each with the function in `cgp-macro-core` that synthesizes it, so this reads as the internal companion to the reference document's Expansion section; **Behavior and corner cases** — how the implementation handles supertraits, default methods, generic parameters, lifetimes, reserved identifiers, and any input the macro treats specially; **Known issues** — limitations and bugs, following the rule below; then **Snapshots**, **Tests**, and **Source**. + +An **AST document** (`asts/.md`) opens with a short overview of the stack as a pipeline, then gives one section per AST type in the order the data flows through them. Each section states the type's role, lists its fields, describes its `Parse` impl (what token grammar it accepts) and/or its `ToTokens` impl (what it emits) and any transform methods it carries, and links to the entrypoint document that drives the stack. It then closes with **Tests** and **Source**. + +A **function document** (`functions//.md`) opens with what the group of functions is for, gives one section per public function stating its signature intent, what it consumes and produces, and its corner cases, and closes with **Tests** and **Source**. A **macro document** (`macros/.md`) describes what the internal `macro_rules!` expands to, how the implementation is expected to call it (for `parse_internal!`, that it expands to a `?` expression and must be called in a `syn::Result`-returning function), and closes with **Tests** and **Source**. + +## The Tests and Snapshots sections + +Every document links its related tests in a **Tests** section, stating the behavior each test pins in the document's own words. List the behavioral tests in [crates/tests/cgp-tests](../../crates/tests/cgp-tests) and the failure cases in [crates/tests/cgp-macro-tests](../../crates/tests/cgp-macro-tests) that exercise the construct, each as a link to the file with a one-line description of what it verifies. Because the reference documents no longer point at tests, this section is the canonical index of a construct's coverage — write it so an agent can see at a glance what behavior is guarded and, by omission, what is not. + +Every entrypoint document additionally carries a **Snapshots** section that indexes the macro-expansion snapshots for that macro and calls out which variants are missing. Macro snapshots are pinned by the `snapshot_*!` macros in [crates/macros/cgp-macro-test-util](../../crates/macros/cgp-macro-test-util) and, per [crates/tests/CLAUDE.md](../../crates/tests/CLAUDE.md), each macro's canonical full-expansion snapshot plus its genuinely distinct variants live only in the concept target that owns the macro's feature. The Snapshots section is the central place to find them: link each snapshot file, describe which expansion variant it captures (the plain case, a supertrait-and-default-method case, a lifetime-and-type-parameter case, a namespace-prefix case, and so on), and then state plainly which variants have *no* snapshot yet, so a gap in coverage is visible rather than silently absent. When you add a snapshot, register it here; when a variant you know matters is untested, record it as a missing snapshot rather than leaving the section to imply full coverage. + +## Known issues + +Record limitations, surprising behavior, and confirmed bugs in the implementation under a **Known issues** section, following the same rule as the reference documents in [../CLAUDE.md](../CLAUDE.md): describe the behavior as it currently is even when it is wrong, say what the correct behavior would be for a bug, and remove the note in the same change that fixes the code. An implementation document is the right home for a limitation that is about *how the macro is built* — a parser that panics on an input it should reject with a `syn::Error`, a generic-parameter shape the codegen does not yet handle, a stage that drops information — while the reference document's Known issues covers the user-visible consequence. When both exist, cross-link them rather than duplicating the explanation. A failure case captured in `cgp-macro-tests` (per [crates/tests/CLAUDE.md](../../crates/tests/CLAUDE.md)) should be indexed from the relevant Known issue here and from its Tests section. + +## Keeping the reference and implementation documents aligned + +The reference and implementation documents are two views of the same macro and must not drift apart or duplicate each other. The reference owns the user-facing contract — syntax, the expansion shown as before/after Rust, and user-visible corner cases — and points only at library source. The implementation document owns the internal mechanics — the pipeline, the synthesizing functions, the AST types, and all test and snapshot pointers. A reference document may link to an implementation document to elaborate a corner case it does not want to explain in full, and every reference document's Source section links to its implementation counterpart so an agent can drop from "what it does" into "how it is built"; the implementation document links back to the reference for the user-facing semantics rather than re-deriving them. When you change a macro, update both views in the same change: the reference Expansion for the contract, and the implementation Pipeline and Generated items for the mechanics. diff --git a/docs/implementation/README.md b/docs/implementation/README.md new file mode 100644 index 00000000..928d74d6 --- /dev/null +++ b/docs/implementation/README.md @@ -0,0 +1,49 @@ +# CGP Implementation Reference + +This directory documents the *internals* of the CGP macros — how each macro is implemented in [crates/macros/cgp-macro-core](../../crates/macros/cgp-macro-core) and [crates/macros/cgp-macro-lib](../../crates/macros/cgp-macro-lib), including corner-case behavior, known limitations and bugs, and the test suite that exercises each construct. It is the documentation an agent reviewing or maintaining the macro source reads first: it records the current state of the code in one place so an agent can pick up a construct's implementation from where the last one left off. The authoring rules, document templates, and the synchronization rule that binds these documents to the code live in [CLAUDE.md](CLAUDE.md). + +These documents complement the [construct reference](../reference/README.md) rather than repeating it. The reference explains what each construct does for a *user* — its accepted syntax and the code it expands to — and points only at library source. The implementation documents explain how the macro *produces* that behavior, and they are the sole home for every pointer into the [test suite](../../crates/tests): behavioral tests, failure cases, and macro-expansion snapshots all index from here. A reference document links to its implementation counterpart to elaborate a corner case; an implementation document links back to the reference for the user-facing semantics. + +## Directory layout + +The tree is organized by the kind of source construct each document describes, so an agent has an obvious place to start for "the macro entry point", "the AST type behind a stage", "a helper function", or "an internal macro". A new document goes in the matching subdirectory and registers itself in the catalog below in the same change. + +The [entrypoints/](entrypoints/) directory holds one document per CGP macro — the top-level procedural macro a programmer invokes — describing its `cgp-macro-lib` entry function, the transform pipeline it drives, the items it emits, its corner cases, known issues, tests, and snapshots. The [asts/](asts/) directory holds one document per evaluation stack of AST constructs — the `cgp-macro-core` types implementing `Parse` or `ToTokens`, or serving as an intermediate representation — with the types of one pipeline grouped into a single document. The [functions/](functions/) directory holds the standalone helper functions, split into [functions/parse/](functions/parse/) for parsing helpers and [functions/derive/](functions/derive/) for code-synthesis helpers. The [macros/](macros/) directory holds the internal `macro_rules!` macros the implementation is written in, such as `parse_internal!` and `define_keyword!`. + +## Catalog + +The catalog is the index of implementation documents. The build-out is proceeding one construct at a time; this section registers what is documented and lists what is still pending, so the next agent can see both the shape of the finished tree and where to continue. When you add a document, move its entry from the pending list to the documented list in the same change. + +### Entrypoints — [entrypoints/](entrypoints/) + +Documented so far: + +- [`#[cgp_component]`](entrypoints/cgp_component.md) — the foundational component-definition macro and its `preprocess → eval → to_items` pipeline. + +Pending, one document each — the remaining `cgp-macro-lib` macros (`#[cgp_impl]`, `#[cgp_provider]`, `#[cgp_new_provider]`, `#[cgp_fn]`, `#[cgp_type]`, `#[cgp_getter]`, `#[cgp_auto_getter]`, `#[blanket_trait]`, `delegate_components!`, `check_components!`, `delegate_and_check_components!`, `#[cgp_namespace]`, `Symbol!`, `Product!`, `Sum!`, `Path!`, and the data derives `#[derive(HasField)]`, `HasFields`, `CgpData`, `CgpRecord`, `CgpVariant`, `BuildField`, `ExtractField`, `FromVariant`), the `cgp-extra-macro-lib` macros (`#[cgp_computer]`, `#[cgp_producer]`, `#[cgp_auto_dispatch]`), `#[async_trait]` from `cgp-async-macro`, and the `snapshot_*!` family from [cgp-macro-test-util](../../crates/macros/cgp-macro-test-util). + +### AST stacks — [asts/](asts/) + +Documented so far: + +- [The `cgp_component` AST stack](asts/cgp_component.md) — `CgpComponentArgs`, `ItemCgpComponent`, `PreprocessedCgpComponent`, and `EvaluatedCgpComponent`. + +Pending — one document per remaining evaluation stack, grouped by the macro that owns it: the `cgp_impl`, `cgp_provider`, `cgp_fn`, `cgp_type`, `cgp_getter`, `delegate_component`, `check_components`, `namespace`, `cgp_data`, `product`, and `sum` stacks, plus the shared building-block AST types (`attributes/`, `generics/`, `field/`, `getter/`, `implicits/`, `ident/`, `path/`, `keyword`). + +### Functions — [functions/](functions/) + +Documented so far: + +- [Delegated-impl synthesis](functions/derive/delegated_impls.md) — `trait_items_to_delegated_impl_items` and `provider_trait_to_impl_items`, the forwarding-impl machinery. +- [`parse_is_provider_params`](functions/parse/is_provider_params.md) — building the `IsProviderFor` params tuple from trait generics. + +Pending — the remaining helpers in `cgp-macro-core/src/functions`: identifier case conversion (`camel_case`/`snake_case`), generics merging, field/getter/implicit-argument parsing, and `strip`. + +### Internal macros — [macros/](macros/) + +Documented so far: + +- [`parse_internal!`](macros/parse_internal.md) — build a `syn` node from quoted tokens with a descriptive parse error. +- [`define_keyword!`](macros/define_keyword.md) — declare a custom-keyword marker type implementing `IsKeyword`. + +Pending — the `export_construct(s)!` family in `cgp-macro-core/src/macros` that backs the hygienic `exports.rs` markers. diff --git a/docs/implementation/asts/cgp_component.md b/docs/implementation/asts/cgp_component.md new file mode 100644 index 00000000..4f6e3781 --- /dev/null +++ b/docs/implementation/asts/cgp_component.md @@ -0,0 +1,39 @@ +# The `cgp_component` AST stack + +The `cgp_component` stack is the sequence of AST types that `#[cgp_component]` parses into and transforms through — the argument types, then the three pipeline stages `ItemCgpComponent`, `PreprocessedCgpComponent`, and `EvaluatedCgpComponent`. Each stage is a plain struct holding the data the next stage needs, and each transform is a method on one stage returning the next. This document describes the types; the [entrypoint document](../entrypoints/cgp_component.md) describes how the macro drives them, and the [reference document](../../reference/macros/cgp_component.md) describes the user-facing result. + +The stack flows in one direction: `CgpComponentArgs` and a `syn::ItemTrait` combine into `ItemCgpComponent`, which `preprocess`es into `PreprocessedCgpComponent`, which `eval`s into `EvaluatedCgpComponent`, which finally `to_items` renders into a `Vec`. Only the argument types implement `Parse`; the stage types are constructed programmatically and carry the transform methods rather than a `ToTokens` impl. + +## `CgpComponentRawArgs` and `CgpComponentArgs` + +`CgpComponentArgs` is the parsed, defaulted form of the attribute argument, and `CgpComponentRawArgs` is the intermediate that captures exactly what the user wrote before defaults are applied. The split exists so parsing and defaulting are separate concerns: `CgpComponentRawArgs` holds three `Option`s (`context_ident`, `provider_ident`, `component_name`), and `CgpComponentArgs` holds the same three fields resolved to concrete values. + +`CgpComponentRawArgs::parse` (in `args/raw.rs`) accepts the two attribute forms. When the input is a single token followed by end-of-input (`peek2(End)`), it is the bare-identifier form and that token is the `provider_ident`. Otherwise it parses a comma-separated sequence of `key: value` pairs, matching the key string against `name`, `context`, and `provider`, rejecting a duplicate key with "duplicate key is not allowed" and an unknown key with "unknown key {key}". The `name` value parses as an [`IdentWithTypeGenerics`](../asts/cgp_component.md) so a component name may carry generic parameters, while `context` and `provider` parse as bare `Ident`s. + +`CgpComponentArgs` is produced from the raw form through `TryFrom` (in `args/component_args.rs`), which applies the defaults the reference documents describe: `provider_ident` is required and errors with "`provider_ident` key must be given" when absent, `context_ident` defaults to `Ident::new("__Context__", …)`, and `component_name` defaults to the provider identifier with a `Component` suffix. `CgpComponentArgs` implements `Parse` by parsing a `CgpComponentRawArgs` and delegating to this `TryFrom`, so the entry function can `syn::parse2` the attribute directly into the defaulted form. + +## `ItemCgpComponent` + +`ItemCgpComponent` is the raw input stage — the parsed attribute and the parsed trait, before any CGP attributes are stripped. It holds `args: CgpComponentArgs` and `item_trait: syn::ItemTrait`, and the entry function constructs it directly from the two `syn::parse2` results. + +Its one method, `preprocess`, calls `CgpComponentAttributes::preprocess` on the trait to split the CGP modifier attributes off the plain trait, then returns a `PreprocessedCgpComponent` carrying the cloned args, the cleaned trait, and the parsed attributes. It generates no code; it only normalizes the trait so later stages see a plain `syn::ItemTrait` and a separate, structured record of the attributes that modify the output. + +## `PreprocessedCgpComponent` + +`PreprocessedCgpComponent` is the stage that owns the core derivation. It holds `args`, the preprocessed `item_trait`, and `attributes: CgpComponentAttributes`, and it carries the methods that build the provider trait, the two blanket impls, and the component struct. + +Its `eval` method orchestrates the derivation: it calls `to_component_struct` for the `EmptyStruct` marker, `to_provider_trait_and_blanket_impl` for the provider trait paired with its blanket impl, and `to_consumer_item_impl` for the consumer blanket impl, then packages all of these with the original consumer trait, the attributes, and the args into an `EvaluatedCgpComponent`. The individual builders are `to_provider_trait` (the provider trait, with `self`/`Self` rewritten and supertraits lowered to context `where` predicates), `to_provider_trait_and_blanket_impl` (which reuses `to_provider_trait` and adds the `__Provider__` blanket impl), `to_consumer_item_impl` (the `__Context__` consumer impl), and `to_component_struct` (the marker). The [entrypoint document's Generated items section](../entrypoints/cgp_component.md) describes precisely what each builder emits; the key structural point is that the provider trait is built once and shared, so the trait and its blanket impl cannot disagree. + +## `EvaluatedCgpComponent` + +`EvaluatedCgpComponent` is the final stage — a bag of all the derived items plus the context needed to render the standard provider impls. Its fields are the `component_struct` (an `EmptyStruct`), the `consumer_trait`, `consumer_impl`, `provider_trait`, and `provider_impl`, plus the `args` and `attributes` carried through for the provider-impl builders. + +Its `to_items` method fixes the emission order — consumer trait, consumer impl, provider trait, provider impl, component struct — then appends the provider impls from `to_item_impls`. `to_item_impls` gathers the provider impls (`to_provider_impls`) and the prefix impls (`to_prefix_impls`). `to_provider_impls` always emits the `UseContext` impl (`to_use_context_impl`) and the `RedirectLookup` impl (`to_redirect_lookup_impl`), then one `UseDelegate` impl per `#[derive_delegate]` attribute (`to_use_delegate_impls`); `to_prefix_impls` emits one namespace impl per `#[prefix]` attribute. The provider impls are collected as `ItemProviderImpl`s (each pairing the impl with its component type) and rendered through `ItemProviderImpls::to_item_impls`. + +## Tests + +The argument parser's rejection of a non-trait item is pinned in [cgp-macro-tests/tests/parser_rejections/cgp_component.rs](../../../crates/tests/cgp-macro-tests/tests/parser_rejections/cgp_component.rs). The stage transforms are exercised end-to-end through the expansion snapshots indexed in the [entrypoint document's Snapshots section](../entrypoints/cgp_component.md) — the plain, supertrait/default-method, lifetime, and namespace variants each pin the output of the full `preprocess → eval → to_items` sequence. + +## Source + +The stack lives in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/): the argument types in `args/`, `ItemCgpComponent` in `item.rs`, `PreprocessedCgpComponent` and its builders in `preprocessed/`, and `EvaluatedCgpComponent` and the provider-impl builders in `evaluated/`. The `EmptyStruct`, `ItemProviderImpl`, and `CgpComponentAttributes` helper types live in sibling `types/` modules; the visitors that rewrite `self`/`Self` live in [cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). diff --git a/docs/implementation/entrypoints/cgp_component.md b/docs/implementation/entrypoints/cgp_component.md new file mode 100644 index 00000000..ec88db39 --- /dev/null +++ b/docs/implementation/entrypoints/cgp_component.md @@ -0,0 +1,73 @@ +# `#[cgp_component]` — implementation + +`#[cgp_component]` turns one consumer trait into a full component by running a three-stage transform pipeline that parses the trait, derives the provider trait and blanket impls, and emits the standard provider impls. This document covers how that pipeline is built; for what the macro accepts and the expansion a user sees, read the reference document [reference/macros/cgp_component.md](../../reference/macros/cgp_component.md). + +## Entry point + +The macro is driven by the thin `cgp_component` function in [cgp-macro-lib/src/cgp_component.rs](../../../crates/macros/cgp-macro-lib/src/cgp_component.rs), which follows the canonical entry-point shape: it parses the attribute tokens into a [`CgpComponentArgs`](../asts/cgp_component.md) and the item tokens into a `syn::ItemTrait`, assembles them into an `ItemCgpComponent`, and runs the pipeline in one expression, wrapping the resulting items in a `quote!`: + +```rust +let item_cgp_component = ItemCgpComponent { args, item_trait }; +let derived = item_cgp_component.preprocess()?.eval()?.to_items()?; +``` + +All real logic lives in `cgp-macro-core`; the entry function contains no codegen of its own. The `syn::parse2` of the attribute is where the argument grammar is enforced, so a malformed attribute fails here through [`CgpComponentArgs`](../asts/cgp_component.md)'s `Parse` impl, and applying the macro to a non-trait item fails at the `syn::parse2::` call. + +## Pipeline + +The macro moves through three explicit stages, each a method on the AST type produced by the previous one; the [`cgp_component` AST stack](../asts/cgp_component.md) documents these types in full, and this section only names what each stage contributes. + +The **preprocess** stage (`ItemCgpComponent::preprocess`) strips the CGP-specific attributes off the trait through `CgpComponentAttributes::preprocess`, separating the modifier attributes (`#[derive_delegate]`, `#[prefix]`, and the rest) from the plain trait, and produces a `PreprocessedCgpComponent` holding the args, the cleaned `ItemTrait`, and the parsed attributes. No code is generated yet; this stage only normalizes the input. + +The **eval** stage (`PreprocessedCgpComponent::eval`) is where the core derivation happens. It builds the component marker struct, the provider trait, the provider blanket impl, and the consumer blanket impl, and packages them with the original consumer trait and the attributes into an `EvaluatedCgpComponent`. Each derived item is produced by a dedicated method — `to_component_struct`, `to_provider_trait_and_blanket_impl`, and `to_consumer_item_impl` — described under Generated items. + +The **to_items** stage (`EvaluatedCgpComponent::to_items`) collects the five core items in emission order and appends the standard provider impls — the `UseContext` impl, the `RedirectLookup` impl, one `UseDelegate` impl per `#[derive_delegate]` attribute, and one prefix impl per `#[prefix]` attribute — returning the `Vec` the entry function emits. + +## Generated items + +The macro emits five core items followed by the standard provider impls, and the emission order is fixed by `EvaluatedCgpComponent::to_items`: consumer trait, consumer blanket impl, provider trait, provider blanket impl, component struct, then the provider impls. This order is what the canonical snapshot in `component_macro.rs` pins, so it is a contract, not an incidental detail. + +The **consumer trait** is emitted unchanged from the preprocessed `ItemTrait` — the macro clones it into the output verbatim, minus the CGP attributes stripped during preprocess. + +The **provider trait** is built by `PreprocessedCgpComponent::to_provider_trait` (in `preprocessed/to_provider_trait.rs`). It clones the consumer trait, renames it to the provider identifier, inserts the context type parameter (`__Context__` by default) at the front of the generics, and moves the consumer trait's supertraits into a `__Context__: ` predicate in the `where` clause. It then replaces the trait's sole supertrait with the `IsProviderFor` bound, where the `Params` tuple comes from [`parse_is_provider_params`](../functions/parse/is_provider_params.md) over the consumer generics. Finally it rewrites every `self`/`Self` in the signatures to the context value and type using the `ReplaceSelfType`, `ReplaceSelfReceiver`, and `ReplaceSelfValue` visitors, so a method that took `&self` now takes `__context__: &__Context__`. Local associated types declared by the trait are collected first and passed to the type visitor as `skip_assoc_types`, so a reference to one of the trait's own associated types is left qualified rather than being rewritten onto the context. + +The **provider blanket impl** is built alongside the provider trait by `to_provider_trait_and_blanket_impl` (in `preprocessed/to_provider_blanket_impl.rs`), which returns both so they share one construction of the provider trait. It implements the provider trait for a fresh `__Provider__` parameter under two `where` predicates: `__Provider__: DelegateComponent + IsProviderFor`, and `<__Provider__ as DelegateComponent>::Delegate: `. The method bodies forward each call to the delegate through [`provider_trait_to_impl_items`](../functions/derive/delegated_impls.md). The `IsProviderFor` bound sits on `__Provider__` itself, beside `DelegateComponent`, which is what threads a component's dependencies down the delegation chain. + +The **consumer blanket impl** is built by `to_consumer_item_impl` (in `preprocessed/to_consumer_impl.rs`). It implements the consumer trait for `__Context__` under the predicate `__Context__: <__Context__, …>` (plus a `__Context__: ` predicate when the consumer trait has supertraits), and forwards each consumer method to the provider through the same delegated-impl helper. This is the bridge that makes `context.method()` resolve once a context implements the provider trait for itself. + +The **component struct** is built by `to_component_struct` as an `EmptyStruct` from the component name and its generics, emitting `pub struct Component;` (carrying `PhantomData` generics when the component name has type parameters). + +Beyond the five core items, `to_items` appends the standard provider impls. The **`UseContext` impl** (`evaluated/to_use_context_impl.rs`) implements the provider trait for `UseContext` by routing each method back through the context's own consumer-trait impl, under `__Context__: `. The **`RedirectLookup` impl** (`evaluated/to_redirect_lookup_impl.rs`) implements the provider trait for `RedirectLookup<__Components__, __Path__>`, the mechanism behind namespaces and the `open` statement; when the component has type parameters it appends them to the lookup path through `ConcatPath` (so a parameter `T` extends the path by `PathCons`), and when it has none it looks up `__Path__` directly. Each `#[derive_delegate]` attribute adds a **`UseDelegate` impl** via `to_use_delegate_impls`, and each `#[prefix]` attribute (from a `#[cgp_namespace]`) adds a **prefix impl** via `to_prefix_impls`. + +## Behavior and corner cases + +A supertrait on the consumer trait is not kept as a supertrait on the provider trait; it becomes a `where` predicate on the context. `to_provider_trait` moves the consumer supertraits into `__Context__: ` and replaces the provider trait's supertrait list with the single `IsProviderFor` bound, so `pub trait CanGreet: HasName` yields a provider trait whose only supertrait is `IsProviderFor<…>` and whose `where` clause carries `__Context__: HasName`. The same `__Context__: HasName` predicate is threaded onto the consumer blanket impl, the `UseContext` impl, and the `RedirectLookup` impl, so every generated impl repeats the supertrait as a context bound. + +A default method body is preserved into the provider trait. Because `to_provider_trait` clones the whole consumer trait including method bodies and only rewrites `self`/`Self`, a consumer method with a default body becomes a provider-trait method with the same body rewritten onto `__context__`; a provider written as an empty `#[cgp_impl]` then inherits that default. This is why an empty provider impl can satisfy a component whose methods all have defaults. + +Generic parameters on the component are appended after the context in the provider trait and grouped into the `IsProviderFor` params tuple. A lifetime parameter is kept ahead of `__Context__` (lifetimes must precede type parameters in Rust generics) and is lifted into `Life<'a>` inside the params tuple by `parse_is_provider_params`, so `HasReference<'a, T>` produces `IsProviderFor<…, (Life<'a>, T)>`. In the `RedirectLookup` impl only *type* parameters extend the lookup path — `generic_params_to_path` filters to `GenericParam::Type`, so lifetimes and const parameters are excluded from the `ConcatPath` path even though the lifetime still appears in the params tuple. + +The reserved identifiers are emitted literally. The context parameter is `__Context__` unless the `context` key overrides it, the provider parameter in the provider blanket impl is the hardcoded `__Provider__`, and the `RedirectLookup` impl introduces `__Components__` and `__Path__`. These names are chosen to avoid clashing with a user's own type parameters and appear verbatim in the generated code and every snapshot. + +## Known issues + +A const generic parameter on the component causes a panic rather than a clean error. `parse_is_provider_params` reaches `unimplemented!("const generic parameters are not yet supported in CGP traits")` for a `GenericParam::Const`, so `#[cgp_component]` on a trait with a const generic aborts macro expansion with a panic instead of returning a `syn::Error` pointing at the offending parameter. The correct behavior would be to reject the input with a spanned error, or to support const parameters in the params tuple; until then, components cannot carry const generics. This limitation has no expansion snapshot (the macro cannot produce output) and is a candidate for a failure case in `cgp-macro-tests`. + +## Snapshots + +The canonical full-expansion snapshot and the macro's distinct variants live in the concept targets that own the corresponding feature, per [crates/tests/CLAUDE.md](../../../crates/tests/CLAUDE.md); this section is the central index of which `#[cgp_component]` expansions are pinned and which are not. + +- The plain, no-parameter expansion is pinned in [basic_delegation/component_macro.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs) — a simple consumer trait with one method, the reference expansion other concepts reuse without re-snapshotting. +- The supertrait-plus-default-method variant is pinned in [basic_delegation/default_methods.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs) — shows the supertrait lowered to a `__Context__` `where` predicate and a default body copied into the provider trait. +- The lifetime-and-type-parameter variant is pinned in [generic_components/component_lifetime.rs](../../../crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs) — shows the lifetime kept ahead of `__Context__`, lifted to `Life<'a>` in the params tuple, and the type parameter appended to the `RedirectLookup` path via `ConcatPath`. +- The namespace and prefix variants — the prefix impls `to_prefix_impls` emits — are pinned across the `namespaces` target, including [namespaces/namespace_basic.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_basic.rs), [namespaces/namespace_symbol_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_symbol_path.rs), [namespaces/namespace_type_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_type_path.rs), [namespaces/namespace_multi.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_multi.rs), [namespaces/redirect_lookup.rs](../../../crates/tests/cgp-tests/tests/namespaces/redirect_lookup.rs), [namespaces/default_impls.rs](../../../crates/tests/cgp-tests/tests/namespaces/default_impls.rs), and [namespaces/prefix_default_namespace.rs](../../../crates/tests/cgp-tests/tests/namespaces/prefix_default_namespace.rs). + +Two variants have no snapshot yet. There is no snapshot of the `UseDelegate` impl that a `#[derive_delegate]` attribute adds to a `#[cgp_component]` definition — that attribute's output is exercised through the error and handler families rather than pinned on a bare component here (see [reference/attributes/derive_delegate.md](../../reference/attributes/derive_delegate.md)). And there is no snapshot of a component carrying a type parameter but no lifetime, distinct from the combined lifetime-and-type case above; the type-only path through `generic_params_to_path` is therefore only covered incidentally. + +## Tests + +Beyond the snapshots above, the behavioral tests in [crates/tests/cgp-tests](../../../crates/tests/cgp-tests) verify that the generated wiring actually works: [basic_delegation/default_methods.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs) confirms at run time that an empty provider impl picks up the default method bodies and that `App.greet()` returns the expected string, and [generic_components/component_lifetime.rs](../../../crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs) checks the lifetime-carrying component wires and passes `check_components!`. The failure case in [cgp-macro-tests/tests/parser_rejections/cgp_component.rs](../../../crates/tests/cgp-macro-tests/tests/parser_rejections/cgp_component.rs) asserts that applying the macro to a non-trait item (a struct) is rejected at parse time rather than producing garbage output. + +## Source + +The entry point is `cgp_component` in [cgp-macro-lib/src/cgp_component.rs](../../../crates/macros/cgp-macro-lib/src/cgp_component.rs). The pipeline and its AST types live in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/): argument parsing in `args/`, the provider trait and both blanket impls in `preprocessed/`, and the standard provider impls in `evaluated/`. The AST stack is documented in [asts/cgp_component.md](../asts/cgp_component.md); the shared codegen helpers it calls are documented in [functions/derive/delegated_impls.md](../functions/derive/delegated_impls.md) and [functions/parse/is_provider_params.md](../functions/parse/is_provider_params.md); the `parse_internal!` macro used throughout is documented in [macros/parse_internal.md](../macros/parse_internal.md). diff --git a/docs/implementation/functions/derive/delegated_impls.md b/docs/implementation/functions/derive/delegated_impls.md new file mode 100644 index 00000000..10f150f2 --- /dev/null +++ b/docs/implementation/functions/derive/delegated_impls.md @@ -0,0 +1,27 @@ +# Delegated-impl synthesis + +The delegated-impl functions turn a trait's items into the body of an impl that forwards every method, associated type, and constant to a chosen delegate type. They are the shared machinery behind the forwarding impls that `#[cgp_component]` and its relatives emit — the consumer blanket impl, the provider blanket impl, the `UseContext` impl, and the `RedirectLookup` impl all route their calls through the same delegate type by way of these functions, so the forwarding shape is written once and reused everywhere. + +The core idea is a single delegate type supplied by the caller: given a trait and a `delegate_type` expression, each generated impl item calls the delegate's version of that trait item. A method `fn area(context: &Context) -> f64` becomes `fn area(context: &Context) -> f64 { ::area(context) }`; an associated type becomes `type Output = ::Output;`; an associated const becomes `const N: usize = ::N;`. Which concrete type fills `` is the caller's choice, and that is what distinguishes the four impls that use these functions. + +## `trait_items_to_delegated_impl_items` + +`trait_items_to_delegated_impl_items` maps a slice of `syn::TraitItem` to the `Vec` that forwards each one to the delegate, and is the entry point most callers use. It takes the trait items, the `delegate_type` to forward to, and the `provider_trait_path` used to qualify associated-type and const projections, and applies `trait_item_to_delegated_impl_items` to each item. + +`trait_item_to_delegated_impl_items` handles the three supported item kinds and rejects the rest. A **function** is forwarded by `signature_to_delegated_impl_item_fn`, which builds a method body that calls the delegate with the same arguments. An **associated type** becomes `type Name = ::Name;`, qualified through the provider trait path so the projection is unambiguous. An **associated const** becomes `const Name = ::Name;`, copying the const's type and attributes. Any other trait item — a macro invocation, for example — produces a `syn::Error` reading "unsupported trait item", so the macro fails cleanly rather than dropping the item silently. + +## `provider_trait_to_impl_items` + +`provider_trait_to_impl_items` is the convenience wrapper for the common case of forwarding a *provider* trait's own items to a delegate. It takes the provider `ItemTrait` and a `delegate_type`, reconstructs the provider trait path from the trait's identifier and its generics (via `split_for_impl`), and calls `trait_items_to_delegated_impl_items` with that path. The provider blanket impl and the `RedirectLookup` impl use it because both forward the provider trait to a `<… as DelegateComponent<…>>::Delegate` type; the consumer blanket impl and the `UseContext` impl call `trait_items_to_delegated_impl_items` directly instead, because they forward *across* traits (consumer to provider, or provider to consumer) and so must supply a different trait path than the trait being implemented. + +## Behavior and corner cases + +The forwarding qualifies associated types and consts through the supplied trait path, not through the impl's own trait, which matters when the source and target traits differ. When the consumer blanket impl forwards to the provider trait, an associated type is projected as `<__Context__ as ProviderTrait>::Output`, because the value lives on the provider side; passing the wrong path here would produce an impl that does not type-check. Method forwarding, by contrast, needs no trait qualification — it calls the delegate's inherent-looking associated function `::method(args)` and relies on the delegate's trait bound in the impl's `where` clause to resolve it. + +## Tests + +These functions have no dedicated unit test; they are covered through the `#[cgp_component]` expansion snapshots, which pin the forwarding bodies of all four impls. The plain case in [basic_delegation/component_macro.rs](../../../../crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs) shows method forwarding through `<__Provider__ as DelegateComponent<…>>::Delegate::foo(…)` and through `UseContext`/`RedirectLookup`; the default-method case in [basic_delegation/default_methods.rs](../../../../crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs) confirms a forwarded call resolves to a default body. Associated-type and const forwarding are pinned by the `#[cgp_type]` snapshots in the `abstract_types` target. + +## Source + +The functions live in [cgp-macro-core/src/functions/delegated_impls/](../../../../crates/macros/cgp-macro-core/src/functions/delegated_impls/): `trait_items.rs` holds `trait_items_to_delegated_impl_items` and the per-item dispatch, `provider_trait.rs` holds `provider_trait_to_impl_items`, `signature.rs` holds the method-forwarding builder `signature_to_delegated_impl_item_fn`, and `item_type.rs` holds `trait_to_impl_item_type`. The callers are documented in [entrypoints/cgp_component.md](../../entrypoints/cgp_component.md) and the [cgp_component AST stack](../../asts/cgp_component.md). diff --git a/docs/implementation/functions/parse/is_provider_params.md b/docs/implementation/functions/parse/is_provider_params.md new file mode 100644 index 00000000..cb584983 --- /dev/null +++ b/docs/implementation/functions/parse/is_provider_params.md @@ -0,0 +1,21 @@ +# `parse_is_provider_params` + +`parse_is_provider_params` converts a trait's generic parameters into the tuple of types that fills the `Params` position of an [`IsProviderFor`](../../../reference/traits/is_provider_for.md) bound. Every provider trait carries an `IsProviderFor` supertrait, and this function computes the `(Params)` part from the consumer trait's generics, so the marker records exactly the extra parameters a component takes beyond its context. + +The transformation is a straightforward per-parameter mapping, but it normalizes the parameters into type form because the params tuple is a tuple of *types*. A type parameter passes through as itself: `T` becomes `T`. A lifetime parameter is lifted into a type through the `Life` wrapper, because a bare lifetime cannot appear as a tuple element: `'a` becomes `Life<'a>`. The parameters are first passed through `TypeGenerics` so that bounds and defaults are stripped and only the parameter names remain, then each is rendered with `parse_internal!`. The result is a `Punctuated` that the caller wraps in parentheses. + +## Behavior and corner cases + +Lifetimes are preserved in the params tuple even though they are dropped from the redirected lookup path. `parse_is_provider_params` emits `Life<'a>` for a lifetime, so `HasReference<'a, T>` yields the tuple `(Life<'a>, T)`; the separate `generic_params_to_path` helper used by the `RedirectLookup` impl keeps only type parameters, which is why a lifetime appears in `IsProviderFor` but not in the `ConcatPath` path. Holding both facts together is necessary to read the lifetime-component snapshot correctly. + +## Known issues + +A const generic parameter triggers a panic. The `GenericParam::Const` arm is `unimplemented!("const generic parameters are not yet supported in CGP traits")`, so any component-defining macro that reaches this function with a const parameter aborts expansion with a panic rather than returning a spanned `syn::Error`. The correct behavior would be a clean rejection or genuine const-parameter support. This is the root cause of the const-generic limitation recorded in [entrypoints/cgp_component.md](../../entrypoints/cgp_component.md); the same panic affects every macro that builds a provider trait through this helper. + +## Tests + +The function is covered indirectly through the expansion snapshots that pin the `IsProviderFor` params tuple: the empty `()` case in [basic_delegation/component_macro.rs](../../../../crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs) and the `(Life<'a>, T)` case in [generic_components/component_lifetime.rs](../../../../crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs). The const-generic panic has no test yet and is a candidate failure case for `cgp-macro-tests`. + +## Source + +The function lives in [cgp-macro-core/src/functions/is_provider_params.rs](../../../../crates/macros/cgp-macro-core/src/functions/is_provider_params.rs). It is called by the provider-trait and blanket-impl builders in [cgp-macro-core/src/types/cgp_component/preprocessed/](../../../../crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/); the `Life` wrapper it emits is documented in [reference/types/life.md](../../../reference/types/life.md). diff --git a/docs/implementation/macros/define_keyword.md b/docs/implementation/macros/define_keyword.md new file mode 100644 index 00000000..45bef5f4 --- /dev/null +++ b/docs/implementation/macros/define_keyword.md @@ -0,0 +1,17 @@ +# `define_keyword!` + +`define_keyword!` declares a custom-keyword marker type for the CGP parsers — a zero-sized struct paired with the string it matches. The CGP macros parse several bespoke keywords in their bodies (`new` in `#[cgp_impl]` and `delegate_components!`, `open` in the `open` dispatch statement, and the rest), and each such keyword is represented at the type level by a struct that carries the keyword's spelling so the parser can recognize it and error on a mismatch. + +The macro expands to two items. `define_keyword!(Foo, "foo")` emits `pub struct Foo;` and an `impl crate::traits::IsKeyword for Foo` whose associated const `IDENT` is `"foo"`. The `IsKeyword` trait is the shared interface the parsing machinery uses: a parser peeks the next identifier, compares it against `::IDENT`, and consumes it as that keyword when they match. Defining a keyword is therefore just declaring the marker and wiring its spelling into the trait; the actual peek-and-consume logic lives with the parser that uses the keyword. + +## Behavior and corner cases + +The keyword string and the struct name are independent, so the marker can be named for its role rather than its spelling, though in practice they match (`New`/`"new"`, `Open`/`"open"`). Because the generated struct is an ordinary public type, a keyword marker can also appear in generated code or as a type-level tag where that is useful, not only in the parser. + +## Tests + +`define_keyword!` has no dedicated test; the keywords it defines are exercised through the parser tests and expansion snapshots of the macros that use them — for example the `new`-prefixed forms pinned in the `basic_delegation` snapshots and the `open` statement pinned in the `namespaces` and `dispatching` targets. + +## Source + +The macro is defined in [cgp-macro-core/src/macros/keyword.rs](../../../crates/macros/cgp-macro-core/src/macros/keyword.rs); the `IsKeyword` trait it implements lives in `cgp-macro-core/src/traits/`, and the keyword marker types that use it live in `cgp-macro-core/src/types/keyword*.rs`. The convention that custom keywords go through this macro is recorded in [cgp-macro-core/CLAUDE.md](../../../crates/macros/cgp-macro-core/CLAUDE.md). diff --git a/docs/implementation/macros/parse_internal.md b/docs/implementation/macros/parse_internal.md new file mode 100644 index 00000000..b99df22c --- /dev/null +++ b/docs/implementation/macros/parse_internal.md @@ -0,0 +1,21 @@ +# `parse_internal!` + +`parse_internal!` is the internal macro the CGP codegen uses to build a `syn` AST node from quasi-quoted tokens, attaching a descriptive error if the tokens do not parse. It is the workhorse of the whole macro implementation: nearly every generated fragment — a `where` predicate, a trait path, a type, an impl item — is produced by quoting tokens and parsing them into the target `syn` type through this macro, rather than by constructing the `syn` node field-by-field. + +The macro is a thin wrapper over a function of the same name. `parse_internal!( #tokens … )` expands to `crate::functions::parse_internal(crate::vendor::quote!( #tokens … ))?` — it quotes its body with `quote!` (routed through the crate's vendored re-export so exported `macro_rules!` can reach it) and passes the resulting `TokenStream` to the `parse_internal` function. The trailing `?` is significant: the macro expands to a `?` expression, so it must be invoked inside a function that returns `syn::Result`, and a parse failure propagates as an early return rather than a panic. + +The `parse_internal` function is where the descriptive error is attached. It calls `syn::parse2` for the inferred target type `T: Parse`, and on failure combines the original parser error with a second error spanning the input tokens and reading "failed to parse internal tokens to type ``", followed by the offending tokens rendered with the `::cgp::macro_prelude::` prefix stripped for readability (via `strip_macro_prelude`). This turns an opaque "expected …" parser error into one that names both the target AST type and the concrete tokens that failed, which is what makes a codegen bug diagnosable. + +## Behavior and corner cases + +The target type is inferred from context, so the same invocation parses into whatever `syn` type the surrounding code expects. `let ty: Type = parse_internal!(#ident);` parses a type while `let p: Path = parse_internal!(#ident #generics);` parses a path from similar tokens; the `T: Parse` bound is resolved by the binding or argument position. When no type can be inferred, annotate the binding. + +A subtle interaction with the `?` expansion is that `parse_internal!` cannot be used where a `?` is not valid — outside a `syn::Result`-returning function, or in a `const` context. The sibling plain function `parse_internal(tokens)?` is available for the cases where the token stream is already built (for example when a `quote!` block was assembled conditionally), and the blanket-impl builder uses it directly for exactly that reason. + +## Tests + +`parse_internal!` has no dedicated test; it is exercised by every macro-expansion snapshot in the suite, since essentially all generated code passes through it. Its error path is observed indirectly whenever a codegen change produces unparseable tokens during development. + +## Source + +The macro is defined in [cgp-macro-core/src/macros/parse.rs](../../../crates/macros/cgp-macro-core/src/macros/parse.rs) and the backing function in [cgp-macro-core/src/functions/parse_internal.rs](../../../crates/macros/cgp-macro-core/src/functions/parse_internal.rs). The `quote!` re-export it depends on is in `cgp-macro-core/src/vendor.rs`, and the prefix-stripping helper is `strip_macro_prelude` in `cgp-macro-core/src/functions/strip.rs`. The convention that all AST nodes are built through this macro is recorded in [cgp-macro-core/CLAUDE.md](../../../crates/macros/cgp-macro-core/CLAUDE.md). diff --git a/docs/reference/README.md b/docs/reference/README.md index 53b466fe..2586e5bf 100644 --- a/docs/reference/README.md +++ b/docs/reference/README.md @@ -1,6 +1,6 @@ # CGP Construct Reference -This directory documents every CGP construct — one self-contained document per construct, each explaining its purpose, syntax or definition, expansion or behavior, examples, related constructs, and source. The documents are written for agents who need precise per-construct semantics. The high-level conceptual framing that connects the constructs lives in the sibling [concepts/](../concepts/README.md) directory; the `/cgp` skill remains a complementary teaching aid. The authoring rules, document template, and the requirement to keep these documents in sync with the code live in [../CLAUDE.md](../CLAUDE.md). +This directory documents every CGP construct — one self-contained document per construct, each explaining its purpose, syntax or definition, expansion or behavior, examples, related constructs, and source. The documents are written for agents who need precise per-construct semantics, and they point only at library source, never at a test. The high-level conceptual framing that connects the constructs lives in the sibling [concepts/](../concepts/README.md) directory; the internal mechanics of each macro — its pipeline, the functions that synthesize its output, and every pointer into the test suite — live in the sibling [implementation/](../implementation/README.md) directory, to which each reference document's Source section links; the `/cgp` skill remains a complementary teaching aid. The authoring rules, document template, and the requirement to keep these documents in sync with the code live in [../CLAUDE.md](../CLAUDE.md). ## Directory layout diff --git a/docs/reference/macros/cgp_component.md b/docs/reference/macros/cgp_component.md index eac43b03..94474504 100644 --- a/docs/reference/macros/cgp_component.md +++ b/docs/reference/macros/cgp_component.md @@ -183,4 +183,6 @@ The call `rect.area()` resolves through the consumer blanket impl to `Rectangle: ## Source -The macro entry point is `cgp_component` in [crates/macros/cgp-macro-lib/src/cgp_component.rs](../../../crates/macros/cgp-macro-lib/src/cgp_component.rs), which drives the `preprocess → eval → to_items` pipeline. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/): argument parsing in `args/`, the provider trait and blanket impls in `preprocessed/`, and the standard provider impls (`UseContext`, `RedirectLookup`, `UseDelegate`) in `evaluated/`. The default identifiers `__Context__` and `{Provider}Component` are set in `args/component_args.rs`. Behavioral and expansion-snapshot tests are in [crates/tests/cgp-tests](../../../crates/tests/cgp-tests) and [crates/tests/cgp-macro-tests](../../../crates/tests/cgp-macro-tests). +The macro entry point is `cgp_component` in [crates/macros/cgp-macro-lib/src/cgp_component.rs](../../../crates/macros/cgp-macro-lib/src/cgp_component.rs), which drives the `preprocess → eval → to_items` pipeline. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/): argument parsing in `args/`, the provider trait and blanket impls in `preprocessed/`, and the standard provider impls (`UseContext`, `RedirectLookup`, `UseDelegate`) in `evaluated/`. The default identifiers `__Context__` and `{Provider}Component` are set in `args/component_args.rs`. + +For the full internal walkthrough — the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/cgp_component.md](../../implementation/entrypoints/cgp_component.md). From 891cb33fdeb14225569f8d205b3e31080808d0b5 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 2 Jul 2026 01:13:04 +0200 Subject: [PATCH 2/3] Generate remaining impl docs --- docs/implementation/CLAUDE.md | 14 ++- docs/implementation/README.md | 65 ++++++++--- docs/implementation/asts/attributes.md | 85 +++++++++++++++ docs/implementation/asts/blanket_trait.md | 24 +++++ docs/implementation/asts/cgp_component.md | 32 +++--- docs/implementation/asts/cgp_data.md | 52 +++++++++ docs/implementation/asts/cgp_fn.md | 38 +++++++ docs/implementation/asts/cgp_getter.md | 37 +++++++ docs/implementation/asts/cgp_impl.md | 61 +++++++++++ docs/implementation/asts/cgp_provider.md | 63 +++++++++++ docs/implementation/asts/cgp_type.md | 21 ++++ docs/implementation/asts/check_components.md | 55 ++++++++++ .../implementation/asts/delegate_component.md | 63 +++++++++++ docs/implementation/asts/namespace.md | 45 ++++++++ docs/implementation/asts/path.md | 45 ++++++++ docs/implementation/asts/product.md | 36 +++++++ docs/implementation/asts/sum.md | 25 +++++ docs/implementation/asts/symbol.md | 29 +++++ .../implementation/entrypoints/async_trait.md | 49 +++++++++ .../entrypoints/blanket_trait.md | 84 +++++++++++++++ .../entrypoints/cgp_auto_dispatch.md | 77 +++++++++++++ .../entrypoints/cgp_auto_getter.md | 86 +++++++++++++++ .../entrypoints/cgp_component.md | 79 ++++++++------ .../entrypoints/cgp_computer.md | 67 ++++++++++++ docs/implementation/entrypoints/cgp_fn.md | 98 +++++++++++++++++ docs/implementation/entrypoints/cgp_getter.md | 86 +++++++++++++++ docs/implementation/entrypoints/cgp_impl.md | 82 ++++++++++++++ .../entrypoints/cgp_namespace.md | 92 ++++++++++++++++ .../entrypoints/cgp_new_provider.md | 42 ++++++++ .../entrypoints/cgp_producer.md | 53 +++++++++ .../entrypoints/cgp_provider.md | 73 +++++++++++++ docs/implementation/entrypoints/cgp_type.md | 85 +++++++++++++++ .../entrypoints/check_components.md | 63 +++++++++++ .../delegate_and_check_components.md | 77 +++++++++++++ .../entrypoints/delegate_components.md | 101 ++++++++++++++++++ .../entrypoints/derive_build_field.md | 54 ++++++++++ .../entrypoints/derive_cgp_data.md | 57 ++++++++++ .../entrypoints/derive_cgp_record.md | 28 +++++ .../entrypoints/derive_cgp_variant.md | 28 +++++ .../entrypoints/derive_extract_field.md | 59 ++++++++++ .../entrypoints/derive_from_variant.md | 47 ++++++++ .../entrypoints/derive_has_field.md | 69 ++++++++++++ .../entrypoints/derive_has_fields.md | 69 ++++++++++++ docs/implementation/entrypoints/path.md | 49 +++++++++ docs/implementation/entrypoints/product.md | 58 ++++++++++ .../entrypoints/snapshot_macros.md | 76 +++++++++++++ docs/implementation/entrypoints/sum.md | 44 ++++++++ docs/implementation/entrypoints/symbol.md | 52 +++++++++ .../functions/derive/generics.md | 13 +++ .../implementation/functions/derive/idents.md | 15 +++ .../macros/export_constructs.md | 15 +++ docs/reference/attributes/derive_delegate.md | 2 + docs/reference/attributes/extend.md | 4 +- docs/reference/attributes/extend_where.md | 4 +- docs/reference/attributes/implicit.md | 4 +- docs/reference/attributes/use_provider.md | 4 +- docs/reference/attributes/use_type.md | 4 +- docs/reference/attributes/uses.md | 4 +- docs/reference/components/can_raise_error.md | 2 +- docs/reference/components/computer.md | 2 +- docs/reference/components/handler.md | 2 +- docs/reference/components/has_error_type.md | 2 +- docs/reference/components/has_type.md | 2 +- docs/reference/components/producer.md | 2 +- docs/reference/components/runner.md | 2 +- docs/reference/components/try_computer.md | 2 +- docs/reference/derives/derive_build_field.md | 4 +- docs/reference/derives/derive_cgp_data.md | 4 +- docs/reference/derives/derive_cgp_record.md | 4 +- docs/reference/derives/derive_cgp_variant.md | 4 +- .../reference/derives/derive_extract_field.md | 4 +- docs/reference/derives/derive_from_variant.md | 4 +- docs/reference/derives/derive_has_field.md | 4 +- docs/reference/derives/derive_has_fields.md | 4 +- docs/reference/macros/async_trait.md | 5 +- docs/reference/macros/blanket_trait.md | 4 +- docs/reference/macros/cgp_auto_dispatch.md | 4 +- docs/reference/macros/cgp_auto_getter.md | 4 +- docs/reference/macros/cgp_computer.md | 4 +- docs/reference/macros/cgp_fn.md | 4 +- docs/reference/macros/cgp_getter.md | 4 +- docs/reference/macros/cgp_impl.md | 4 +- docs/reference/macros/cgp_namespace.md | 4 +- docs/reference/macros/cgp_new_provider.md | 4 +- docs/reference/macros/cgp_producer.md | 4 +- docs/reference/macros/cgp_provider.md | 4 +- docs/reference/macros/cgp_type.md | 4 +- docs/reference/macros/check_components.md | 4 +- .../macros/delegate_and_check_components.md | 4 +- docs/reference/macros/delegate_components.md | 4 +- docs/reference/macros/path.md | 4 +- docs/reference/macros/product.md | 2 + docs/reference/macros/sum.md | 2 + docs/reference/macros/symbol.md | 4 +- .../providers/dispatch_combinators.md | 2 +- docs/reference/providers/error_providers.md | 2 +- .../providers/handler_combinators.md | 2 +- docs/reference/providers/monad_providers.md | 2 +- docs/reference/providers/redirect_lookup.md | 2 +- docs/reference/providers/use_context.md | 2 +- docs/reference/providers/use_default.md | 2 +- docs/reference/providers/use_delegate.md | 2 +- docs/reference/providers/use_field.md | 2 +- docs/reference/providers/use_fields.md | 2 +- docs/reference/providers/use_type.md | 2 +- docs/reference/providers/with_provider.md | 2 +- docs/reference/traits/can_use_component.md | 2 +- docs/reference/traits/cast.md | 2 +- docs/reference/traits/default_namespace.md | 2 +- docs/reference/traits/delegate_component.md | 2 +- docs/reference/traits/extract_field.md | 2 +- docs/reference/traits/from_variant.md | 2 +- docs/reference/traits/has_builder.md | 2 +- docs/reference/traits/has_field.md | 2 +- docs/reference/traits/has_fields.md | 2 +- docs/reference/traits/is_provider_for.md | 2 +- docs/reference/traits/map_type.md | 2 +- docs/reference/traits/monad.md | 2 +- docs/reference/traits/optional_fields.md | 2 +- docs/reference/traits/product_ops.md | 2 +- docs/reference/traits/static_format.md | 2 +- docs/reference/types/chars.md | 2 +- docs/reference/types/life.md | 2 +- 123 files changed, 2889 insertions(+), 137 deletions(-) create mode 100644 docs/implementation/asts/attributes.md create mode 100644 docs/implementation/asts/blanket_trait.md create mode 100644 docs/implementation/asts/cgp_data.md create mode 100644 docs/implementation/asts/cgp_fn.md create mode 100644 docs/implementation/asts/cgp_getter.md create mode 100644 docs/implementation/asts/cgp_impl.md create mode 100644 docs/implementation/asts/cgp_provider.md create mode 100644 docs/implementation/asts/cgp_type.md create mode 100644 docs/implementation/asts/check_components.md create mode 100644 docs/implementation/asts/delegate_component.md create mode 100644 docs/implementation/asts/namespace.md create mode 100644 docs/implementation/asts/path.md create mode 100644 docs/implementation/asts/product.md create mode 100644 docs/implementation/asts/sum.md create mode 100644 docs/implementation/asts/symbol.md create mode 100644 docs/implementation/entrypoints/async_trait.md create mode 100644 docs/implementation/entrypoints/blanket_trait.md create mode 100644 docs/implementation/entrypoints/cgp_auto_dispatch.md create mode 100644 docs/implementation/entrypoints/cgp_auto_getter.md create mode 100644 docs/implementation/entrypoints/cgp_computer.md create mode 100644 docs/implementation/entrypoints/cgp_fn.md create mode 100644 docs/implementation/entrypoints/cgp_getter.md create mode 100644 docs/implementation/entrypoints/cgp_impl.md create mode 100644 docs/implementation/entrypoints/cgp_namespace.md create mode 100644 docs/implementation/entrypoints/cgp_new_provider.md create mode 100644 docs/implementation/entrypoints/cgp_producer.md create mode 100644 docs/implementation/entrypoints/cgp_provider.md create mode 100644 docs/implementation/entrypoints/cgp_type.md create mode 100644 docs/implementation/entrypoints/check_components.md create mode 100644 docs/implementation/entrypoints/delegate_and_check_components.md create mode 100644 docs/implementation/entrypoints/delegate_components.md create mode 100644 docs/implementation/entrypoints/derive_build_field.md create mode 100644 docs/implementation/entrypoints/derive_cgp_data.md create mode 100644 docs/implementation/entrypoints/derive_cgp_record.md create mode 100644 docs/implementation/entrypoints/derive_cgp_variant.md create mode 100644 docs/implementation/entrypoints/derive_extract_field.md create mode 100644 docs/implementation/entrypoints/derive_from_variant.md create mode 100644 docs/implementation/entrypoints/derive_has_field.md create mode 100644 docs/implementation/entrypoints/derive_has_fields.md create mode 100644 docs/implementation/entrypoints/path.md create mode 100644 docs/implementation/entrypoints/product.md create mode 100644 docs/implementation/entrypoints/snapshot_macros.md create mode 100644 docs/implementation/entrypoints/sum.md create mode 100644 docs/implementation/entrypoints/symbol.md create mode 100644 docs/implementation/functions/derive/generics.md create mode 100644 docs/implementation/functions/derive/idents.md create mode 100644 docs/implementation/macros/export_constructs.md diff --git a/docs/implementation/CLAUDE.md b/docs/implementation/CLAUDE.md index 15e32f2e..4beae161 100644 --- a/docs/implementation/CLAUDE.md +++ b/docs/implementation/CLAUDE.md @@ -36,11 +36,19 @@ Because documents live in different subdirectories, a cross-link between two of Each kind of document follows a shape so an agent can navigate any of them by habit. All kinds share the same opening — a level-one heading naming the construct and a one-sentence summary — and the same closing pair of a **Tests** section and a **Source** section. The middle sections differ by kind. -An **entrypoint document** (`entrypoints/.md`) proceeds through: **Entry point** — the `cgp-macro-lib` function, what it parses the attribute and item into, and the pipeline call it drives; **Pipeline** — each stage in order (for `cgp_component`, `preprocess → eval → to_items`), what AST type it produces, and a link to the [asts/](asts/) document that owns those types; **Generated items** — the exact list of items the macro emits, in emission order, each with the function in `cgp-macro-core` that synthesizes it, so this reads as the internal companion to the reference document's Expansion section; **Behavior and corner cases** — how the implementation handles supertraits, default methods, generic parameters, lifetimes, reserved identifiers, and any input the macro treats specially; **Known issues** — limitations and bugs, following the rule below; then **Snapshots**, **Tests**, and **Source**. +An **entrypoint document** (`entrypoints/.md`) proceeds through: **Entry point** — the `cgp-macro-lib` function, what it parses the attribute and item into, and the pipeline call it drives; **Pipeline** — each stage in order (for `cgp_component`, `preprocess → eval → to_items`), what each stage does at a high level, and a link to the [asts/](asts/) document that owns those types; **Generated items** — what the macro emits and in what order, described at a high level and illustrated with a code snippet where a transform is worth showing; **Behavior and corner cases** — how the implementation handles supertraits, default methods, generic parameters, lifetimes, reserved identifiers, and any input the macro treats specially; **Known issues** — limitations and bugs, following the rule below; then **Snapshots**, **Tests**, and **Source**. -An **AST document** (`asts/.md`) opens with a short overview of the stack as a pipeline, then gives one section per AST type in the order the data flows through them. Each section states the type's role, lists its fields, describes its `Parse` impl (what token grammar it accepts) and/or its `ToTokens` impl (what it emits) and any transform methods it carries, and links to the entrypoint document that drives the stack. It then closes with **Tests** and **Source**. +An **AST document** (`asts/.md`) opens with a short overview of the stack as a pipeline, then gives one section per AST type in the order the data flows through them. Each section states the type's role, the shape it parses from or emits into (with a snippet where a grammar or intermediary form is worth showing), and how it hands off to the next stage, and links to the entrypoint document that drives the stack. It then closes with **Tests** and **Source**. -A **function document** (`functions//.md`) opens with what the group of functions is for, gives one section per public function stating its signature intent, what it consumes and produces, and its corner cases, and closes with **Tests** and **Source**. A **macro document** (`macros/.md`) describes what the internal `macro_rules!` expands to, how the implementation is expected to call it (for `parse_internal!`, that it expands to a `?` expression and must be called in a `syn::Result`-returning function), and closes with **Tests** and **Source**. +A **function document** (`functions//.md`) opens with what the group of functions is for and describes what each public function does and its corner cases at a high level, closing with **Tests** and **Source**. A **macro document** (`macros/.md`) describes what the internal `macro_rules!` expands to, how the implementation is expected to call it (for `parse_internal!`, that it expands to a `?` expression and must be called in a `syn::Result`-returning function), and closes with **Tests** and **Source**. + +## Level of detail and code snippets + +An implementation document gives the high-level picture of how a construct works; the code holds the details, so do not rehash it line by line. Explain what the construct does and why, name the stages it moves through and the shape of what it produces, and leave the mechanics of each step to the source. Mention an internal function only when a reader needs it as an entry point into the code, or when the explanation must cross into another implementation document — do not walk a call chain naming every helper it touches. Break an explanation into ordered steps only when it jumps between documents (a macro whose expansion depends on a helper documented elsewhere, say); within a single document, prefer a high-level description over a step-by-step trace of the code. + +Use code snippets to make specific behavior concrete. When you describe how input is parsed or what code is generated, a short before/after snippet is usually clearer than prose — show the parsed form, an intermediary representation the user never writes, or the slice of generated output that illustrates the point. These snippets are deliberately not exhaustive: the reference document already shows the full accepted syntax and the complete expansion, so an implementation snippet covers only the fragment that explains the behavior at hand — one corner case, one intermediary form, or how one construct lowers into another. Prefer illustrating a tricky transform (a supertrait becoming a `where`-bound, a lifetime lifted into `Life<'a>`) with a small example over describing it in the abstract. + +When a section lists many items one at a time — the tests, the snapshots, a set of accepted keys — use a bullet list rather than framed prose. The dual-reader topic-sentence style governs the explanatory prose, not these enumerations: introduce the list with a short sentence and let the bullets carry the items. ## The Tests and Snapshots sections diff --git a/docs/implementation/README.md b/docs/implementation/README.md index 928d74d6..9976d46a 100644 --- a/docs/implementation/README.md +++ b/docs/implementation/README.md @@ -12,38 +12,73 @@ The [entrypoints/](entrypoints/) directory holds one document per CGP macro — ## Catalog -The catalog is the index of implementation documents. The build-out is proceeding one construct at a time; this section registers what is documented and lists what is still pending, so the next agent can see both the shape of the finished tree and where to continue. When you add a document, move its entry from the pending list to the documented list in the same change. +This section is the index of implementation documents. When you add a document, register it here in the same change. ### Entrypoints — [entrypoints/](entrypoints/) -Documented so far: +The component and provider macros: - [`#[cgp_component]`](entrypoints/cgp_component.md) — the foundational component-definition macro and its `preprocess → eval → to_items` pipeline. +- [`#[cgp_impl]`](entrypoints/cgp_impl.md) — lowers consumer-style syntax into a provider impl and hands it to `#[cgp_provider]`. +- [`#[cgp_provider]`](entrypoints/cgp_provider.md) — passes a provider-trait impl through and derives its `IsProviderFor` impl. +- [`#[cgp_new_provider]`](entrypoints/cgp_new_provider.md) — `#[cgp_provider]` with the provider struct also declared. -Pending, one document each — the remaining `cgp-macro-lib` macros (`#[cgp_impl]`, `#[cgp_provider]`, `#[cgp_new_provider]`, `#[cgp_fn]`, `#[cgp_type]`, `#[cgp_getter]`, `#[cgp_auto_getter]`, `#[blanket_trait]`, `delegate_components!`, `check_components!`, `delegate_and_check_components!`, `#[cgp_namespace]`, `Symbol!`, `Product!`, `Sum!`, `Path!`, and the data derives `#[derive(HasField)]`, `HasFields`, `CgpData`, `CgpRecord`, `CgpVariant`, `BuildField`, `ExtractField`, `FromVariant`), the `cgp-extra-macro-lib` macros (`#[cgp_computer]`, `#[cgp_producer]`, `#[cgp_auto_dispatch]`), `#[async_trait]` from `cgp-async-macro`, and the `snapshot_*!` family from [cgp-macro-test-util](../../crates/macros/cgp-macro-test-util). +Functions and getters: -### AST stacks — [asts/](asts/) +- [`#[cgp_fn]`](entrypoints/cgp_fn.md) — a single-implementation capability as a blanket-impl trait, with `#[implicit]` argument lowering. +- [`#[cgp_getter]`](entrypoints/cgp_getter.md) — a getter component wired through CGP, adding `UseField`/`UseFields` provider impls. +- [`#[cgp_auto_getter]`](entrypoints/cgp_auto_getter.md) — a getter as a blanket impl over `HasField`. + +Abstract types and blanket traits: + +- [`#[cgp_type]`](entrypoints/cgp_type.md) — an abstract-type component, reusing the `#[cgp_component]` pipeline and adding `UseType`. +- [`#[blanket_trait]`](entrypoints/blanket_trait.md) — a blanket impl generated from a trait with default methods. + +Wiring and checking: + +- [`delegate_components!`](entrypoints/delegate_components.md) — the context wiring table and its mapping/statement grammar. +- [`check_components!`](entrypoints/check_components.md) — compile-time wiring assertions. +- [`delegate_and_check_components!`](entrypoints/delegate_and_check_components.md) — wire and check in one macro. +- [`cgp_namespace!`](entrypoints/cgp_namespace.md) — reusable, inheritable wiring tables via `RedirectLookup`. + +Type-level construction macros: + +- [`Symbol!`](entrypoints/symbol.md), [`Product!`](entrypoints/product.md), [`Sum!`](entrypoints/sum.md), [`Path!`](entrypoints/path.md) — the type-level string, list, sum, and path macros. + +Data derives: -Documented so far: +- [`#[derive(HasField)]`](entrypoints/derive_has_field.md), [`#[derive(HasFields)]`](entrypoints/derive_has_fields.md) — field-access derives. +- [`#[derive(CgpData)]`](entrypoints/derive_cgp_data.md), [`#[derive(CgpRecord)]`](entrypoints/derive_cgp_record.md), [`#[derive(CgpVariant)]`](entrypoints/derive_cgp_variant.md) — the extensible-data derives. +- [`#[derive(BuildField)]`](entrypoints/derive_build_field.md), [`#[derive(ExtractField)]`](entrypoints/derive_extract_field.md), [`#[derive(FromVariant)]`](entrypoints/derive_from_variant.md) — builder/extractor/variant support. -- [The `cgp_component` AST stack](asts/cgp_component.md) — `CgpComponentArgs`, `ItemCgpComponent`, `PreprocessedCgpComponent`, and `EvaluatedCgpComponent`. +Handlers and other extra macros: -Pending — one document per remaining evaluation stack, grouped by the macro that owns it: the `cgp_impl`, `cgp_provider`, `cgp_fn`, `cgp_type`, `cgp_getter`, `delegate_component`, `check_components`, `namespace`, `cgp_data`, `product`, and `sum` stacks, plus the shared building-block AST types (`attributes/`, `generics/`, `field/`, `getter/`, `implicits/`, `ident/`, `path/`, `keyword`). +- [`#[cgp_computer]`](entrypoints/cgp_computer.md), [`#[cgp_producer]`](entrypoints/cgp_producer.md) — define `Computer`/`Producer` providers from functions. +- [`#[cgp_auto_dispatch]`](entrypoints/cgp_auto_dispatch.md) — generate a dispatching handler. +- [`#[async_trait]`](entrypoints/async_trait.md) — rewrite trait `async fn` to `-> impl Future`. +- [The `snapshot_*!` family](entrypoints/snapshot_macros.md) — the `cgp-macro-test-util` macros that pin macro expansions as `insta` snapshots. + +### AST stacks — [asts/](asts/) + +One document per evaluation stack, grouped by the macro that owns it: + +- [cgp_component](asts/cgp_component.md), [cgp_impl](asts/cgp_impl.md), [cgp_provider](asts/cgp_provider.md), [cgp_type](asts/cgp_type.md), [cgp_fn](asts/cgp_fn.md), [cgp_getter](asts/cgp_getter.md), [blanket_trait](asts/blanket_trait.md). +- [delegate_component](asts/delegate_component.md), [check_components](asts/check_components.md), [namespace](asts/namespace.md). +- [cgp_data](asts/cgp_data.md) — the shared extensible-data derive stack. +- [product](asts/product.md), [sum](asts/sum.md), [path](asts/path.md), [symbol](asts/symbol.md) — the type-level construction stacks. +- [attributes](asts/attributes.md) — the modifier-attribute AST types (`#[uses]`, `#[use_type]`, `#[use_provider]`, `#[extend]`, `#[extend_where]`, `#[derive_delegate]`, `#[default_impl]`). ### Functions — [functions/](functions/) -Documented so far: +The cross-cutting helper functions; construct-specific parse/derive helpers are documented inside the owning macro's entrypoint or AST document. -- [Delegated-impl synthesis](functions/derive/delegated_impls.md) — `trait_items_to_delegated_impl_items` and `provider_trait_to_impl_items`, the forwarding-impl machinery. +- [Delegated-impl synthesis](functions/derive/delegated_impls.md) — the forwarding-impl machinery shared by the component impls. - [`parse_is_provider_params`](functions/parse/is_provider_params.md) — building the `IsProviderFor` params tuple from trait generics. - -Pending — the remaining helpers in `cgp-macro-core/src/functions`: identifier case conversion (`camel_case`/`snake_case`), generics merging, field/getter/implicit-argument parsing, and `strip`. +- [`merge_generics`](functions/derive/generics.md) — combining two `Generics` into one. +- [Identifier case conversion](functions/derive/idents.md) — the PascalCase/snake_case/reserved-name helpers. ### Internal macros — [macros/](macros/) -Documented so far: - - [`parse_internal!`](macros/parse_internal.md) — build a `syn` node from quoted tokens with a descriptive parse error. - [`define_keyword!`](macros/define_keyword.md) — declare a custom-keyword marker type implementing `IsKeyword`. - -Pending — the `export_construct(s)!` family in `cgp-macro-core/src/macros` that backs the hygienic `exports.rs` markers. +- [`export_construct!` / `export_constructs!`](macros/export_constructs.md) — declare the hygienic markers backing `exports.rs`. diff --git a/docs/implementation/asts/attributes.md b/docs/implementation/asts/attributes.md new file mode 100644 index 00000000..28697be1 --- /dev/null +++ b/docs/implementation/asts/attributes.md @@ -0,0 +1,85 @@ +# The attribute-modifier AST stack + +The attribute modifiers — `#[uses]`, `#[use_type]`, `#[use_provider]`, `#[extend]`, `#[extend_where]`, `#[derive_delegate]`, and `#[default_impl]` — are not standalone macros. Each is an `#[…]` attribute that a host macro (`#[cgp_component]`, `#[cgp_impl]`, or `#[cgp_fn]`) strips off its input, parses into an AST type, and folds into the code it generates. This document covers each modifier's AST type, what it parses from, and what it injects into its host's output; for the user-facing syntax and expansion of each, read the reference documents under [reference/](../../reference/README.md) (in the `attributes/` subdirectory), and for how the hosts drive them see [entrypoints/cgp_component.md](../entrypoints/cgp_component.md), [entrypoints/cgp_impl.md](../entrypoints/cgp_impl.md), and [entrypoints/cgp_fn.md](../entrypoints/cgp_fn.md). + +The modifiers do not parse themselves out of the token stream on their own; a host collects them first. `#[cgp_component]` gathers them into a `CgpComponentAttributes`, `#[cgp_impl]` into a `CgpImplAttributes`, and `#[cgp_fn]` into a `FunctionAttributes`. Each collector walks the item's attribute list, matches the leading identifier (`uses`, `use_type`, …), parses that attribute's arguments into the corresponding AST type, and passes any unrecognized attribute through untouched onto the generated code. Which modifiers a host accepts differs — `#[derive_delegate]` and `#[prefix]` are only meaningful on a component, `#[default_impl]` only on a provider impl — so a given modifier appears in only the collectors of the hosts that consume it. + +## `#[uses]` + +`#[uses(TraitA, TraitB)]` imports `Self` trait bounds, reading like a `use` statement. It parses into `UsesAttributes`, which holds a `Vec` — one path per imported trait, accepting only the plain `Trait` form and no associated-type equality. Its `to_type_param_bounds` turns each path directly into a `TypeParamBound`, and the host appends those bounds to the generated impl's `where` clause (on `Self`), where they become impl-side dependencies. On `#[cgp_fn]` the same parsing runs through `FunctionAttributes`; on `#[cgp_impl]` through `CgpImplAttributes`. The bounds land only on the impl, never on the consumer trait, which is what keeps the dependency hidden from callers. + +## `#[use_type]` + +`#[use_type(HasErrorType::Error)]` imports an abstract type: it rewrites the bare alias everywhere and adds the owning trait as a bound. It parses into a `UseTypeAttribute` per spec, collected into a `UseTypeAttributes`. Each spec captures a context type (defaulting to `Self`, or an explicit `@Context::` foreign context), the owning trait path, and one or more type idents (with optional `as` alias and `=` equality). Application is a two-phase transform. First, the `SubstituteAbstractType` visitor rewrites every bare, single-segment, argument-free use of the alias into the fully-qualified associated type: + +```rust +// #[use_type(HasErrorType::Error)] turns a bare `Error` into: +::Error +``` + +Then the host adds the trait: on a `#[cgp_component]` trait, `transform_item_trait` pushes the trait path onto the consumer trait's supertraits (only for `Self`-context specs); on an impl, `transform_item_impl` derives the `where` predicates — `context_type: trait_path` — and extends the impl's `where` clause. The predicate derivation also resolves `as` aliases, `=` equalities, and cross-spec equalities, and rejects two specs sharing one alias. The visitor is applied in reverse spec order so earlier specs can shadow later ones. A `=` equality is rejected outright on a `#[cgp_component]` trait, since a component definition cannot pin an abstract type to a concrete one. The single-identifier-head parse of an `@Context::` prefix is deliberate: it keeps `IdentWithTypeArgs` rather than a greedy path parser, which would otherwise swallow the trailing `::Trait::Type`. + +## `#[use_provider]` + +`#[use_provider(Inner: AreaCalculator)]` completes an inner provider's bound for a higher-order provider. It parses into a `UseProviderAttribute` — a provider type, a colon, and a `+`-separated list of provider-trait paths — collected into a `UseProviderAttributes`. The one thing it does is finish each bound by inserting the context type as the leading generic argument, so the user's `: AreaCalculator` becomes `AreaCalculator`, and move the completed bound into the impl's `where` clause on the provider parameter: + +```rust +// #[use_provider(Inner: AreaCalculator)] becomes the where-predicate: +Inner: AreaCalculator +``` + +The context type is inserted at index 0 of the trait's angle-bracketed arguments, so a bound that already carries parameters keeps them after the context. On `#[cgp_impl]` the collection is `CgpImplAttributes`; on `#[cgp_fn]`, `FunctionAttributes`. There is no call-site rewriting — the body still calls the provider explicitly with the associated-function form. + +## `#[extend]` + +`#[extend(Trait)]` adds *supertrait* bounds to a generated trait. On `#[cgp_fn]` it is parsed into the `extend` field of `FunctionAttributes` — a `Vec` — and its bounds are pushed onto both the generated trait's supertraits and the impl's `where` clause, because it is the only way to add a supertrait when a `#[cgp_fn]`'s `where` clauses are reserved for impl-side dependencies. On `#[cgp_component]` it is parsed by `CgpComponentAttributes` and its bounds are appended to the consumer trait's supertraits during `preprocess`, where it is the preferred way to add a non-type capability supertrait (an abstract-type supertrait should instead use `#[use_type]`, which adds the bound *and* rewrites the type). + +## `#[extend_where]` + +`#[extend_where(Bound)]` adds `where` predicates to a generated trait definition, and is `#[cgp_fn]`-only. It parses into the `extend_where` field of `FunctionAttributes` — a `Vec` — and its predicates are added to both the trait and the impl `where` clauses. It is the escape hatch for the bounds `#[uses]` cannot spell, chiefly associated-type-equality constraints. + +## `#[derive_delegate]` + +`#[derive_delegate(UseDelegate)]` (on a `#[cgp_component]` trait) generates a dispatcher provider impl so the component can be wired to a `UseDelegate` table. It parses into a `DeriveDelegateAttribute` — a wrapper identifier (`UseDelegate`) and its angle-bracketed key, which is either a single identifier or a non-empty parenthesized tuple — collected into a `DeriveDelegateAttributes`. Its `to_provider_impl` builds one impl of the provider trait for `Wrapper<__Components__>` that forwards each method to a delegate looked up through `DelegateComponent`. The impl carries two synthetic generics and two `where` bounds — the table lookup and the delegate's provider-trait bound — and forwards each trait method through the shared delegated-impl helpers: + +```rust +impl<__Context__, __Components__, __Delegate__> AreaCalculator<__Context__> + for UseDelegate<__Components__> +where + __Components__: DelegateComponent<(Shape), Delegate = __Delegate__>, + __Delegate__: AreaCalculator<__Context__>, +{ /* each method forwards to __Delegate__ */ } +``` + +The host (`#[cgp_component]`) collects it in `CgpComponentAttributes` and emits one such impl per `#[derive_delegate]` attribute alongside the component's standard provider impls. It is a legacy form for user code — `open` dispatch is preferred — but CGP's own error and handler families still define components with it. + +## `#[default_impl]` + +`#[default_impl(@test.ShowImplComponent.u32 in ExtendedNamespace)]` (on a `#[cgp_impl]` provider) registers the provider as a namespace's default for one path. It parses into a `DefaultImplAttribute` — a key type (a path or type), the `in` keyword, and the namespace path — collected into a `DefaultImplAttributes`. Its `to_item_impl` emits one impl of the namespace's lookup trait, keyed on the given path type, whose `Delegate` associated type is the provider being defined: + +```rust +// #[default_impl(@test.ShowImplComponent.u32 in ExtendedNamespace)] on provider ShowU32: +impl<__Components__> ExtendedNamespace<__Components__> +for PathCons>> +{ + type Delegate = ShowU32; +} +``` + +The namespace path gains a trailing `__Components__` type argument and the impl generics gain a matching `__Components__` parameter, so the default is generic over any table the namespace is queried through. The host (`#[cgp_impl]`) collects it in `CgpImplAttributes` and emits one such impl per attribute after the provider impl, using the provider's own generics and provider type. + +## Tests + +The behavioral and snapshot tests that exercise each modifier are listed per attribute below; test and snapshot pointers for a construct live only in these implementation documents. + +- **`#[uses]`** — [impl_side_dependencies/fn_uses.rs](../../../crates/tests/cgp-tests/tests/impl_side_dependencies/fn_uses.rs) pins the `#[cgp_fn]` form and [impl_side_dependencies/impl_uses.rs](../../../crates/tests/cgp-tests/tests/impl_side_dependencies/impl_uses.rs) the `#[cgp_impl]` form; [generic_components/fn_impl_generics.rs](../../../crates/tests/cgp-tests/tests/generic_components/fn_impl_generics.rs) exercises it alongside generic parameters. +- **`#[use_type]`** — [abstract_types/use_type_component.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_component.rs) covers the `#[cgp_component]` supertrait form; [abstract_types/use_type_fn_alias.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_alias.rs), [use_type_fn_equality.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_equality.rs), and [use_type_fn_foreign.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_foreign.rs) cover the alias, equality, and foreign-context (`@`) forms; [use_type_fn_equality_cross_trait.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_equality_cross_trait.rs) and [use_type_fn_foreign_equality_cross_trait.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_foreign_equality_cross_trait.rs) cover cross-spec equality; [use_type_generic_param.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_generic_param.rs) covers a generic-parameter abstract type. +- **`#[use_provider]`** — [higher_order_providers/use_provider_fn.rs](../../../crates/tests/cgp-tests/tests/higher_order_providers/use_provider_fn.rs) pins the `#[cgp_fn]` form and [higher_order_providers/use_provider_impl.rs](../../../crates/tests/cgp-tests/tests/higher_order_providers/use_provider_impl.rs) the `#[cgp_impl]` form; [higher_order_providers/scaled_area.rs](../../../crates/tests/cgp-tests/tests/higher_order_providers/scaled_area.rs) wires a full higher-order provider through it. +- **`#[extend]`** — [impl_side_dependencies/fn_extend.rs](../../../crates/tests/cgp-tests/tests/impl_side_dependencies/fn_extend.rs) pins the `#[cgp_fn]` supertrait form; [abstract_types/extend_component.rs](../../../crates/tests/cgp-tests/tests/abstract_types/extend_component.rs) and [abstract_types/use_type_fn_extend.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_extend.rs) exercise it on a component and alongside `#[use_type]`; [getters/abstract_type_extend.rs](../../../crates/tests/cgp-tests/tests/getters/abstract_type_extend.rs) uses it with a getter. +- **`#[extend_where]`** — [abstract_types/use_type_fn_nested_foreign.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_nested_foreign.rs) exercises it alongside `#[use_type]` on a `#[cgp_fn]`. +- **`#[derive_delegate]`** — [dispatching/use_delegate_getter.rs](../../../crates/tests/cgp-tests/tests/dispatching/use_delegate_getter.rs) wires a component defined with `#[derive_delegate]` through a `UseDelegate` table. +- **`#[default_impl]`** — [namespaces/default_impls.rs](../../../crates/tests/cgp-tests/tests/namespaces/default_impls.rs) pins the emitted namespace-default impl (`snapshot_cgp_impl!`), and [namespaces/default_impls_wiring.rs](../../../crates/tests/cgp-tests/tests/namespaces/default_impls_wiring.rs) checks a context picks up the default. + +## Source + +The modifiers live in [cgp-macro-core/src/types/attributes/](../../../crates/macros/cgp-macro-core/src/types/attributes/): `uses.rs` (`UsesAttributes`), the `use_type/` submodule (`UseTypeAttribute`, per-type entries in `ident.rs`, the two-phase transform in `attributes.rs`, and predicate derivation in `type_predicates.rs`), the `use_provider/` submodule (`UseProviderAttribute` and its bound completion), the `derive_delegate/` submodule (`DeriveDelegateAttribute::to_provider_impl`), and the `default_impl/` submodule (`DefaultImplAttribute::to_item_impl`). `#[extend]`/`#[extend_where]` are fields of `FunctionAttributes` in `function.rs`. The host collectors are `CgpComponentAttributes` in `cgp_component_attributes.rs`, `CgpImplAttributes` in `cgp_impl_attributes.rs`, and `FunctionAttributes` in `function.rs`. The abstract-type substitution is the `SubstituteAbstractType` visitor in [cgp-macro-core/src/visitors/substitute_abstract_type.rs](../../../crates/macros/cgp-macro-core/src/visitors/substitute_abstract_type.rs), and the `#[derive_delegate]` forwarding bodies come from the [delegated-impl helpers](../functions/derive/delegated_impls.md). diff --git a/docs/implementation/asts/blanket_trait.md b/docs/implementation/asts/blanket_trait.md new file mode 100644 index 00000000..dcd5c09f --- /dev/null +++ b/docs/implementation/asts/blanket_trait.md @@ -0,0 +1,24 @@ +# The `blanket_trait` AST stack + +The `blanket_trait` stack is a single type. `#[blanket_trait]` has no multi-stage pipeline and no bespoke argument type — the entry function parses the optional context identifier and a `syn::ItemTrait` directly — so all the codegen lives in `ItemBlanketTrait`, whose `to_items` emits the trait unchanged plus one generated blanket impl. This document covers that type; the [entrypoint document](../entrypoints/blanket_trait.md) covers the shape of the items it produces. + +## `ItemBlanketTrait` + +`ItemBlanketTrait` holds the context identifier and the parsed trait, and does everything in `to_items`, which returns the cloned input trait followed by the impl built by `to_item_impl`. Because the trait is emitted verbatim, its default bodies and supertraits survive into the output untouched; the derivation is entirely on the impl. + +`to_item_impl` walks the trait's items once to build the blanket impl. It first collects the associated-type identifiers and runs a `RemoveSelfPathVisitor` over the whole trait to rewrite `Self::` references to the bare parameter name, then processes each item by kind: + +- a **type** contributes a `type = ;` assignment (from the lifted parameter), a new impl generic parameter, and — if it declared bounds — a `: ` predicate collected before its default is stripped; +- a **method** contributes an impl method whose body is the trait's default block, erroring if the default is absent; +- a **const** contributes an impl constant whose expression is the trait's default, erroring if the default is absent; +- any other item is rejected as unsupported. + +It then assembles the impl generics — the trait's own generics, plus the context parameter, plus one parameter per associated type — and builds the `where` clause: a single `#context: ` predicate carrying the trait's supertraits as the hidden dependency, followed by the collected associated-type bounds. The impl targets the trait (with the trait's own type generics) for the context type. The [entrypoint document](../entrypoints/blanket_trait.md) shows the resulting shapes. + +## Tests + +- `ItemBlanketTrait` is exercised end-to-end by the expansion snapshots indexed in the [entrypoint document's Snapshots section](../entrypoints/blanket_trait.md); the missing-default-body error path has no dedicated `cgp-macro-tests` failure case yet. + +## Source + +`ItemBlanketTrait` lives in [cgp-macro-core/src/types/blanket_trait.rs](../../../crates/macros/cgp-macro-core/src/types/blanket_trait.rs). The `Self::`-to-parameter rewriting is done by `RemoveSelfPathVisitor` in [cgp-macro-core/src/visitors/remove_self_path.rs](../../../crates/macros/cgp-macro-core/src/visitors/remove_self_path.rs). diff --git a/docs/implementation/asts/cgp_component.md b/docs/implementation/asts/cgp_component.md index 4f6e3781..19cdd393 100644 --- a/docs/implementation/asts/cgp_component.md +++ b/docs/implementation/asts/cgp_component.md @@ -1,39 +1,37 @@ # The `cgp_component` AST stack -The `cgp_component` stack is the sequence of AST types that `#[cgp_component]` parses into and transforms through — the argument types, then the three pipeline stages `ItemCgpComponent`, `PreprocessedCgpComponent`, and `EvaluatedCgpComponent`. Each stage is a plain struct holding the data the next stage needs, and each transform is a method on one stage returning the next. This document describes the types; the [entrypoint document](../entrypoints/cgp_component.md) describes how the macro drives them, and the [reference document](../../reference/macros/cgp_component.md) describes the user-facing result. - -The stack flows in one direction: `CgpComponentArgs` and a `syn::ItemTrait` combine into `ItemCgpComponent`, which `preprocess`es into `PreprocessedCgpComponent`, which `eval`s into `EvaluatedCgpComponent`, which finally `to_items` renders into a `Vec`. Only the argument types implement `Parse`; the stage types are constructed programmatically and carry the transform methods rather than a `ToTokens` impl. +The `cgp_component` stack is the sequence of AST types that `#[cgp_component]` parses into and transforms through: the argument types, then the three pipeline stages `ItemCgpComponent`, `PreprocessedCgpComponent`, and `EvaluatedCgpComponent`. Each stage is a plain struct holding what the next stage needs, and the data flows in one direction — args plus a `syn::ItemTrait` become `ItemCgpComponent`, which `preprocess`es, then `eval`s, then `to_items` renders to a `Vec`. The [entrypoint document](../entrypoints/cgp_component.md) covers what each stage produces; this document covers the types. ## `CgpComponentRawArgs` and `CgpComponentArgs` -`CgpComponentArgs` is the parsed, defaulted form of the attribute argument, and `CgpComponentRawArgs` is the intermediate that captures exactly what the user wrote before defaults are applied. The split exists so parsing and defaulting are separate concerns: `CgpComponentRawArgs` holds three `Option`s (`context_ident`, `provider_ident`, `component_name`), and `CgpComponentArgs` holds the same three fields resolved to concrete values. +The attribute argument is parsed in two steps so that parsing and defaulting stay separate. `CgpComponentRawArgs` captures exactly what the user wrote as three `Option`s; `CgpComponentArgs` is the same three fields resolved to concrete values. -`CgpComponentRawArgs::parse` (in `args/raw.rs`) accepts the two attribute forms. When the input is a single token followed by end-of-input (`peek2(End)`), it is the bare-identifier form and that token is the `provider_ident`. Otherwise it parses a comma-separated sequence of `key: value` pairs, matching the key string against `name`, `context`, and `provider`, rejecting a duplicate key with "duplicate key is not allowed" and an unknown key with "unknown key {key}". The `name` value parses as an [`IdentWithTypeGenerics`](../asts/cgp_component.md) so a component name may carry generic parameters, while `context` and `provider` parse as bare `Ident`s. +`CgpComponentRawArgs` accepts either a bare provider identifier or a comma-separated `key: value` list over the keys `name`, `context`, and `provider`, rejecting a duplicate or unknown key: -`CgpComponentArgs` is produced from the raw form through `TryFrom` (in `args/component_args.rs`), which applies the defaults the reference documents describe: `provider_ident` is required and errors with "`provider_ident` key must be given" when absent, `context_ident` defaults to `Ident::new("__Context__", …)`, and `component_name` defaults to the provider identifier with a `Component` suffix. `CgpComponentArgs` implements `Parse` by parsing a `CgpComponentRawArgs` and delegating to this `TryFrom`, so the entry function can `syn::parse2` the attribute directly into the defaulted form. +```rust +#[cgp_component(AreaCalculator)] // bare form +#[cgp_component { provider: AreaCalculator, context: Cx }] // keyed form +``` -## `ItemCgpComponent` +`CgpComponentArgs` is produced from the raw form by a `TryFrom` that applies the defaults: `provider` is required, `context` defaults to `__Context__`, and `name` defaults to the provider identifier with a `Component` suffix. Its `Parse` impl just parses the raw form and runs that conversion, so the entry function can parse the attribute straight into the defaulted type. -`ItemCgpComponent` is the raw input stage — the parsed attribute and the parsed trait, before any CGP attributes are stripped. It holds `args: CgpComponentArgs` and `item_trait: syn::ItemTrait`, and the entry function constructs it directly from the two `syn::parse2` results. +## `ItemCgpComponent` -Its one method, `preprocess`, calls `CgpComponentAttributes::preprocess` on the trait to split the CGP modifier attributes off the plain trait, then returns a `PreprocessedCgpComponent` carrying the cloned args, the cleaned trait, and the parsed attributes. It generates no code; it only normalizes the trait so later stages see a plain `syn::ItemTrait` and a separate, structured record of the attributes that modify the output. +`ItemCgpComponent` is the raw input stage — the parsed args and trait before any CGP attributes are stripped. Its `preprocess` step splits the CGP modifier attributes off the trait and hands the cleaned trait, the args, and the parsed attributes to the next stage, so later stages see a plain `syn::ItemTrait` alongside a structured record of the attributes that modify the output. ## `PreprocessedCgpComponent` -`PreprocessedCgpComponent` is the stage that owns the core derivation. It holds `args`, the preprocessed `item_trait`, and `attributes: CgpComponentAttributes`, and it carries the methods that build the provider trait, the two blanket impls, and the component struct. - -Its `eval` method orchestrates the derivation: it calls `to_component_struct` for the `EmptyStruct` marker, `to_provider_trait_and_blanket_impl` for the provider trait paired with its blanket impl, and `to_consumer_item_impl` for the consumer blanket impl, then packages all of these with the original consumer trait, the attributes, and the args into an `EvaluatedCgpComponent`. The individual builders are `to_provider_trait` (the provider trait, with `self`/`Self` rewritten and supertraits lowered to context `where` predicates), `to_provider_trait_and_blanket_impl` (which reuses `to_provider_trait` and adds the `__Provider__` blanket impl), `to_consumer_item_impl` (the `__Context__` consumer impl), and `to_component_struct` (the marker). The [entrypoint document's Generated items section](../entrypoints/cgp_component.md) describes precisely what each builder emits; the key structural point is that the provider trait is built once and shared, so the trait and its blanket impl cannot disagree. +`PreprocessedCgpComponent` owns the core derivation. It holds the args, the preprocessed trait, and the attributes, and its `eval` step derives the provider trait, the two blanket impls, and the component marker struct, packaging them into the final stage. The one structural point worth knowing is that the provider trait is built once and shared with its blanket impl, so the trait and the impl cannot disagree; the shapes they produce are described in the [entrypoint document](../entrypoints/cgp_component.md). ## `EvaluatedCgpComponent` -`EvaluatedCgpComponent` is the final stage — a bag of all the derived items plus the context needed to render the standard provider impls. Its fields are the `component_struct` (an `EmptyStruct`), the `consumer_trait`, `consumer_impl`, `provider_trait`, and `provider_impl`, plus the `args` and `attributes` carried through for the provider-impl builders. - -Its `to_items` method fixes the emission order — consumer trait, consumer impl, provider trait, provider impl, component struct — then appends the provider impls from `to_item_impls`. `to_item_impls` gathers the provider impls (`to_provider_impls`) and the prefix impls (`to_prefix_impls`). `to_provider_impls` always emits the `UseContext` impl (`to_use_context_impl`) and the `RedirectLookup` impl (`to_redirect_lookup_impl`), then one `UseDelegate` impl per `#[derive_delegate]` attribute (`to_use_delegate_impls`); `to_prefix_impls` emits one namespace impl per `#[prefix]` attribute. The provider impls are collected as `ItemProviderImpl`s (each pairing the impl with its component type) and rendered through `ItemProviderImpls::to_item_impls`. +`EvaluatedCgpComponent` is the final stage — a bag of all the derived items plus the args and attributes needed to render the standard provider impls. Its `to_items` step emits the five core items in fixed order and then appends the provider impls: always the `UseContext` and `RedirectLookup` impls, plus one `UseDelegate` impl per `#[derive_delegate]` attribute and one prefix impl per `#[prefix]` attribute. ## Tests -The argument parser's rejection of a non-trait item is pinned in [cgp-macro-tests/tests/parser_rejections/cgp_component.rs](../../../crates/tests/cgp-macro-tests/tests/parser_rejections/cgp_component.rs). The stage transforms are exercised end-to-end through the expansion snapshots indexed in the [entrypoint document's Snapshots section](../entrypoints/cgp_component.md) — the plain, supertrait/default-method, lifetime, and namespace variants each pin the output of the full `preprocess → eval → to_items` sequence. +- [cgp-macro-tests/tests/parser_rejections/cgp_component.rs](../../../crates/tests/cgp-macro-tests/tests/parser_rejections/cgp_component.rs) pins the argument/trait parser's rejection of a non-trait item. +- The stage transforms are exercised end-to-end by the expansion snapshots indexed in the [entrypoint document's Snapshots section](../entrypoints/cgp_component.md). ## Source -The stack lives in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/): the argument types in `args/`, `ItemCgpComponent` in `item.rs`, `PreprocessedCgpComponent` and its builders in `preprocessed/`, and `EvaluatedCgpComponent` and the provider-impl builders in `evaluated/`. The `EmptyStruct`, `ItemProviderImpl`, and `CgpComponentAttributes` helper types live in sibling `types/` modules; the visitors that rewrite `self`/`Self` live in [cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). +The stack lives in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/): the argument types in `args/`, `ItemCgpComponent` in `item.rs`, `PreprocessedCgpComponent` in `preprocessed/`, and `EvaluatedCgpComponent` in `evaluated/`. The `self`/`Self` rewriting is done by the visitors in [cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). diff --git a/docs/implementation/asts/cgp_data.md b/docs/implementation/asts/cgp_data.md new file mode 100644 index 00000000..eeb1d7d4 --- /dev/null +++ b/docs/implementation/asts/cgp_data.md @@ -0,0 +1,52 @@ +# The `cgp_data` AST stack + +The `cgp_data` stack is the small family of AST types that every extensible-data derive parses into before the shared codegen takes over: `ItemCgpData`, `ItemCgpRecord`, `ItemCgpVariant`, and the field-tag types (`Symbol`, `Index`, `FieldName`, `HasFieldBound`) that name each field. Unlike the [`cgp_component` stack](cgp_component.md), there is no multi-stage `preprocess → eval → to_items` transform here: each of the eight data derives parses its input into one of these types and then calls a `to_*` method that composes free codegen helpers into a `Vec`. This document covers the types; the per-derive entrypoint documents ([`derive_has_field`](../entrypoints/derive_has_field.md), [`derive_has_fields`](../entrypoints/derive_has_fields.md), [`derive_cgp_data`](../entrypoints/derive_cgp_data.md), [`derive_build_field`](../entrypoints/derive_build_field.md), [`derive_extract_field`](../entrypoints/derive_extract_field.md), [`derive_from_variant`](../entrypoints/derive_from_variant.md)) cover what each generated item looks like. + +The organizing idea is that a *record* is a struct and a *variant* is an enum, and the two shapes drive disjoint codegen: a record produces field getters, the `HasFields` product, and the incremental builder; a variant produces the `HasFields` sum, the `FromVariant` constructors, and the incremental extractor. `ItemCgpRecord` and `ItemCgpVariant` are the two shape-specific types, `ItemCgpData` is the union that dispatches on shape, and the field-tag types are shared by both because every field — named struct field, tuple field, or enum variant — is addressed by the same kind of type-level tag. + +## `ItemCgpData` + +`ItemCgpData` is the shape-dispatching wrapper that backs `#[derive(CgpData)]`. It is an enum of `Record(ItemCgpRecord)` or `Variant(ItemCgpVariant)`, and its `Parse` impl parses a `syn::Item` and routes a `struct` to the record arm and an `enum` to the variant arm, rejecting anything else with "expect body to be either a struct or enum". Its only method, `to_items`, forwards to the wrapped `ItemCgpRecord::to_items` or `ItemCgpVariant::to_items`, so `CgpData` on a struct emits exactly what `CgpRecord` emits and `CgpData` on an enum exactly what `CgpVariant` emits. + +## `ItemCgpRecord` + +`ItemCgpRecord` wraps a `syn::ItemStruct` and owns all struct-shape codegen. It is a thin struct — just `item_struct` — that exposes one method per slice of the record output plus a `to_items` that concatenates them: + +- `to_has_field_impls` — the per-field `HasField`/`HasFieldMut` getters, via `derive_has_field_impls_from_struct`. This is what `#[derive(HasField)]` calls. +- `to_has_fields_impls` — the five representation impls (`HasFields`, `HasFieldsRef`, `FromFields`, `ToFields`, `ToFieldsRef`), via `derive_has_fields_impls_from_struct`. This is the struct path of `#[derive(HasFields)]`. +- `to_build_field_items` — the incremental builder: the `__Partial{Name}` struct and its trait impls. This is what `#[derive(BuildField)]` calls. +- `to_items` — the full `#[derive(CgpRecord)]`/`#[derive(CgpData)]`-on-struct output: the getters, then the representation impls, then the builder items, in that order. + +The builder method names the partial companion struct `__Partial{ContextName}` and composes the helpers in the [`derive_builder/`](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/) submodule in a fixed order (builder struct, `HasBuilder`, `IntoBuilder`, `PartialData`, `FinalizeBuild`, then the per-field `UpdateField` and `HasField` impls). `#[derive(HasField)]`, `#[derive(HasFields)]`, `#[derive(BuildField)]`, `#[derive(CgpRecord)]`, and the struct path of `#[derive(CgpData)]` all construct an `ItemCgpRecord` and call one of these methods, which is why they never disagree about the shape they emit. + +## `ItemCgpVariant` + +`ItemCgpVariant` wraps a `syn::ItemEnum` and owns all enum-shape codegen, mirroring `ItemCgpRecord`: + +- `to_has_fields_impls` — the five representation impls over a *sum* rather than a product, via `derive_has_fields_impls_from_enum`. This is the enum path of `#[derive(HasFields)]`. +- `to_from_variant_impls` — the per-variant `FromVariant` constructors, via `derive_from_variant_from_enum`. This is what `#[derive(FromVariant)]` calls. +- `to_extract_field_items` — the incremental extractor: the `__Partial{Name}` and `__PartialRef{Name}` enums and their trait impls. This is what `#[derive(ExtractField)]` calls. +- `to_items` — the full `#[derive(CgpVariant)]`/`#[derive(CgpData)]`-on-enum output: the representation impls, then the `FromVariant` constructors, then the extractor items. + +The extractor method names two partial companion enums, `__Partial{ContextName}` (owned) and `__PartialRef{ContextName}` (borrowed), and drives most extractor helpers twice — once for each — passing a `bool` that selects the borrowed form. That is why the borrowed extractor mirrors the owned one and both stay in sync with the owned/ref pair. `#[derive(HasFields)]` on an enum, `#[derive(FromVariant)]`, `#[derive(ExtractField)]`, `#[derive(CgpVariant)]`, and the enum path of `#[derive(CgpData)]` all construct an `ItemCgpVariant` and call one of these methods. + +## `Symbol`, `Index`, and `FieldName` + +The field-tag types decide how a field is named at the type level, and every data derive routes its field identifiers through them. A named field or an enum variant is keyed by a `Symbol` — a type-level string — and a tuple-struct field is keyed by an `Index` — a type-level natural number of its position. + +`Symbol` holds the field's identifier as a `String` and, on `ToTokens`, emits the full type-level spelling `Symbol>` where `N` is the character count and the `Chars` cons-list carries the characters. So the field name `foo` expands to `Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>`; the leading length works around the absence of const generics over strings. `Index` holds a `usize` position and emits `Index`. `FieldName` is the enum that unifies the two — `Ident(Symbol)` or `Index(Index)` — so a helper that walks a struct's fields does not care whether they are named or positional; it converts each `Member` to a `FieldName` and lets `ToTokens` pick the right spelling. + +```rust +// a named field a tuple field +Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>> Index<0> +``` + +`HasFieldBound` is the small companion that renders a `HasField`/`HasFieldMut` bound (`HasField`), used where the codegen needs to write such a bound as a `where`-clause fragment rather than as a full impl. + +## Tests + +The stack has no parser-rejection tests of its own in `cgp-macro-tests`; the shape errors it raises (a non-struct/non-enum for `CgpData`, a non-struct for the record derives, a non-enum for the variant derives, and a non-single-field variant for the extractor and `FromVariant`) surface at `syn::parse2` or in the codegen helpers and are exercised only implicitly. The stage transforms are exercised end-to-end by the expansion snapshots indexed in the entrypoint documents' Snapshots sections — the [`snapshot_derive_has_field`](../entrypoints/derive_has_field.md#snapshots), [`snapshot_derive_has_fields`](../entrypoints/derive_has_fields.md#snapshots), and [`snapshot_derive_cgp_data`](../entrypoints/derive_cgp_data.md#snapshots) families. + +## Source + +The stack lives in [crates/macros/cgp-macro-core/src/types/cgp_data/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/): `ItemCgpData` in `item.rs`, `ItemCgpRecord` in `record.rs`, and `ItemCgpVariant` in `variant.rs`. The record codegen helpers are under `derive_has_field.rs`, `derive_has_fields/`, and `derive_builder/`; the variant codegen helpers under `derive_has_fields/`, `derive_from_variant.rs`, and `derive_extractor/`. The field-tag types are in [crates/macros/cgp-macro-core/src/types/field/](../../../crates/macros/cgp-macro-core/src/types/field/): `Symbol` in `symbol.rs`, `Index` in `index.rs`, `FieldName` in `field_name.rs`, and `HasFieldBound` in `has_field_bound.rs`. The runtime traits these impls satisfy are defined in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). diff --git a/docs/implementation/asts/cgp_fn.md b/docs/implementation/asts/cgp_fn.md new file mode 100644 index 00000000..578e189b --- /dev/null +++ b/docs/implementation/asts/cgp_fn.md @@ -0,0 +1,38 @@ +# The `cgp_fn` AST stack + +The `cgp_fn` stack is the short sequence of AST types that `#[cgp_fn]` parses into and transforms through: the raw `ItemCgpFn` and the `PreprocessedItemCgpFn` it normalizes into. Data flows in one direction — an optional trait-name `Ident` plus a `syn::ItemFn` become `ItemCgpFn`, which `preprocess`es into `PreprocessedItemCgpFn`, whose `to_items` renders the trait and blanket impl to a `Vec`. The [entrypoint document](../entrypoints/cgp_fn.md) covers what each stage produces; this document covers the types and the implicit-argument helpers they lean on. + +## `ItemCgpFn` + +`ItemCgpFn` is the raw input stage — the parsed attribute identifier and function before any normalization. Its only field beyond the function is the optional trait-name `Ident`, left `None` when the user wrote `#[cgp_fn]` with no argument. + +Its `preprocess` step does all the up-front work that the emit stage assumes is already done. It resolves the trait name (the attribute identifier, or the function name run through `to_camel_case_str` to PascalCase), moves the function's visibility aside so the trait can carry it, extracts the `#[implicit]` arguments and prepends their field-reading `let` bindings to the body, parses the companion attributes into a `FunctionAttributes` record, and takes the function's generics out into a separate field. Everything it produces is packaged into `PreprocessedItemCgpFn`. + +## `PreprocessedItemCgpFn` + +`PreprocessedItemCgpFn` owns the emit stage. It holds the resolved trait name, the normalized `ItemFn` (implicit arguments already removed, body bindings already prepended), the parsed `ImplicitArgFields`, the `FunctionAttributes`, the saved visibility, and the saved generics. Its `to_items` produces the two output items by calling `to_item_trait` and `to_item_impl`. + +`to_item_trait` builds the trait: it wraps the function's signature as a `TraitItemFn` with no body, applies the saved generics (dropping the `where` clause, which is impl-side only), extends the supertraits with the `#[extend(...)]` bounds, adds any `#[extend_where(...)]` predicates to the trait's own `where` clause, runs the `#[use_type]` transform, re-attaches the raw attributes, and sets the saved visibility. `to_item_impl` builds the blanket impl: it emits `impl #ident #type_generics for __Context__` with the full function body, inserts `__Context__` as the leading generic parameter, appends any `#[impl_generics(...)]` parameters, then layers the `where` clause — first the `#[uses]`/`#[extend]` bounds as a `Self: …` predicate, then the `#[extend_where]` predicates, then the implicit `HasField` bounds last, and finally the `#[use_type]`/`#[use_provider]` transforms. + +The ordering here is the contract the snapshots pin: the implicit-argument bounds are always appended after the attribute-contributed predicates, so a reader of a generated impl sees user-declared dependencies before field requirements. + +## Implicit arguments: `ImplicitArgFields` and `ImplicitArgField` + +The implicit-argument types are shared building blocks that `#[cgp_fn]` and `#[cgp_impl]` both use, so they live under `types/implicits/` rather than in the `cgp_fn` module. An `ImplicitArgField` records one extracted argument — its field name, the field type to require, the receiver mutability, the field mode (the conversion to apply), and the original argument type — and `ImplicitArgFields` is the collected list. + +The extraction is driven by `extract_and_parse_implicit_args`, which pulls every `#[implicit]`-marked argument out of a signature's inputs and parses each into an `ImplicitArgField`. `ImplicitArgField` then contributes in two directions: `to_has_field_bound` produces the `HasField`/`HasFieldMut` bound the impl requires, and `to_statement` produces the `let #name: #arg_type = self.get_field(...) ;` binding that `prepend_to_block` splices onto the front of the body. The conversion is chosen by `parse_field_type`, the same field-mode logic the getter macros use. + +```rust +// for `#[implicit] name: &str` on `&self`, to_statement produces: +let name: &str = self.get_field(PhantomData::).as_str(); +``` + +`ImplicitArgFields` also carries `extract_from_impl_items`, used by `#[cgp_impl]` to collect implicit arguments across all methods of a provider impl and deduplicate them; `#[cgp_fn]` uses only the single-function `extract_and_parse_implicit_args` path. + +## Tests + +The stage transforms are exercised end-to-end by the expansion snapshots indexed in the [entrypoint document's Snapshots section](../entrypoints/cgp_fn.md); there is no separate parser-rejection test file for `#[cgp_fn]` in `cgp-macro-tests`. The `&mut self`-with-multiple-implicits rejection and the mutable-pattern rejection enforced during extraction are currently unpinned by any test. + +## Source + +The stack lives in [cgp-macro-core/src/types/cgp_fn/](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/): `ItemCgpFn` and its `preprocess` in `item.rs`, `PreprocessedItemCgpFn` and its `to_item_trait`/`to_item_impl` in `preprocessed.rs`. The implicit-argument types are in [cgp-macro-core/src/types/implicits/](../../../crates/macros/cgp-macro-core/src/types/implicits/) and their extraction in [cgp-macro-core/src/functions/implicits/](../../../crates/macros/cgp-macro-core/src/functions/implicits/); the field-mode conversion (`parse_field_type`) is in [cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), shared with the getter stack in [asts/cgp_getter.md](cgp_getter.md). Companion-attribute parsing is in [cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs). diff --git a/docs/implementation/asts/cgp_getter.md b/docs/implementation/asts/cgp_getter.md new file mode 100644 index 00000000..b5e26640 --- /dev/null +++ b/docs/implementation/asts/cgp_getter.md @@ -0,0 +1,37 @@ +# The `cgp_getter` and `cgp_auto_getter` AST stack + +This stack covers the two getter macros together, because they share the getter-field parsing and the field-mode conversions and differ only in what they emit around a common getter-method body. `#[cgp_auto_getter]` parses a trait into `ItemCgpAutoGetter` and emits one blanket impl; `#[cgp_getter]` reuses the whole `#[cgp_component]` pipeline to produce an `EvaluatedCgpComponent`, wraps it in `ItemCgpGetter`, and appends three field-reading provider impls. Both feed on the shared `GetterField` parser and the `getter/` field-mode types. The two [entrypoint documents](../entrypoints/cgp_getter.md) cover what each stage produces; this document covers the types. + +## Shared getter-field parsing: `GetterField` and `parse_getter_fields` + +Both macros turn a getter trait's methods into `GetterField`s through the shared `parse_getter_fields` helper, which is the single source of truth for what a getter signature means. A `GetterField` records the field name (the method name), the field type to require, the return type, the receiver mutability, an optional `PhantomData` phantom-argument type, the field mode, and the receiver mode. + +The parser enforces the getter-method contract and resolves the two shorthands a reader most needs to know. A getter method must be a plain (non-const, non-async, non-unsafe, non-generic) method whose first argument is a reference — either `&self` (`ReceiverMode::SelfReceiver`) or a typed `&SomeType` receiver (`ReceiverMode::Type`), the latter letting a getter read a field out of a type other than the context, with `Self` rewritten to the context. The return type then determines the field type and the *field mode* — the conversion the getter body applies — through the shared `parse_field_type`: a `&str` return reads a `String` field (`FieldMode::Str`, `.as_str()`), an `Option<&T>` reads `Option` (`FieldMode::OptionRef`, `.as_ref()`), a `&[T]` reads an `AsRef<[T]>` field (`FieldMode::Slice`, `.as_ref()`), an `MRef<'_, T>` wraps the borrow (`FieldMode::MRef`, `MRef::Ref(...)`), a plain `&T` is a bare `FieldMode::Reference`, and any owned return is `FieldMode::Copy` (`.clone()`). `parse_getter_fields` also extracts an optional single associated return type and checks that, when present, the trait has exactly one method whose return type matches it. + +The getter-method body itself is built by `derive_getter_method` from the `types/getter/` module, which emits `receiver.get_field(PhantomData::) ` for the field's mode; the same `FieldMode` and `GetFieldWithModeExpr` types drive the `#[implicit]` bindings in the [`cgp_fn` stack](cgp_fn.md), which is why the two families convert fields identically. + +## `ItemCgpAutoGetter` + +`ItemCgpAutoGetter` is the whole AST for `#[cgp_auto_getter]` — a single struct holding the cleaned trait. Its `preprocess` associated function strips the CGP modifier attributes off the trait (discarding them, since the auto getter has no component to configure) and keeps the trait; there is no multi-stage pipeline because the macro emits no component. + +Its `to_items` emits the trait unchanged plus one blanket impl, built by `to_blanket_impl` → `derive_blanket_impl`. That impl fixes the context type to `__Context__`, adds each getter method reading its like-named field, and requires the corresponding `HasField` bound; a trait supertrait becomes a `__Context__: Supertrait` predicate, a trait generic parameter is preserved onto the impl, and a single associated return type is added as an extra parameter set to itself with its bounds carried over. The shape of the emitted impl is shown in the [entrypoint document](../entrypoints/cgp_auto_getter.md). + +## `EvaluatedCgpComponent` (reused) and `ItemCgpGetter` + +`#[cgp_getter]` produces no getter-specific parse stage of its own; it drives the `#[cgp_component]` pipeline to an `EvaluatedCgpComponent` (documented in the [`cgp_component` AST stack](cgp_component.md)) and then wraps that in `ItemCgpGetter`. The `TryFrom` conversion is where the getter fields are parsed: it runs `parse_getter_fields` over the consumer trait and stores the resulting `GetterField`s and optional associated type alongside the evaluated component. + +`ItemCgpGetter`'s `to_items` emits the component's own items first — the five core items plus the standard `UseContext`/`RedirectLookup` provider impls — and then appends the three getter-specific provider impls, each carrying its own `IsProviderFor` impl: + +- `to_use_fields_impl` builds the `UseFields` impl, keyed by method name: for each field it emits the getter-method body reading `Symbol!("field_name")` and requires the matching `HasField` bound on the receiver type. Always emitted. +- `to_use_field_impl` builds the `UseField<__Tag__>` impl, where `__Tag__` is a *free* generic parameter added to the impl generics, so the getter reads whatever field the wiring supplies. Emitted only for a single-getter trait. +- `to_with_provider_impl` builds the `WithProvider<__Provider__>` impl, which delegates field access to an inner `FieldGetter`/`MutFieldGetter` provider (a slice field uses an `AsRef<[T]>`-valued bound). Emitted only for a single-getter trait. + +Each of these threads the optional associated type through as an extra generic parameter, exactly as the auto-getter blanket impl does, keeping the three impls consistent with the consumer trait. + +## Tests + +The stage transforms are exercised end-to-end by the expansion snapshots indexed in the two entrypoint documents' Snapshots sections — the [`#[cgp_getter]` snapshots](../entrypoints/cgp_getter.md) and the [`#[cgp_auto_getter]` snapshots](../entrypoints/cgp_auto_getter.md). There is no separate parser-rejection test file for either macro in `cgp-macro-tests`; the getter-method contract checks in `parse_getter_fields` (rejecting const/async/unsafe/generic getters, a bad receiver, or multiple associated types) are currently unpinned by dedicated failure cases. + +## Source + +The auto-getter stack lives in [cgp-macro-core/src/types/cgp_auto_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_auto_getter/) (`item.rs`, `blanket.rs`), driven by [cgp-macro-lib/src/cgp_auto_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs) and documented in [entrypoints/cgp_auto_getter.md](../entrypoints/cgp_auto_getter.md). The full-getter stack lives in [cgp-macro-core/src/types/cgp_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/) (`item.rs`, `getter_field.rs`, `to_use_fields_impl.rs`, `use_field.rs`, `with_provider.rs`), driven by [cgp-macro-lib/src/cgp_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_getter.rs) and documented in [entrypoints/cgp_getter.md](../entrypoints/cgp_getter.md); it reuses the [`cgp_component` stack](cgp_component.md). The shared getter-field parser is in [cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs), the field-mode conversion in [cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), and the field-mode and getter-method emit types in [cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/). diff --git a/docs/implementation/asts/cgp_impl.md b/docs/implementation/asts/cgp_impl.md new file mode 100644 index 00000000..33f9771a --- /dev/null +++ b/docs/implementation/asts/cgp_impl.md @@ -0,0 +1,61 @@ +# The `cgp_impl` AST stack + +The `cgp_impl` stack is the sequence of AST types that `#[cgp_impl]` parses into and lowers through: the argument type `ImplArgs`, then the two lowering stages `ItemCgpImpl` and `LoweredCgpImpl`, then the `CgpProviderOrBareImpl` output that either forwards to the [`cgp_provider` stack](cgp_provider.md) or emits an untouched consumer impl. The data flows one way — args plus a `syn::ItemImpl` become `ItemCgpImpl`, which `lower`s into `LoweredCgpImpl`, which `lower`s again into `CgpProviderOrBareImpl`. The [entrypoint document](../entrypoints/cgp_impl.md) covers what each stage produces; this document covers the types. The `self`/`Self` rewrite that these stages depend on is done by the [`replace_self` visitors](#the-replace_self-visitors) described at the end. + +## `ImplArgs` + +`ImplArgs` is the parsed attribute argument: an optional `new` keyword, the provider type, and an optional `: ComponentType` override. Its `Parse` impl reads the keyword, then the provider type, then a component type if a colon follows: + +```rust +pub struct ImplArgs { + pub new: Option>, + pub provider_type: Type, + pub component_type: Option, +} +``` + +When the macro lowers to the provider stage, these fields are copied straight into a [`ProviderArgs`](cgp_provider.md#providerargs) (the `new` and `component_type` fields), and the `provider_type` becomes the `Self` type of the generated provider impl. + +## `ItemCgpImpl` + +`ItemCgpImpl` is the raw input stage — the parsed args and the `impl` block before any lowering. Its `lower` step does the attribute processing and header normalization: it parses the CGP modifier attributes off the block into a `CgpImplAttributes`, extracts `#[implicit]` parameters into `HasField` bounds on `Self`, folds `#[uses]`/`#[use_type]`/`#[use_provider]` into the impl generics and bodies, builds a delegation impl for each `#[default_impl]`, and resolves the provider trait path and context type. + +The header handling is the one structural point worth knowing. When the block has a `for` clause, the trait path is the provider trait and the block's `Self` type is the context. When the `for` clause is omitted, the block's `Self` type *is* the provider trait path, and `lower` inserts the reserved `__Context__` as the leading impl generic so the next stage always has an explicit context to move into position: + +```rust +// input, no `for` // recorded on LoweredCgpImpl +impl AreaCalculator { provider_trait_path = AreaCalculator + fn area(&self) -> f64 context_type = __Context__ + { … } item_impl generics gain a leading __Context__ +} +``` + +`lower` hands the cleaned `item_impl`, the args, the `context_type`, the `provider_trait_path`, and the `default_impls` to `LoweredCgpImpl`. + +## `LoweredCgpImpl` + +`LoweredCgpImpl` owns the consumer-to-provider rewrite. Its `lower` step branches on the provider type. For the ordinary case it calls `to_raw_item_impl` to produce a provider-trait impl and wraps it in an [`ItemCgpProvider`](cgp_provider.md#itemcgpprovider), reusing that stack's `IsProviderFor` derivation and struct emission. For the `#[cgp_impl(Self)]` case — where the provider type is the literal `Self` — it returns the original block unchanged as a bare consumer impl, requiring a `for` clause and erroring otherwise. + +`to_raw_item_impl` is where the rewrite happens: it swaps the block's `Self` type to the provider type, inserts the context type as the provider trait's leading type argument, computes the receiver identifier (the context type snake-cased and double-underscored, or the literal `__context__` when the context is not a plain identifier), and runs the three `replace_self` visitors. It first collects the block's own associated types so the type visitor skips rewriting `Self::Output` and other local associated types. + +## `CgpProviderOrBareImpl` + +`CgpProviderOrBareImpl` is the output of the second `lower` — an enum with a `Bare` variant holding the untouched consumer impl and a `Provider` variant holding a [`LoweredCgpProvider`](cgp_provider.md#loweredcgpprovider). Its `ToTokens` renders whichever variant it holds, so the `Bare` case emits a single consumer impl while the `Provider` case emits the provider impl, its `IsProviderFor` impl, and any provider struct. The entrypoint appends the `default_impls` after this. + +## The `replace_self` visitors + +Three `VisitMut` passes in [cgp-macro-core/src/visitors/replace_self/](../../../crates/macros/cgp-macro-core/src/visitors/replace_self/) perform the rewrite that turns consumer-style syntax into provider-style, and they run in this order: + +- **`ReplaceSelfTypeVisitor`** rewrites the `Self` type to the context type and `Self::Foo` paths to `Context::Foo`, but skips any path whose associated type is in the block's local associated-type list, so a trait's own `Self::Output` is left intact. It handles macro bodies at the token level too, since `VisitMut` does not see inside a `macro!( … )`. +- **`ReplaceSelfReceiverVisitor`** rewrites the method receiver into an explicit context parameter, preserving the reference and mutability shape: `&self` becomes `ctx: &Context`, `&mut self` becomes `ctx: &mut Context`, `self` becomes `ctx: Context`, and a lifetime on the receiver is carried onto the parameter type. +- **`ReplaceSelfValueVisitor`** rewrites every `self` *value* expression to the context identifier, again descending into macro bodies at the token level, and stops at nested `fn` items since they do not capture the outer `self`. + +The receiver identifier and the context type these visitors substitute are the ones `to_raw_item_impl` computed. The same visitors are not used by the [`cgp_provider` stack](cgp_provider.md), which already receives provider-form input. + +## Tests + +- The stage transforms are exercised end-to-end by the `snapshot_cgp_impl!` expansion snapshots and the behavioral tests indexed in the [entrypoint document](../entrypoints/cgp_impl.md). + +## Source + +The stack lives in [cgp-macro-core/src/types/cgp_impl/](../../../crates/macros/cgp-macro-core/src/types/cgp_impl/): `ImplArgs` in `args.rs`, `ItemCgpImpl` in `item.rs`, `LoweredCgpImpl` and `to_raw_item_impl` in `lowered.rs`, and `CgpProviderOrBareImpl` in `provider_or_bare.rs`. The companion-attribute parsing is in [cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs), and the `self`/`Self` rewriting in [cgp-macro-core/src/visitors/replace_self/](../../../crates/macros/cgp-macro-core/src/visitors/replace_self/). The provider stage this stack hands off to is documented in [asts/cgp_provider.md](cgp_provider.md). diff --git a/docs/implementation/asts/cgp_provider.md b/docs/implementation/asts/cgp_provider.md new file mode 100644 index 00000000..95e36af8 --- /dev/null +++ b/docs/implementation/asts/cgp_provider.md @@ -0,0 +1,63 @@ +# The `cgp_provider` AST stack + +The `cgp_provider` stack is the sequence of AST types that both [`#[cgp_provider]`](../entrypoints/cgp_provider.md) and [`#[cgp_new_provider]`](../entrypoints/cgp_new_provider.md) parse into and lower through — the two macros share this stack entirely and differ only in whether the `new` keyword is set. The argument type `ProviderArgs` and a `syn::ItemImpl` become an `ItemCgpProvider`, whose single `lower` step derives the `IsProviderFor` impl (via `ItemProviderImpl`) and the provider struct (via `EmptyStruct`), packaging all three items into a `LoweredCgpProvider` that renders them. The argument-splitting helper `ProviderImplArgs` supports the `IsProviderFor` derivation. The [`#[cgp_provider]` entrypoint](../entrypoints/cgp_provider.md) covers what the stage produces; this document covers the types. + +## `ProviderArgs` + +`ProviderArgs` is the parsed attribute argument, shared by both macros: an optional `new` keyword and an optional component-type override. + +```rust +pub struct ProviderArgs { + pub new: Option>, + pub component_type: Option, +} +``` + +`#[cgp_provider]` parses it as written; `#[cgp_new_provider]` parses it and then forces `new` to `Some`. When [`#[cgp_impl]`](cgp_impl.md#implargs) lowers to this stack, it constructs a `ProviderArgs` from its own `ImplArgs`, copying the `new` and `component_type` fields. + +## `ItemCgpProvider` + +`ItemCgpProvider` is the input stage — the args and the provider-trait impl. Its `lower` step drives the whole macro in one pass, delegating to three helpers on itself: + +- `component_type` derives the component: it reads the provider trait's identifier and appends `Component` (so `AreaCalculator` → `AreaCalculatorComponent`), unless the attribute supplied an explicit override. +- `ItemProviderImpl::to_is_provider_for_impl` derives the `IsProviderFor` impl. +- `to_provider_struct` derives the provider struct, returning `None` when `new` is unset. + +It packages the original `item_impl` (emitted verbatim), the derived `IsProviderFor` impl, and the optional struct into a `LoweredCgpProvider`. + +## `ItemProviderImpl` and the `IsProviderFor` derivation + +`ItemProviderImpl` pairs a component type with a provider impl and derives the `IsProviderFor` marker impl from it. `to_is_provider_for_impl` clones the provider impl, clears its body, associated types, attributes, `defaultness`, and `unsafety`, and swaps the trait for `IsProviderFor` — keeping the original generic parameters and `where` clause so the marker holds under exactly the same conditions: + +```rust +// from impl ComputerRef for FirstNameToString where … +// to impl IsProviderFor +// for FirstNameToString where … {} +``` + +The trait arguments come from `ProviderImplArgs::from_generic_args`, and the derivation ends by running [`replace_provider_in_generics`](../../../crates/macros/cgp-macro-core/src/visitors/replace_provider.rs) with a map from the provider identifier to the component type, which rewrites a `Provider: SomeTrait` `where`-bound into an `IsProviderFor<…>` bound so a higher-order provider's inner-provider dependency shows up as an `IsProviderFor` obligation. + +## `ProviderImplArgs` + +`ProviderImplArgs` splits a provider trait's generic arguments into the context type and the `Params` tuple. Walking the arguments in order, it takes the first *type* argument as the context and collects the rest as `Params`; a lifetime always goes into `Params` (its `ToTokens` lifts it to `Life<'a>`) regardless of position, and a `const` argument is rejected with a spanned error. A trait path with no type argument at all is an error, since there is no context to place in the leading position. + +## `LoweredCgpProvider` + +`LoweredCgpProvider` is the output stage — a bag of the three emitted items. Its `ToTokens` renders them in order: the provider impl, the `IsProviderFor` impl, then the provider struct (which renders to nothing when `None`). + +## `EmptyStruct` + +`EmptyStruct` is the provider struct, emitted only when `new` is set. `to_provider_struct` reads the shape from the impl's `Self` type: a plain name yields a unit `pub struct Name;`, while a generic provider yields a struct whose single `PhantomData` field binds every parameter — a lifetime parameter is bound as `Life<'a>` inside the `PhantomData` tuple so the struct stays covariant and `'static`-friendly. + +```rust +// generic provider Self type SpawnAndRun +pub struct SpawnAndRun(pub ::core::marker::PhantomData<(InCode)>); +``` + +## Tests + +- The stage transforms are exercised by the `snapshot_cgp_provider!` snapshots and the behavioral tests indexed in the [`#[cgp_provider]` entrypoint document](../entrypoints/cgp_provider.md); `#[cgp_new_provider]`'s direct coverage is indexed in [its entrypoint document](../entrypoints/cgp_new_provider.md). + +## Source + +The stack lives in [cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/): `ProviderArgs` in `args.rs`, `ItemCgpProvider` and its helpers in `item.rs`, `LoweredCgpProvider` in `lower.rs`, and `ProviderImplArgs` in `provider_impl_args.rs`. The `IsProviderFor` derivation (`ItemProviderImpl`) is in [cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs), the provider struct (`EmptyStruct`) in [cgp-macro-core/src/types/empty_struct.rs](../../../crates/macros/cgp-macro-core/src/types/empty_struct.rs), and the provider-name rewrite in [cgp-macro-core/src/visitors/replace_provider.rs](../../../crates/macros/cgp-macro-core/src/visitors/replace_provider.rs). The consumer-style stack that hands off to this one is documented in [asts/cgp_impl.md](cgp_impl.md). diff --git a/docs/implementation/asts/cgp_type.md b/docs/implementation/asts/cgp_type.md new file mode 100644 index 00000000..71e8cc13 --- /dev/null +++ b/docs/implementation/asts/cgp_type.md @@ -0,0 +1,21 @@ +# The `cgp_type` AST stack + +The `cgp_type` stack is thin: `#[cgp_type]` reuses the whole [`cgp_component` AST stack](cgp_component.md) to derive the component and adds a single wrapper type, `ItemCgpType`, that carries the finished `EvaluatedCgpComponent` and appends the two abstract-type provider impls. There is no bespoke argument type — the attribute is parsed as `CgpComponentArgs`, with the provider-name default patched in the [entrypoint function](../entrypoints/cgp_type.md) before the pipeline runs. This document covers `ItemCgpType` and the `ItemProviderImpl`/`ItemProviderImpls` helpers it renders through; the [entrypoint document](../entrypoints/cgp_type.md) covers what each item produces. + +## `ItemCgpType` + +`ItemCgpType` is the final rendering stage. It holds a single field, the `EvaluatedCgpComponent` produced by the shared `preprocess → eval` pipeline, and exists only to emit the extra impls on top of the standard component output. Its `to_items` first calls the wrapped component's own `to_items` (the five core items plus the `UseContext` and `RedirectLookup` provider impls) and then extends that vector with the abstract-type impls. + +The extra impls are built by `to_item_provider_impls`, which reads the component's args, provider trait, and single associated type (via `extract_item_type_from_trait`, which also validates that the trait body is exactly one non-generic associated type) and produces two `ItemProviderImpl`s: the `UseType` impl and the `WithProvider<__Provider__>` impl. It clones the provider trait's generics for each, inserts the associated-type name (and `__Provider__` for the `WithProvider` case) as leading impl parameters, and moves any associated-type bound onto both impls with `Self::` rewritten to the free parameter. The shapes of the two impls are shown in the [entrypoint document](../entrypoints/cgp_type.md). + +## `ItemProviderImpl` and `ItemProviderImpls` + +`ItemProviderImpl` pairs one provider `syn::ItemImpl` with the component-marker type it implements, and its role in this stack is to attach the matching `IsProviderFor` impl: `to_item_impls` emits the provider impl and a companion `IsProviderFor` impl carrying the same generics and `where` clause, so the two can never disagree. `ItemProviderImpls` is just the collection of them, and its `to_item_impls` flattens the pairs into the `Vec` that `ItemCgpType::to_items` folds into the output. This pairing helper is shared with other macros that emit provider impls, so `#[cgp_type]` gets the `IsProviderFor` bookkeeping for free. + +## Tests + +- The stage is exercised end-to-end by the expansion snapshots indexed in the [entrypoint document's Snapshots section](../entrypoints/cgp_type.md); the trait-shape rejection in `extract_item_type_from_trait` has no dedicated `cgp-macro-tests` failure case yet. + +## Source + +`ItemCgpType` and `extract_item_type_from_trait` live in [cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs). The `ItemProviderImpl`/`ItemProviderImpls` helpers are in [cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs). The associated-type-bound rewriting is done by [`get_bounds_and_replace_self_assoc_type`](../../../crates/macros/cgp-macro-core/src/visitors/self_assoc_type.rs), and the shared component types are in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/), documented in [asts/cgp_component.md](cgp_component.md). diff --git a/docs/implementation/asts/check_components.md b/docs/implementation/asts/check_components.md new file mode 100644 index 00000000..c99bede1 --- /dev/null +++ b/docs/implementation/asts/check_components.md @@ -0,0 +1,55 @@ +# The `check_components` and `delegate_and_check_components` AST stacks + +These two stacks generate the compile-time wiring checks. The `check_components` stack parses a check table into entries and lowers each into a check-trait impl; the `delegate_and_check_components` stack is a thin layer that reuses both this stack and the [`delegate_component` stack](delegate_component.md), deriving check entries from delegation keys. Evaluation flows from a `CheckComponentsTable` down to `EvaluatedCheckEntry` values, each rendering one empty impl of the table's check trait. The [`check_components!`](../entrypoints/check_components.md) and [`delegate_and_check_components!`](../entrypoints/delegate_and_check_components.md) entrypoint documents cover what the pipelines produce; this document covers the types. + +## `CheckComponentsTables` and `CheckComponentsTable` + +`CheckComponentsTables` is the whole `check_components!` body — a `Vec`, parsed by looping until the input is empty, so one invocation can carry several context blocks. `to_items` concatenates each table's items. + +`CheckComponentsTable` is one context block: an optional `check_providers` list, an optional leading generic list, the derived-or-overridden check-trait name, the context type, an optional `where` clause, and the `CheckEntries`. Its `Parse` reads the `#[check_trait]` and `#[check_providers]` attributes (rejecting any other), derives the trait name as `__Check{Context}` from the context type's leading identifier when not overridden, and parses the braced entries. Its `eval` builds the check trait once — supertraiting `CanUseComponent` normally, or `IsProviderFor<…, Context, …>` under `#[check_providers]` — then emits one impl per evaluated entry. For the context-checking form it overrides the impl's `Self`-type span with the component's span so an error points at the component; the `#[check_providers]` form instead emits one impl per listed provider. + +## `CheckEntries` and `CheckEntry` + +`CheckEntries` is the braced list, a `Punctuated`; its `eval` flattens every entry into `EvaluatedCheckEntry` values. + +`CheckEntry` is one line: a `CheckKey` and an optional `CheckValue` after a colon. Its `eval` produces the cartesian product of keys and values — one evaluated entry per (key, value) pair — and, when there is no value, one entry with unit params. It also chooses the diagnostic span per entry, preferring the component or the parameter side depending on which list is longer, so the error lands on the token the user is most likely to have gotten wrong. + +## A key: `CheckKey` + +`CheckKey` is the left side, an enum of a single `Type` or a bracketed `Multi` list. `to_keys` returns one type for the single form and one per element for the array form, which is how a bracketed key checks several components at once. + +## A value: `CheckValue` + +`CheckValue` is the optional right side — the generic parameters to check the component with — an enum of a single `TypeWithGenerics` or a bracketed `Multi` list. `to_values` returns one or many, so a bracketed value checks one component against several parameter sets. `TypeWithGenerics` is a type plus an optional leading generic list, letting a parameter introduce its own generics (` &'a T`) that merge with the table's when the impl is built. An omitted value defaults to the unit type. + +## `EvaluatedCheckEntry` + +`EvaluatedCheckEntry` is the lowered form: the component key, an optional `TypeWithGenerics` value, and the diagnostic span. It is a plain data struct; `CheckComponentsTable::eval` consumes it to build each impl, placing the key in the `__Component__` position and the value (or `()`) in the `__Params__` position. + +## `ItemDelegateAndCheckComponents` + +`ItemDelegateAndCheckComponents` is the entire `delegate_and_check_components!` body — just a wrapper around a parsed [`DelegateTable`](delegate_component.md). It adds the derivation from delegation to checking: + +- `check_trait_ident` derives the check-trait name as `__CanUse{Context}` (distinct from `check_components!`'s `__Check{Context}`) or reads a single `#[check_trait]` attribute off the table. +- `to_check_entries` walks the delegation keys via `ToKeysWithCheckParams` and turns each into `CheckEntry` values. +- `to_check_components` packages those entries, the table's generics, the derived name, and the context type into a `CheckComponentsTable`, so the checking half is rendered by the ordinary `check_components` pipeline. + +The wiring half is not re-derived here — the entrypoint calls `DelegateTable::eval` directly. + +## `CheckParamsAttribute` and `KeyWithCheckParams` + +`CheckParamsAttribute` is the per-entry check control parsed from the delegation key's attributes: `Default` (check with unit params), `Skip` (`#[skip_check]`, no check), or `Multi` (`#[check_params(...)]`, one check per listed parameter). Its `merge` combines a bracket-level attribute with an inner key's own — unioning two `Multi` sets, but erroring when `Skip` meets `Multi` — and `parse_attributes` enforces that at most one attribute appears and that `#[skip_check]` takes no arguments. + +`KeyWithCheckParams` pairs a delegation key type with its resolved `CheckParamsAttribute`. Its `to_check_entries` turns the pairing into `CheckEntry` values: `Default` yields one bare entry, `Skip` yields none, and `Multi` yields one valued entry per parameter. + +## `ToKeysWithCheckParams` + +`ToKeysWithCheckParams` is the trait that walks a `DelegateEntries` and collects `KeyWithCheckParams`. It handles single and array keys (merging bracket-level and inner attributes), and it deliberately produces no check entries for redirect (`=>`) mappings, `@`-path keys, and the `open`/`namespace`/`for` statement forms — validating that each carries no attribute rather than silently dropping one. A per-key generic list on a `SingleDelegateKey` is intentionally not carried into the check entry, since the derived impl sees only the table-level generics; this limitation is recorded in the [entrypoint document's Known issues](../entrypoints/delegate_and_check_components.md). + +## Tests + +Both stacks are exercised by the expansion snapshots indexed in the [`check_components!`](../entrypoints/check_components.md) and [`delegate_and_check_components!`](../entrypoints/delegate_and_check_components.md) entrypoint documents; each is a compile-only test, so a successful build is the passing assertion. There are no `cgp-macro-tests` failure cases for the check family. + +## Source + +The `check_components` stack lives in [cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/): the tables in `tables.rs` and `table.rs` (with the trait build, attribute parsing, name derivation, supertrait choice, and span override in `table.rs`), the entries in `entries.rs` and `entry.rs`, the key and value in `key.rs` and `value.rs`, `TypeWithGenerics` in `type_with_generics.rs`, and `EvaluatedCheckEntry` in `evaluated_check_entry.rs`. The `delegate_and_check_components` stack lives in [cgp-macro-core/src/types/delegate_and_check_components/](../../../crates/macros/cgp-macro-core/src/types/delegate_and_check_components/): the wrapper item in `item.rs`, the attributes in `check_params.rs`, the per-key conversion in `key_with_check_params.rs`, and the entry walk in `to_keys_with_check_params.rs`. It reuses the [`DelegateTable`](delegate_component.md). All impls are built with [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/asts/delegate_component.md b/docs/implementation/asts/delegate_component.md new file mode 100644 index 00000000..fcf88605 --- /dev/null +++ b/docs/implementation/asts/delegate_component.md @@ -0,0 +1,63 @@ +# The `delegate_component` AST stack + +The `delegate_component` stack is the set of AST types that `delegate_components!` (and, for its wiring half, [`delegate_and_check_components!`](../entrypoints/delegate_and_check_components.md)) parses the macro body into and lowers to impls. The top is `DelegateTable`; below it the body is a `DelegateEntries` of leading statements plus comma-separated mappings, and each mapping pairs a key with a value under one of three operators. Evaluation flows in one direction: the tree lowers to a flat list of `EvaluatedDelegateEntry` values, each of which renders a `DelegateComponent` impl and an `IsProviderFor` impl. The [entrypoint document](../entrypoints/delegate_components.md) covers what the whole pipeline produces; this document covers the types, one per role in the grammar. + +## `DelegateTable` and `EvaluatedDelegateTable` + +`DelegateTable` is the whole parsed body: outer attributes, an optional leading generic list (`ImplGenerics`), an optional `new` keyword, the target type, and the braced `DelegateEntries`. Its `eval` produces an `EvaluatedDelegateTable` — a bag of `ItemImpl`s and `EmptyStruct`s — whose `ToTokens` emits the structs first, then the impls. + +`eval` does three things: if `new` is present it parses the target into an identifier-plus-generics and pushes an `EmptyStruct` for it; it builds the entry impls from `DelegateEntries::build_impls`; and it collects every nested `UseDelegate` inner table (via `ExtractInnerDelegateTables`) and emits each inner table's own struct and impls. The target type and the outer generics are threaded down into every entry so all impls carry the table's generics. + +## `DelegateEntries` + +`DelegateEntries` is the table body: a `Vec` followed by a `Punctuated`. Its `Parse` impl peeks for a statement keyword (`namespace`, `open`, or `for`) and consumes all leading statements first, then parses the remaining comma-separated mappings — which is why a statement written after a mapping fails to parse. Its `eval_entries` lowers the statements first, then the mappings, concatenating the evaluated entries; `build_impls` then renders each into its `DelegateComponent`/`IsProviderFor` pair. + +## `InnerDelegateTable` + +`InnerDelegateTable` is a nested table lifted out of a `UseDelegate` value: an identifier, its generics, and its own `DelegateEntries`. It builds its own `EmptyStruct` and, treating its own identifier-plus-generics as the target type, its own entry impls — so a nested table is evaluated exactly like a top-level one. `ExtractInnerDelegateTables` recurses so that nesting to any depth is flattened into the table's struct-and-impl list. + +## `DelegateStatement` + +`DelegateStatement` is the leading statement form, an enum over three variants that all lower through `eval_entries` into the same flat entry list: + +- **`OpenDelegateStatement`** (`open { A, B };`) — opens each listed component for per-value wiring. For each component it emits an entry whose key is the component and whose value is `RedirectLookup>`, rooting a redirect at the component name in the context's own table. The `@Component.Key` mappings that follow store providers under the extended path. +- **`NamespaceDelegateStatement`** (`namespace SomeNamespace;`) — forwards every lookup through a namespace trait. It lowers via the shared "for-entry" path to a blanket `DelegateComponent<__Key__>` impl bounded on `__Key__: SomeNamespace`, so any key the namespace defines is inherited. +- **`ForDelegateStatement`** (`for in SomeTable where … { … }`) — a loop that pulls mappings out of another lookup table. Each inner mapping produces a for-entry whose namespace-trait bound is reconstructed with the table type and a `Delegate = value` binding appended to the namespace path's arguments. + +The namespace and `for` forms share `EvaluatedForEntry` and `eval_delegate_entries_via_for`, which build the `Namespace<…, Delegate = …>` bound and the `__Key__`/`__Value__` generics before producing the final `EvaluatedDelegateEntry`. + +## `DelegateMapping` + +`DelegateMapping` is one comma-separated entry, an enum whose variant is chosen by the operator after the key. `DelegateMode` peeks the operator and drives the split: + +- **`NormalDelegateMapping`** (`:`) — maps the key straight to the value type; the evaluated entry's `Delegate` is the value. +- **`DirectDelegateMapping`** (`->`) — forwards to the value's own entry for the key. It sets `Delegate` to `>::Delegate` and adds a `Value: DelegateComponent` bound to the entry's generics. +- **`RedirectDelegateMapping`** (`=>`) — redirects the lookup along an `@`-path value. It sets `Delegate` to `RedirectLookup`, using the path directly for a plain key or a wildcard-terminated prefix for a path key. + +Only Normal and Direct mappings can carry a nested inner table (their values are `DelegateValue`); a Redirect value is a bare path and contributes no inner table. + +## A key: `DelegateKey` + +`DelegateKey` is the left side of a mapping, an enum over three shapes selected by a lookahead on a fork (after skipping any attributes and generics): a leading `@` gives a `PathDelegateKey`, a leading bracket gives a `MultiDelegateKey`, otherwise a `SingleDelegateKey`. `EvalDelegateKey::eval` returns a `Vec` (a type plus its generics), so a single mapping can expand to several keyed impls. + +- **`SingleDelegateKey`** — attributes, an optional generic list, and a type; evaluates to one key carrying its generics. +- **`MultiDelegateKey`** — a bracketed, comma-separated list of `SingleDelegateKey`; the array-key form, evaluating to one key per element so `[A, B]: P` becomes two impls. +- **`PathDelegateKey`** — the `@`-prefixed open key. It parses a `PathHead` after the `@` and lowers each expanded path to a prefix type terminated by a `__Wildcard__` generic, appending that wildcard to the key's generics. A brace group in the path (`@C.{u32, u64}`) expands to several paths, each becoming its own key. This is what lets a dispatch parameter slot into the redirect path at lookup time. + +## A value: `DelegateValue` + +`DelegateValue` is the right side of a Normal or Direct mapping, an enum of either a plain `Type` or a `DelegateValueWithInnerTable`. Its `Parse` speculatively tries the inner-table form first and falls back to a bare type. + +`DelegateValueWithInnerTable` parses the legacy nested-dispatch shape `Wrapper`: a wrapper identifier, `<`, the `new` keyword, an `InnerDelegateTable`, `>`. Its `eval` produces the value type `Wrapper` (dropping the `new`, which only signals that the inner struct must be declared), and `ExtractInnerDelegateTables` yields the inner table itself so `DelegateTable::eval` emits its struct and impls alongside the outer entry. + +## `EvaluatedDelegateEntry` + +`EvaluatedDelegateEntry` is the lowered form every key/value/statement collapses to: the target type, the merged generics, the key type, and the value (`Delegate`) type. It owns the rendering: `build_delegate_component_impl` emits the `DelegateComponent for TableType { type Delegate = Value; }` impl, and `build_is_provider_for_impl` emits the forwarding `IsProviderFor` impl bounded on `Value: IsProviderFor`, appending the reserved `__Context__` and `__Params__` generics. (`build_namespace_impl`, on the same type, is used by the namespace preset machinery to emit a `Namespace for Key` impl instead.) + +## Tests + +The stack is exercised end-to-end by the expansion snapshots and behavioral tests indexed in the [entrypoint document](../entrypoints/delegate_components.md); there are no `cgp-macro-tests` failure cases for the delegate family. + +## Source + +The stack lives in [cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/): the table and `new` keyword in `table/main.rs` and inner tables in `table/inner.rs`; the entries in `entries.rs`; the keys in `key/` (`single.rs`, `multi.rs`, `path.rs`, dispatched in `key/mod.rs`); the values in `value/` (`inner_table.rs`, dispatched in `value/mod.rs`); the mappings and their operator in `mapping/` (`normal.rs`, `direct.rs`, `redirect.rs`, `mode.rs`, and the `EvaluatedDelegateEntry` renderer in `mapping/eval.rs`); and the statements in `statement/` (`open.rs`, `namespace.rs`, `for_loop.rs`, and the shared for-entry evaluator in `statement/eval.rs`). Attribute rejection is in `validate_attributes.rs`, path parsing (`PathHead`, `UniPath`) in [types/path/](../../../crates/macros/cgp-macro-core/src/types/path/), and all impls are built with [parse_internal!](../macros/parse_internal.md). The `RedirectLookup` value the `open` and `=>` forms emit is the impl generated by [`#[cgp_component]`](../entrypoints/cgp_component.md). diff --git a/docs/implementation/asts/namespace.md b/docs/implementation/asts/namespace.md new file mode 100644 index 00000000..afbaff5f --- /dev/null +++ b/docs/implementation/asts/namespace.md @@ -0,0 +1,45 @@ +# The `namespace` AST stack + +The `namespace` stack is the pair of AST types that `cgp_namespace!` parses into and renders from — `NamespaceTable`, which holds the parsed header and entries and carries all the derivation logic, and `EvaluatedNamespaceTable`, the bag of finished `syn` items it produces. A supporting type, `InheritNamespaceStatement`, lowers a parent-namespace clause into the inheritance entry. The data flows in one direction: the macro body parses into `NamespaceTable`, whose `eval` builds an `EvaluatedNamespaceTable` that a `ToTokens` impl renders. The [entrypoint document](../entrypoints/cgp_namespace.md) covers what each generated item looks like; this document covers the types. + +## `NamespaceTable` + +`NamespaceTable` is the parsed form of the whole macro body and the type that does the work. Its `Parse` impl reads, in order, an optional generic list, an optional `new` keyword, the namespace name (an identifier with optional type arguments), an optional `: parent` clause (parsed as a path with type arguments), and a brace-delimited entry table: + +```rust +pub struct NamespaceTable { + pub impl_generics: ImplGenerics, + pub new: Option>, + pub namespace: IdentWithTypeArgs, + pub parent_namespace: Option<(Colon, PathWithTypeArgs)>, + pub entries: DelegateEntries, +} +``` + +The `entries` field is a `DelegateEntries` — the same type `delegate_components!` parses its table into — so a namespace body accepts every mapping form, array key, and statement that a delegation table does. `NamespaceTable` carries a family of `build_*` methods, one per generated item: `build_item_trait` emits the `{Namespace}<__Table__>` lookup trait only when `new` is set, `build_namespace_struct` the `__{Namespace}Components` marker only when `new` is set, `build_item_impls` one impl per evaluated entry (each entry evaluated against the shared `__Table__` type), and `build_parent_namespace_impl` the inheritance impl when a parent is named. Its `eval` method runs all four and packages the results, inserting the inheritance impl ahead of the entry impls so it wins during resolution. + +## `InheritNamespaceStatement` + +`InheritNamespaceStatement` is the intermediary that turns a `: parent` clause into an inheritance entry; the user never writes it. It pairs the parent namespace path with the child's own marker-struct identifier, and its `eval_for_entry` builds a for-entry — the same `EvaluatedForEntry` shape `delegate_components!` uses — whose `where` clause bounds a key on the parent namespace over the child's local table. That for-entry then evaluates to the blanket impl that reads each parent entry and re-emits it under the child (the `__Key__`/`__Value__`/`DefaultNamespace` shape shown in the entrypoint document). Routing inheritance through the shared for-entry machinery is what keeps a namespace's parent lookup consistent with an ordinary delegation table's. + +## `EvaluatedNamespaceTable` + +`EvaluatedNamespaceTable` is the final stage — a bag holding the optional trait, the optional struct, and the vector of impls: + +```rust +pub struct EvaluatedNamespaceTable { + pub item_impls: Vec, + pub item_trait: Option, + pub item_struct: Option, +} +``` + +Its only behavior is a `ToTokens` impl that renders the items in a fixed order — struct first, then trait, then every impl — which is the order the canonical snapshots pin. Because the inheritance impl was inserted at the front of `item_impls` during `eval`, it renders ahead of the per-entry impls. + +## Tests + +- The stack is exercised end-to-end by the expansion snapshots and behavioral tests indexed in the [entrypoint document](../entrypoints/cgp_namespace.md), which pin each entry form (redirect, direct mapping, array key, inheritance, and path-prefix rewrite) and the wiring they produce. + +## Source + +The stack lives in [cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/): `NamespaceTable` and its `build_*`/`eval` methods in `table.rs`, `InheritNamespaceStatement` in `inherit.rs`, and `EvaluatedNamespaceTable` in `eval.rs`. The entry table and the for-entry machinery it reuses live in [cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/). The entrypoint that drives the stack is documented in [entrypoints/cgp_namespace.md](../entrypoints/cgp_namespace.md). diff --git a/docs/implementation/asts/path.md b/docs/implementation/asts/path.md new file mode 100644 index 00000000..8016118a --- /dev/null +++ b/docs/implementation/asts/path.md @@ -0,0 +1,45 @@ +# The `path` AST stack + +The `path` stack is the family of AST types that parse and emit CGP's type-level paths. `Path!` itself drives only two of them — `UniPath`, which parses the `@`-path and emits the `PathCons` chain, and `PathElement`, which classifies each segment as a symbol or a named type — but the same segment machinery is shared by the richer path forms the namespace and prefix constructs need. This document covers the whole stack in the order the data flows, starting with the two `Path!` drives; the [entrypoint document](../entrypoints/path.md) covers what the macro produces. + +## `PathElement` + +`PathElement` is one segment of a path, either a named `Type` or a `Symbol`. Its `Parse` impl first reads the segment as a full Rust `Type`, then reclassifies: if the type reduces to a single identifier, begins with a lowercase ASCII letter, and is not a primitive type name, it becomes a `Symbol` (built via `Symbol::from_ident`, see the [`Symbol` AST](symbol.md)); otherwise it stays the named `Type`. + +```rust +app // -> Symbol (lowercase, non-primitive) +ErrorRaiserComponent // -> Type (capitalized) +u32 // -> Type (lowercase but primitive) +``` + +The primitive check recognizes the `iN`/`uN`/`fN` numeric families plus `char`, `bool`, `usize`, `isize`, and `str`. `PathElement` emits itself through `ToTokens` (delegating to the symbol or the type) and also implements the internal `ToType` trait for callers that need a `syn::Type`. + +## `UniPath` + +`UniPath` is the whole `@`-path — the type `Path!` parses into and the one `PathElement` list its `ToTokens` folds. Its `Parse` impl consumes a leading `At` token and then a dot-separated, non-empty run of `PathElement`s via `parse_separated_nonempty`, so a body without the `@` or with no segments is rejected. Its `ToTokens` right-folds the segments onto `Nil`, wrapping each in `PathCons`: + +```rust +// @app.error.ErrorRaiserComponent folds to +PathCons>> +``` + +`UniPath` also carries helpers the namespace machinery uses — `append_type` to push a trailing named segment and `to_prefix` to convert into a `PrefixPath` — but `Path!` uses only the parse-and-emit path. `PathCons` and `Nil` come from the [export markers](../../../crates/macros/cgp-macro-core/src/exports.rs). + +## `PrefixPath` + +`PrefixPath` is a `UniPath` whose chain terminates in a named suffix type rather than `Nil`, used by the `#[prefix(...)]` attribute to route a component key through a namespace path. It holds the segment list plus a `suffix: Type`, and its `ToTokens` folds the segments onto that suffix instead of `Nil`, so `@bar.baz` with a `FooProviderComponent` suffix becomes `PathCons>>` once the suffix itself expands. `Path!` never produces a `PrefixPath` directly; it is reached through `UniPath::to_prefix`. + +## `PathHead` and the branching forms + +The remaining types support the multi-path, generic-carrying grammar that `#[cgp_namespace]` and the `open` statement accept, which `Path!` does not: `PathHead` is a recursive parser for a path that can branch (a brace group of alternative sub-paths), carry a per-value group (a bracketed set sharing a tail), or attach generics, and its `into_paths` flattens such a tree into a list of `(ImplGenerics, UniPath)` pairs. `PathElementWithGenerics` pairs a `PathElement` with leading `ImplGenerics` so a segment can introduce a lifetime or type parameter. `PathHeadOrType` and `UniPathOrType` are the entry parsers that decide, by peeking for a leading `@`, whether an input is a path or a plain type — the disambiguation the namespace and wiring grammars need where either is allowed. These belong to the path stack because they reuse `PathElement` and the same `PathCons` fold, but they are driven by the namespace and wiring macros rather than by `Path!`. + +## Tests + +`Path!` is rarely written directly, so the stack is exercised mainly through the namespace and prefix machinery that reuses it. + +- [namespaces/redirect_lookup.rs](../../../crates/tests/cgp-tests/tests/namespaces/redirect_lookup.rs) pins, through a `snapshot_cgp_component!` golden, the `PathCons` chain a `#[prefix(@bar.baz in DefaultNamespace)]` attribute produces via `PrefixPath`. +- [namespaces/namespace_symbol_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_symbol_path.rs) and [namespaces/namespace_type_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_type_path.rs) exercise the lowercase-symbol and capitalized-type segment classification of `PathElement` through `#[cgp_namespace]` `@`-paths. + +## Source + +The stack lives in [cgp-macro-core/src/types/path/](../../../crates/macros/cgp-macro-core/src/types/path/): `PathElement` in `path_element.rs`, `UniPath` in `unipath.rs`, `PrefixPath` in `prefix.rs`, `PathHead` in `path_head.rs`, `PathElementWithGenerics` in `path_element_with_generics.rs`, and the `PathHeadOrType`/`UniPathOrType` disambiguators in `path_head_or_type.rs` and `unipath_or_type.rs`. The runtime spine `PathCons` is defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/path.rs). diff --git a/docs/implementation/asts/product.md b/docs/implementation/asts/product.md new file mode 100644 index 00000000..b85ad527 --- /dev/null +++ b/docs/implementation/asts/product.md @@ -0,0 +1,36 @@ +# The `product` AST stack + +The `product` stack is the pair of AST types behind `Product!` and `product!`: `ProductType` for the type-level macro and `ProductExpr` for the value-level one. Both parse a comma-separated list into a `Punctuated` and fold it into a `Cons`/`Nil` chain, differing only in whether they emit the type form `Cons<…>` or the constructor form `Cons(…)`. The [entrypoint document](../entrypoints/product.md) covers what the macros produce; this document covers the types. + +## `ProductType` + +`ProductType` is the type-level form. It holds the parsed element list (`types: Punctuated`), and its `Parse` impl reads that list with `parse_terminated`, so a trailing comma is accepted and an empty body yields an empty list. Its `eval` method folds the elements right-to-left onto `Nil`, wrapping each in the type form `Cons`, then re-parses the accumulated tokens into a `syn::Type` through [`parse_internal!`](../macros/parse_internal.md): + +```rust +// Product![A, B, C] evals to +Cons>> +// Product![] evals to +Nil +``` + +Returning a validated `syn::Type` rather than a raw token stream is what lets the entry function drop the result straight into `to_token_stream()`. `Cons` and `Nil` come from the [export markers](../../../crates/macros/cgp-macro-core/src/exports.rs). + +## `ProductExpr` + +`ProductExpr` is the value-level form and is structurally identical: it too holds a `Punctuated` and parses with `parse_terminated`. The one difference is in `eval`, which wraps each element in the tuple-struct constructor form `Cons(ty, acc)` rather than the type form, folding onto `Nil` the same way: + +```rust +// product![a, b, c] evals to +Cons(a, Cons(b, Cons(c, Nil))) +``` + +Note that its field is still named and typed as a list of `Type`, not `Expr` — the value macro reuses the type parser and only changes the emission shape, so the two forms cannot diverge in how they read their input. + +## Tests + +- The `Cons`/`Nil` field spine is pinned as embedded output by the record derive snapshots ([extensible_records/person_record.rs](../../../crates/tests/cgp-tests/tests/extensible_records/person_record.rs), [extensible_records/record_derive.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_derive.rs)), which emit a `Product!` of `Field` entries. +- [handlers/pipe_handlers.rs](../../../crates/tests/cgp-tests/tests/handlers/pipe_handlers.rs) exercises the type-level `Product![…]` as a list of provider types in a handler pipeline. + +## Source + +The stack lives in [cgp-macro-core/src/types/product/](../../../crates/macros/cgp-macro-core/src/types/product/): `ProductType` in `product_type.rs` and `ProductExpr` in `product_expr.rs`, both re-parsing their fold through [parse_internal!](../macros/parse_internal.md). The runtime types `Cons` and `Nil` are defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/). diff --git a/docs/implementation/asts/sum.md b/docs/implementation/asts/sum.md new file mode 100644 index 00000000..0d2e8d3f --- /dev/null +++ b/docs/implementation/asts/sum.md @@ -0,0 +1,25 @@ +# The `sum` AST stack + +The `sum` stack is a single AST type, `SumType`, behind the `Sum!` macro. It parses a comma-separated list of types and folds it into an `Either`/`Void` chain — the same one-type, parse-then-`eval` shape as [`ProductType`](product.md), differing only in the spine it folds onto. The [entrypoint document](../entrypoints/sum.md) covers what the macro produces; this document covers the type. + +## `SumType` + +`SumType` holds the parsed element list (`types: Punctuated`), and its `Parse` impl reads that list with `parse_terminated`, so a trailing comma is accepted and an empty body yields an empty list. Its `eval` method folds the elements right-to-left onto `Void`, wrapping each in `Either`, then re-parses the accumulated tokens into a `syn::Type` through [`parse_internal!`](../macros/parse_internal.md): + +```rust +// Sum![A, B, C] evals to +Either>> +// Sum![] evals to +Void +``` + +The only thing that distinguishes this from `ProductType` is the terminator: a sum folds onto `Void` — the uninhabited empty enum — rather than `Nil`, so an empty sum is a type with no values while an empty product is the unit-like `Nil`. `Either` and `Void` come from the [export markers](../../../crates/macros/cgp-macro-core/src/exports.rs). + +## Tests + +- [extensible_variants/sum_macro.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/sum_macro.rs) asserts `Sum![u32, String, bool]` is the identical type to the hand-written `Either>>`, pinning the fold directly. +- [extensible_variants/has_fields_enum.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/has_fields_enum.rs) exercises the `Sum!` variant spine an enum derives through `#[derive(HasFields)]`. + +## Source + +The type lives in [cgp-macro-core/src/types/sum.rs](../../../crates/macros/cgp-macro-core/src/types/sum.rs), re-parsing its fold through [parse_internal!](../macros/parse_internal.md). The runtime types `Either` and the uninhabited `Void` are defined in [cgp-field](../../../crates/core/cgp-field/src/types/sum.rs). diff --git a/docs/implementation/asts/symbol.md b/docs/implementation/asts/symbol.md new file mode 100644 index 00000000..e784cf5d --- /dev/null +++ b/docs/implementation/asts/symbol.md @@ -0,0 +1,29 @@ +# The `Symbol` AST + +The `Symbol` stack is a single AST type: `Symbol`, which parses a string literal and emits the type-level `Symbol>` string. It has no intermediate stages — one `Parse` reads the literal and one `ToTokens` emits the type — so the whole of `Symbol!`'s logic lives here. The [entrypoint document](../entrypoints/symbol.md) covers what the macro produces; this document covers the type. + +## `Symbol` + +`Symbol` holds the captured string and its span (`ident: String`, `span: Span`); it does not retain the `syn` literal. Its `Parse` impl reads a single `LitStr` and stores the literal's value and span, so a non-literal body is rejected there. + +Its `ToTokens` impl is where the type-level string is built. It folds the string's characters right-to-left onto `Nil`, wrapping each in a `Chars` node, then wraps the resulting chain in `Symbol` where `LEN` is the string's byte length from `str::len()`: + +```rust +// "ab" folds to +Chars<'a', Chars<'b', Nil>> +// then wraps to +Symbol<2, Chars<'a', Chars<'b', Nil>>> +``` + +Every emitted token carries the stored span via `quote_spanned!`, so a type error on the produced `Symbol` points back at the original literal. The `Symbol`, `Chars`, and `Nil` names come from the [export markers](../../../crates/macros/cgp-macro-core/src/exports.rs) so the output is hygienic. + +Beyond parsing a literal, `Symbol` is also constructed from a bare identifier through `Symbol::from_ident`, which the [`path` stack](path.md) uses to turn a lowercase path segment into a symbol; that constructor stores the identifier's text and span and reuses the same `ToTokens` emission, bypassing the `LitStr` parser. `Symbol` also implements the internal `ToType` trait, so a caller that needs a `syn::Type` rather than raw tokens can obtain one. + +## Tests + +- [field_access/symbol.rs](../../../crates/tests/cgp-tests/tests/field_access/symbol.rs) pins the runtime round-trip — a `Symbol!` value `Display`s back to its string and `StaticString::VALUE` recovers the literal — across the empty string, ASCII, and multi-byte Unicode, confirming the char chain rather than `LEN` drives the reconstruction. +- The `Symbol>` emission is checked as embedded output by the record and field derive snapshots indexed in the [entrypoint document's Tests section](../entrypoints/symbol.md). + +## Source + +The type lives in [cgp-macro-core/src/types/field/symbol.rs](../../../crates/macros/cgp-macro-core/src/types/field/symbol.rs). The runtime types `Symbol`, `Chars`, and `Nil` are defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/). diff --git a/docs/implementation/entrypoints/async_trait.md b/docs/implementation/entrypoints/async_trait.md new file mode 100644 index 00000000..5e7cca59 --- /dev/null +++ b/docs/implementation/entrypoints/async_trait.md @@ -0,0 +1,49 @@ +# `#[async_trait]` — implementation + +`#[async_trait]` rewrites every `async fn` declared in a trait into a plain method returning `-> impl Future`, so a trait can advertise async methods without tripping the `async_fn_in_trait` lint. This document covers how the macro is built; for the accepted syntax and the full expansion, read the reference document [reference/macros/async_trait.md](../../reference/macros/async_trait.md). + +## Entry point + +The macro lives entirely in the [cgp-async-macro](../../../crates/macros/cgp-async-macro/) crate — it does not use `cgp-macro-core` at all. The `#[proc_macro_attribute]` shim `async_trait` in [cgp-async-macro/src/lib.rs](../../../crates/macros/cgp-async-macro/src/lib.rs) discards its attribute arguments unconditionally and forwards the annotated item to `impl_async` in [cgp-async-macro/src/impl_async.rs](../../../crates/macros/cgp-async-macro/src/impl_async.rs). Because the attribute tokens are ignored, the macro is always written bare. + +## Pipeline + +There is no staged pipeline; `impl_async` is a single `syn::parse2::` followed by an in-place mutation pass. It attempts to parse the item as a trait, and on success walks the trait's methods, rewriting each `async` signature and returning the modified trait; on any parse failure it returns the original tokens unchanged. This parse-or-passthrough structure is what makes the macro composable — applying it to an `impl` block (which does not parse as an `ItemTrait`) is a no-op, so a provider's `async fn` bodies are left intact while the matching trait declaration carries the rewritten signature. + +## Generated items + +The macro emits the same trait it was given, with each `async` method signature rewritten. For a method whose signature is `async`, it clears the `async` keyword and replaces the return type `T` with `impl ::core::future::Future`; a method with no return arrow is treated as returning `()`: + +```rust +// async fn fetch(&self, id: &str) -> Result, Error>; +fn fetch(&self, id: &str) -> impl ::core::future::Future, Error>>; + +// async fn run(&self); +fn run(&self) -> impl ::core::future::Future; +``` + +Only method signatures are touched. Non-async methods, associated types, and associated constants pass through unchanged, and the method body — for the rare method that has one — is never rewritten (see Known issues). + +## Behavior and corner cases + +The **only structural transform is to the signature**: the `async` token is removed and the return type is wrapped in `impl Future`. The macro introduces no boxing, no allocation, and no `Send` bound — it is a mechanical spelling of return-position `impl Trait` in a trait, and the returned future is exactly the one the method body produces. + +The **passthrough on non-trait items is deliberate**, not an error path in the usual sense: any item that fails to parse as an `ItemTrait` is returned verbatim, which is what lets `#[async_trait]` sit harmlessly on an `impl` block that a host macro like [`#[cgp_fn]`](cgp_fn.md) copies the attribute onto. + +## Known issues + +The macro **mishandles an async method that carries a default body**. It strips `async` and rewrites the return type to `impl Future`, but leaves the body verbatim rather than wrapping it in an `async { … }` block. The result is a non-async method whose body still returns a plain value (and may use `.await`), which fails to compile. In practice this is rarely hit — async trait methods are almost always bodyless declarations, with behavior supplied by a provider impl — but a default-bodied `async fn` inside a `#[async_trait]` trait is not supported. The correct behavior would be to wrap a rewritten method's body in `async move { … }` so the signature and body agree. The user-visible consequence, together with the absence of a `Send` bound on the generated future, is documented under Known issues in [reference/macros/async_trait.md](../../reference/macros/async_trait.md). + +## Tests + +The macro is exercised through its interaction with the constructs it stacks onto rather than on its own: + +- [async_and_send/cgp_fn_async.rs](../../../crates/tests/cgp-tests/tests/async_and_send/cgp_fn_async.rs) — a `snapshot_cgp_fn!` over an async `#[cgp_fn]` that also carries `#[async_trait]`, pinning the rewritten trait declaration; this snapshot is owned by the `#[cgp_fn]` feature, not by `#[async_trait]`. +- [async_and_send/spawn.rs](../../../crates/tests/cgp-tests/tests/async_and_send/spawn.rs) — async components declared with `#[async_trait]` whose futures are handed to a `Send + 'static`-demanding executor. +- [dispatching/auto_dispatch_async_self_ref_only.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_async_self_ref_only.rs) and the other `auto_dispatch_async_*` files — `#[async_trait]` stacked with [`#[cgp_auto_dispatch]`](cgp_auto_dispatch.md) on async dispatch traits. + +There is no dedicated `snapshot_async_trait!` macro; the rewrite is only pinned incidentally through the `#[cgp_fn]` snapshot above. + +## Source + +The macro entry point is `async_trait` in [cgp-async-macro/src/lib.rs](../../../crates/macros/cgp-async-macro/src/lib.rs), and the rewrite is `impl_async` in [cgp-async-macro/src/impl_async.rs](../../../crates/macros/cgp-async-macro/src/impl_async.rs). It is re-exported into the prelude from [crates/main/cgp-core/src/prelude.rs](../../../crates/main/cgp-core/src/prelude.rs). It is most often stacked with [`#[cgp_component]`](cgp_component.md) and [`#[cgp_fn]`](cgp_fn.md). diff --git a/docs/implementation/entrypoints/blanket_trait.md b/docs/implementation/entrypoints/blanket_trait.md new file mode 100644 index 00000000..68753acf --- /dev/null +++ b/docs/implementation/entrypoints/blanket_trait.md @@ -0,0 +1,84 @@ +# `#[blanket_trait]` — implementation + +`#[blanket_trait]` turns a trait whose items carry default definitions into an extension trait by emitting the trait unchanged and generating the blanket impl that forwards those defaults, hiding the trait's supertraits behind its `where` clause. This document covers how that works internally; for the accepted syntax and the full expansion, read the reference document [reference/macros/blanket_trait.md](../../reference/macros/blanket_trait.md). + +## Entry point + +The macro is driven by the `blanket_trait` function in [cgp-macro-lib/src/blanket_trait.rs](../../../crates/macros/cgp-macro-lib/src/blanket_trait.rs). It parses the attribute argument as an optional context identifier — defaulting to the reserved `__Context__` when the attribute is empty — and the item as a `syn::ItemTrait`, then builds an `ItemBlanketTrait` and renders it directly. + +```rust +let context_ident = if attr.is_empty() { + Ident::new("__Context__", Span::call_site()) +} else { + parse2(attr)? +}; +let item_blanket_impl = ItemBlanketTrait { context_ident, item_trait }; +let items = item_blanket_impl.to_items()?; +``` + +Two failures surface here: a non-identifier attribute argument fails at `parse2`, and a non-trait item fails at `syn::parse2::`. Unlike `#[cgp_component]`, this macro has no multi-stage pipeline — the single `to_items` call does all the work. + +## Pipeline + +There is only one transform. `ItemBlanketTrait::to_items` emits two items: the trait, cloned verbatim from the input, and the blanket impl produced by `to_item_impl`. Because the trait is emitted unchanged, its declarations keep their default bodies as the user wrote them; the derivation happens only on the impl side. The [`blanket_trait` AST stack](../asts/blanket_trait.md) documents `ItemBlanketTrait`. + +## Generated items + +The macro emits the trait unchanged followed by one blanket impl over the context type. The impl is where all the derivation happens: it forwards each trait item's default into an impl item, requires the trait's supertraits on the context, and lifts each associated type into a fresh impl generic. The impl generics are the trait's own generics plus the context parameter plus one parameter per associated type, and the trait's supertraits become a `#context: ` predicate. + +For a method-carrying trait the impl copies each default method body verbatim, so every qualifying context inherits the body: + +```rust +// #[blanket_trait] pub trait FooBar: Foo + Bar { fn foo_bar(&self) { self.foo(); self.bar(); } } + +impl<__Context__> FooBar for __Context__ +where + __Context__: Foo + Bar, +{ + fn foo_bar(&self) { self.foo(); self.bar(); } +} +``` + +An **associated type** is handled specially, because lifting one out of a supertrait is the pattern's main use. Each associated type in the trait becomes a new generic parameter on the impl; a `RemoveSelfPathVisitor` pass rewrites `Self::FooBar` references (in the supertrait's associated-type equality, for instance) to name that free parameter; and the impl assigns the parameter back to the associated type: + +```rust +// #[blanket_trait] pub trait HasFooTypeAtBar: HasFooTypeAt { type FooBar; } + +impl<__Context__, FooBar> HasFooTypeAtBar for __Context__ +where + __Context__: HasFooTypeAt, +{ + type FooBar = FooBar; +} +``` + +An **associated constant** is forwarded like a method: its default expression becomes the impl's constant definition. + +## Behavior and corner cases + +A **method or constant without a default** is a hard error: `to_item_impl` calls `ok_or_else` on the missing `default`, so the macro rejects it with a spanned `syn::Error` ("function item require implementation block" / "const item require implementation expression") rather than emitting a broken impl. An **associated type** needs no default, because the macro supplies the assignment itself from the lifted parameter. + +A **bound on an associated type** is moved onto the lifted parameter in the impl's `where` clause: `type FooBar: Clone` adds `FooBar: Clone` alongside the supertrait predicate, so the blanket impl only applies when the underlying type is `Clone`. The bound is collected from the trait item before its `default` is stripped for the impl copy. + +The **supertraits** of the trait become the hidden dependency: they are cloned into a single `#context: ` `where`-predicate on the impl, which is what shields callers from naming `Foo + Bar`. The trait keeps its supertraits in the declaration too, since the trait is emitted unchanged. + +Any trait item other than a type, method, or constant — a macro invocation, say — is rejected with an "unsupported trait item" error. + +## Snapshots + +Every `snapshot_blanket_trait!` invocation across the suite is indexed here; all live in the `blanket_traits` target: + +- [blanket_traits/basic.rs](../../../crates/tests/cgp-tests/tests/blanket_traits/basic.rs) — the canonical minimal expansion: supertrait bounds only, no body, yielding an empty impl (a trait alias in all but name). +- [blanket_traits/with_method.rs](../../../crates/tests/cgp-tests/tests/blanket_traits/with_method.rs) — a default method body copied verbatim into the blanket impl. +- [blanket_traits/associated_type.rs](../../../crates/tests/cgp-tests/tests/blanket_traits/associated_type.rs) — a local associated type lifted into an impl generic and tied to a supertrait's associated type via `Foo = Self::FooBar`. +- [blanket_traits/associated_type_bounded.rs](../../../crates/tests/cgp-tests/tests/blanket_traits/associated_type_bounded.rs) — the same, plus a bound (`type FooBar: Clone`) moved onto the lifted parameter in the `where` clause. + +Two variants have no snapshot yet: an associated *constant* forwarded from its default expression, and the `#[blanket_trait(Ctx)]` form overriding the default context identifier. + +## Tests + +The snapshot files double as behavioral tests — [blanket_traits/basic.rs](../../../crates/tests/cgp-tests/tests/blanket_traits/basic.rs) and the others each wire a concrete `Context` and assert through a `CanUse…` check trait that the generated blanket impl applies. No `cgp-macro-tests` failure case pins the "missing default body" error path, which is a candidate to add. + +## Source + +The entry point is `blanket_trait` in [cgp-macro-lib/src/blanket_trait.rs](../../../crates/macros/cgp-macro-lib/src/blanket_trait.rs); the logic lives in [cgp-macro-core/src/types/blanket_trait.rs](../../../crates/macros/cgp-macro-core/src/types/blanket_trait.rs) and is documented in [asts/blanket_trait.md](../asts/blanket_trait.md). The `Self::AssocType`-to-parameter rewriting is done by `RemoveSelfPathVisitor` in [cgp-macro-core/src/visitors/remove_self_path.rs](../../../crates/macros/cgp-macro-core/src/visitors/remove_self_path.rs), and all generated fragments are built with [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/entrypoints/cgp_auto_dispatch.md b/docs/implementation/entrypoints/cgp_auto_dispatch.md new file mode 100644 index 00000000..0374f4b5 --- /dev/null +++ b/docs/implementation/entrypoints/cgp_auto_dispatch.md @@ -0,0 +1,77 @@ +# `#[cgp_auto_dispatch]` — implementation + +`#[cgp_auto_dispatch]` takes a trait with one impl per payload type and appends the code that makes the trait work on an enum of those payloads: a blanket impl of the trait for a fresh enum parameter that runs a value-handler matcher, plus one per-variant [`Computer`](../../reference/components/computer.md) per method. This document covers how the macro is built; for the accepted syntax and the full expansion, read the reference document [reference/macros/cgp_auto_dispatch.md](../../reference/macros/cgp_auto_dispatch.md). + +## Entry point + +The macro is the `cgp_auto_dispatch` function in [cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs). It is a self-contained procedural function operating directly on `syn` types rather than a driver over a `cgp-macro-core` AST stack. It parses the annotated item as a `syn::ItemTrait`, keeps the original trait tokens verbatim, and appends generated code to them. The attribute takes no arguments. + +The macro is additive: the trait itself is unchanged, so the per-payload impls the user writes still satisfy it directly. Everything the macro produces is emitted *after* the trait — the enum-level blanket impl first, then one per-variant computer per method. + +## Pipeline + +There is no staged AST pipeline; the entry function walks the trait's methods twice. The generated code is built by two internal helpers, each of which is worth naming because it emits one of the two kinds of output: + +- **`derive_blanket_impl`** builds the single `impl for __Variants__` that, per method, invokes a value-handler matcher over the enum. It threads a `where` clause that bounds each matcher and requires `__Variants__: HasExtractor`. +- **`derive_method_computer`** builds, per method, a free function annotated with [`#[cgp_computer]`](cgp_computer.md) whose body calls the trait method on the payload. The macro emits these by delegating to `#[cgp_computer]` rather than synthesizing the `Computer` impl itself. + +Both helpers reject a trait item that is not a method, and reject a method that has no `self` receiver or carries a non-lifetime generic parameter. + +## Generated items + +For each method the macro emits a per-variant computer named `Compute` followed by the method name in PascalCase (`area` yields `ComputeArea`). Its body is just the trait-method call on the payload, and it is bound so it applies to every payload type implementing the trait; a `&self` method borrows the payload through a fresh lifetime `'__a__`: + +```rust +// from `fn area(&self) -> f64;` +#[cgp_computer(ComputeArea)] +fn area<'__a__, __Variants__: HasArea>(__Variants__: &'__a__ __Variants__) -> f64 { + __Variants__.area() +} +``` + +The enum-level blanket impl implements the trait for a fresh parameter `__Variants__` and, in each method body, dispatches through the matcher struct selected for that method's shape, invoking it with a unit context `&()` and unit code `PhantomData::<()>`: + +```rust +impl<__Variants__> HasArea for __Variants__ +where + MatchWithValueHandlersRef: + for<'__a__> Computer<(), (), &'__a__ __Variants__, Output = f64>, + __Variants__: HasExtractor, +{ + fn area(&self) -> f64 { + MatchWithValueHandlersRef::::compute(&(), PhantomData::<()>, self) + } +} +``` + +The matcher is chosen from the value-handler family by two properties of the method: the receiver form and whether the method takes extra arguments. With no extra arguments the plain family is used — `MatchWithValueHandlersRef` for `&self`, `MatchWithValueHandlersMut` for `&mut self`, `MatchWithValueHandlers` for by-value `self`. With extra arguments the first-argument family is used instead — `MatchFirstWithValueHandlersRef`/`Mut`/(plain) — and the receiver and arguments are bundled into the matcher input as `(context, (args…))`. An `async` method selects the `AsyncComputer` form of both the `where` bound and the matcher call, and `.await`s the result. + +## Behavior and corner cases + +The **matcher input reflects the receiver and argument list**. A no-argument method passes the bare payload as the input; a method with arguments passes a nested tuple `(self, (arg_0, arg_1, …))`, and the arguments are rebound positionally as `arg_i` (the source patterns are discarded). + +**Reference lifetimes are elaborated** so the matcher bound can be quantified. A reference receiver, reference argument, or reference return type with an elided lifetime is rewritten to carry the fresh `'__a__`, and a `for<'__a__>` quantifier is added to the matcher bound when any such lifetime is introduced. A `'static` lifetime is excluded from the quantifier. + +The **enum must be extensible**: the blanket impl always carries `__Variants__: HasExtractor`, so the enum needs a `CgpData`/`CgpVariant`-style derive that supplies the extractor and field machinery. Forgetting a per-variant impl surfaces as an unsatisfied matcher bound at the point the enum's method is used, not at the trait definition. + +## Known issues + +The macro **rejects a trait method with non-lifetime generic parameters** with a spanned `syn::Error` ("Dispatch trait methods cannot contain non-lifetime generic parameters due to the lack of quantified constraints in Rust"). This is a deliberate limitation, not a parser gap: the generated blanket impl would need a bound quantified over the method's type parameter to guarantee every payload satisfies it for all instantiations, and Rust has no such quantified bound. The user-visible consequence is documented under Known issues in [reference/macros/cgp_auto_dispatch.md](../../reference/macros/cgp_auto_dispatch.md); a method that must be generic has to be wired with the dispatch combinators directly instead. + +## Tests + +The behavioral tests cover every receiver-and-argument shape the matcher selection distinguishes: + +- [dispatching/auto_dispatch_shape.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_shape.rs) — a realistic `Shape` enum with a `&self` reader (`area`) and a `&mut self` mutator (`scale`). +- [dispatching/auto_dispatch_self_only.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_self_only.rs), [dispatching/auto_dispatch_self_ref_only.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_self_ref_only.rs), [dispatching/auto_dispatch_self_mut_only.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_self_mut_only.rs) — the by-value, `&self`, and `&mut self` no-argument forms, selecting the three plain matchers. +- [dispatching/auto_dispatch_multi_args.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_multi_args.rs), [dispatching/auto_dispatch_multi_args_ref.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_multi_args_ref.rs), [dispatching/auto_dispatch_multi_args_owned_self.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_multi_args_owned_self.rs) — the argument-taking forms, selecting the first-argument matcher family. +- [dispatching/auto_dispatch_self_ref_return_implicit_ref.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_self_ref_return_implicit_ref.rs), [dispatching/auto_dispatch_self_ref_return_explicit_ref.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_self_ref_return_explicit_ref.rs) — a reference return type with an elided versus an explicit lifetime, pinning the `'__a__` elaboration. +- [dispatching/auto_dispatch_multi_methods.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_multi_methods.rs) — a trait mixing `&self`, `&mut self`, and `self` methods over one enum. +- [dispatching/auto_dispatch_generics.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_generics.rs) — a generic *trait* (`CanCall`) whose per-variant impls add their own bounds; distinct from a generic *method*, which is rejected. +- [dispatching/auto_dispatch_async_self_only.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_async_self_only.rs), [dispatching/auto_dispatch_async_self_ref_only.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_async_self_ref_only.rs), [dispatching/auto_dispatch_async_self_mut_only.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_async_self_mut_only.rs), [dispatching/auto_dispatch_async_multi_args.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_async_multi_args.rs), [dispatching/auto_dispatch_async_multi_args_ref.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_async_multi_args_ref.rs), [dispatching/auto_dispatch_async_multi_args_owned_self.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_async_multi_args_owned_self.rs), [dispatching/auto_dispatch_async_generics.rs](../../../crates/tests/cgp-tests/tests/dispatching/auto_dispatch_async_generics.rs) — the same shapes stacked with [`#[async_trait]`](async_trait.md), selecting the `AsyncComputer` matcher form. + +There is no dedicated `snapshot_cgp_auto_dispatch!` macro; the macro's expansion is not pinned by a snapshot and is exercised only behaviorally. + +## Source + +The entry point is `cgp_auto_dispatch` in [cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs), forwarded from the proc-macro shim in [cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs). The per-variant handlers are emitted through [`#[cgp_computer]`](cgp_computer.md), and the value-handler matchers it wires live in [crates/extra/cgp-dispatch/src/providers/matchers/](../../../crates/extra/cgp-dispatch/src/providers/matchers/). diff --git a/docs/implementation/entrypoints/cgp_auto_getter.md b/docs/implementation/entrypoints/cgp_auto_getter.md new file mode 100644 index 00000000..6635cc61 --- /dev/null +++ b/docs/implementation/entrypoints/cgp_auto_getter.md @@ -0,0 +1,86 @@ +# `#[cgp_auto_getter]` — implementation + +`#[cgp_auto_getter]` derives a single blanket getter impl over `HasField` from a trait's method names, so any context whose field names match the getters gains the trait with no wiring. This document covers how that works internally; for the accepted syntax and the complete expansion a user sees, read the reference document [reference/macros/cgp_auto_getter.md](../../reference/macros/cgp_auto_getter.md). + +## Entry point + +The macro is driven by the `cgp_auto_getter` function in [cgp-macro-lib/src/cgp_auto_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs), which takes no attribute argument, parses the item into a `syn::ItemTrait`, then runs the two-step transform and emits the result. + +```rust +let item = ItemCgpAutoGetter::preprocess(&item_trait)?; +let items = item.to_items()?; +``` + +The macro rejects any attribute argument up front with a spanned error — unlike `#[cgp_getter]`, it has no provider name, component, or keys to accept. Applying it to a non-trait item fails at `parse2::`. All real logic lives in `cgp-macro-core`. + +## Pipeline + +The macro moves through two short steps, both methods on `ItemCgpAutoGetter`, documented in the [`cgp_getter` AST stack](../asts/cgp_getter.md) alongside `#[cgp_getter]`. + +- **preprocess** strips the CGP modifier attributes off the trait and keeps the cleaned trait; there is no component to derive, so this stage does little more than the attribute split. +- **to_items** parses the trait's methods into `GetterField`s and emits the trait unchanged followed by one blanket impl of that trait for `__Context__`. + +## Generated items + +`#[cgp_auto_getter]` emits exactly two items: the trait as written, and a single blanket impl over `__Context__` that implements every getter by reading the like-named field. Unlike `#[cgp_getter]`, there is no provider trait, no component marker, and no `UseField`/`UseFields`/`WithProvider` impls — the field each getter reads is fixed to the method name, so nothing is left to wire. + +Each getter body reads its field with `get_field(PhantomData::)` and appends the field-mode conversion for its return type, and the field itself becomes a `HasField` bound on the impl: + +```rust +// input +#[cgp_auto_getter] +pub trait HasFoo { + fn foo(&self) -> &str; +} + +// derived blanket impl +impl<__Context__> HasFoo for __Context__ +where + __Context__: HasField, +{ + fn foo(&self) -> &str { + self.get_field(PhantomData::).as_str() + } +} +``` + +The conversions are exactly those `#[cgp_getter]` uses — `&str` reads a `String` field and appends `.as_str()`, `Option<&T>` reads `Option` and appends `.as_ref()`, `&[T]` reads an `AsRef<[T]>` field, `MRef<'_, T>` wraps the borrow in `MRef::Ref`, an owned return appends `.clone()`, and a plain `&T` is taken by reference — because both macros share the [getter-field parsing](../asts/cgp_getter.md). The difference is only that `#[cgp_auto_getter]` emits a blanket impl on `__Context__` while `#[cgp_getter]` emits provider impls. + +## Behavior and corner cases + +**A supertrait on the getter trait becomes a context bound on the impl.** The trait's supertrait constraints are lowered to a `__Context__: Supertrait` predicate on the blanket impl, so a getter trait can require capabilities of any context that implements it without those constraints appearing on the impl's `Self` in trait position. + +**A single associated return type is supported and inferred.** A getter trait may declare one `type Name;` used as its method's return type; the blanket impl adds `Name` as a generic parameter, sets `type Name = Name;`, and carries any bound on it (for example `Name: Display`, or a self-referential `Scalar: Mul`) onto the impl with `Self::Name` rewritten to the parameter. More than one associated type, or an associated type alongside more than one method, is rejected. + +**A generic parameter on the trait is preserved onto the impl.** A trait generic over a type parameter keeps that parameter on the blanket impl and threads it through the field bound, so the same getter works for any field type inferred from the argument. + +**A getter can read a field of another type.** A method with a typed receiver (`fn foo_bar(foo: &Self::Foo) -> &Self::Bar`) reads the field out of that receiver type; `Self` in the receiver is rewritten to the context, and the `HasField` bound lands on the receiver type rather than the context. + +## Snapshots + +Every `snapshot_cgp_auto_getter!` invocation across the suite is indexed here, since these snapshots all belong to this entrypoint: + +- [getters/string_auto.rs](../../../crates/tests/cgp-tests/tests/getters/string_auto.rs) — the canonical plain case: a `&str` getter over a `String` field, `.as_str()` applied, no wiring. +- [getters/clone_auto.rs](../../../crates/tests/cgp-tests/tests/getters/clone_auto.rs) — an owned return `.clone()`d out by value. +- [getters/mref_auto.rs](../../../crates/tests/cgp-tests/tests/getters/mref_auto.rs) — an `MRef<'_, String>` return wrapping the borrow in `MRef::Ref`. +- [getters/option_auto.rs](../../../crates/tests/cgp-tests/tests/getters/option_auto.rs) — an `Option<&String>` return reading an `Option` field via `.as_ref()`. +- [getters/slice_auto.rs](../../../crates/tests/cgp-tests/tests/getters/slice_auto.rs) — a `&[u8]` return reading an `AsRef<[u8]> + 'static` field via `.as_ref()`. +- [getters/non_self_auto.rs](../../../crates/tests/cgp-tests/tests/getters/non_self_auto.rs) — a non-`self` getter reading a field out of another type (`&Self::Foo`). +- [getters/auto_getter_generic.rs](../../../crates/tests/cgp-tests/tests/getters/auto_getter_generic.rs) — a trait generic over a type parameter, keyed by a `PhantomData` tag. +- [getters/assoc_type_auto_getter.rs](../../../crates/tests/cgp-tests/tests/getters/assoc_type_auto_getter.rs) — a local associated return type inferred from the field, with a `Display` bound carried onto the impl. +- [getters/assoc_type_self_referential_auto.rs](../../../crates/tests/cgp-tests/tests/getters/assoc_type_self_referential_auto.rs) — a self-referential associated-type bound surviving onto the impl with `Self::Scalar` rewritten to the parameter. +- [getters/abstract_type_extend.rs](../../../crates/tests/cgp-tests/tests/getters/abstract_type_extend.rs), [getters/abstract_type_use_type.rs](../../../crates/tests/cgp-tests/tests/getters/abstract_type_use_type.rs) — getters whose return type is an abstract type imported via `#[extend]` and `#[use_type]`; each file pins both the auto and the full getter variant. + +Coverage is broad; no distinct expansion variant is currently missing a snapshot. + +## Tests + +Each snapshot file also derives a concrete context and asserts the getter resolves, so the snapshot files carry the behavioral checks too: + +- [getters/string_auto.rs](../../../crates/tests/cgp-tests/tests/getters/string_auto.rs) asserts `context.foo()` returns the `foo` field's contents as `&str`. +- [getters/assoc_type_auto_getter.rs](../../../crates/tests/cgp-tests/tests/getters/assoc_type_auto_getter.rs) confirms the associated type is inferred and the getter compiles under the `Display` bound. +- [getters/auto_getter_generic.rs](../../../crates/tests/cgp-tests/tests/getters/auto_getter_generic.rs) confirms the generic-parameter getter applies to any inferred field type. + +## Source + +The entry point is `cgp_auto_getter` in [cgp-macro-lib/src/cgp_auto_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs), which rejects any attribute argument and runs `ItemCgpAutoGetter::preprocess(...).to_items()`. The stack lives in [cgp-macro-core/src/types/cgp_auto_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_auto_getter/) and is documented in [asts/cgp_getter.md](../asts/cgp_getter.md): `item.rs` sets the `__Context__` identifier and drives field parsing, and `blanket.rs` builds the single blanket impl. Getter-method parsing and the return-type shorthands are shared with `#[cgp_getter]` in [cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs), [cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), and [cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/), and all generated fragments are built with [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/entrypoints/cgp_component.md b/docs/implementation/entrypoints/cgp_component.md index ec88db39..6fffce5a 100644 --- a/docs/implementation/entrypoints/cgp_component.md +++ b/docs/implementation/entrypoints/cgp_component.md @@ -1,73 +1,88 @@ # `#[cgp_component]` — implementation -`#[cgp_component]` turns one consumer trait into a full component by running a three-stage transform pipeline that parses the trait, derives the provider trait and blanket impls, and emits the standard provider impls. This document covers how that pipeline is built; for what the macro accepts and the expansion a user sees, read the reference document [reference/macros/cgp_component.md](../../reference/macros/cgp_component.md). +`#[cgp_component]` turns one consumer trait into a full component by parsing the trait, deriving the provider trait and the blanket impls that route between the two sides, and emitting the standard provider impls. This document covers how that works internally; for the accepted syntax and the complete expansion a user sees, read the reference document [reference/macros/cgp_component.md](../../reference/macros/cgp_component.md). ## Entry point -The macro is driven by the thin `cgp_component` function in [cgp-macro-lib/src/cgp_component.rs](../../../crates/macros/cgp-macro-lib/src/cgp_component.rs), which follows the canonical entry-point shape: it parses the attribute tokens into a [`CgpComponentArgs`](../asts/cgp_component.md) and the item tokens into a `syn::ItemTrait`, assembles them into an `ItemCgpComponent`, and runs the pipeline in one expression, wrapping the resulting items in a `quote!`: +The macro is driven by the thin `cgp_component` function in [cgp-macro-lib/src/cgp_component.rs](../../../crates/macros/cgp-macro-lib/src/cgp_component.rs), which follows the canonical entry-point shape: it parses the attribute into a `CgpComponentArgs` and the item into a `syn::ItemTrait`, then runs the pipeline and emits the result. ```rust let item_cgp_component = ItemCgpComponent { args, item_trait }; let derived = item_cgp_component.preprocess()?.eval()?.to_items()?; ``` -All real logic lives in `cgp-macro-core`; the entry function contains no codegen of its own. The `syn::parse2` of the attribute is where the argument grammar is enforced, so a malformed attribute fails here through [`CgpComponentArgs`](../asts/cgp_component.md)'s `Parse` impl, and applying the macro to a non-trait item fails at the `syn::parse2::` call. +All real logic lives in `cgp-macro-core`. Two failures surface here: a malformed attribute is rejected while parsing `CgpComponentArgs` (the argument grammar is enforced by its `Parse` impl), and applying the macro to a non-trait item fails at `syn::parse2::`. ## Pipeline -The macro moves through three explicit stages, each a method on the AST type produced by the previous one; the [`cgp_component` AST stack](../asts/cgp_component.md) documents these types in full, and this section only names what each stage contributes. +The macro moves through three stages, each a method on the AST type the previous one produced; the [`cgp_component` AST stack](../asts/cgp_component.md) documents those types in full. -The **preprocess** stage (`ItemCgpComponent::preprocess`) strips the CGP-specific attributes off the trait through `CgpComponentAttributes::preprocess`, separating the modifier attributes (`#[derive_delegate]`, `#[prefix]`, and the rest) from the plain trait, and produces a `PreprocessedCgpComponent` holding the args, the cleaned `ItemTrait`, and the parsed attributes. No code is generated yet; this stage only normalizes the input. - -The **eval** stage (`PreprocessedCgpComponent::eval`) is where the core derivation happens. It builds the component marker struct, the provider trait, the provider blanket impl, and the consumer blanket impl, and packages them with the original consumer trait and the attributes into an `EvaluatedCgpComponent`. Each derived item is produced by a dedicated method — `to_component_struct`, `to_provider_trait_and_blanket_impl`, and `to_consumer_item_impl` — described under Generated items. - -The **to_items** stage (`EvaluatedCgpComponent::to_items`) collects the five core items in emission order and appends the standard provider impls — the `UseContext` impl, the `RedirectLookup` impl, one `UseDelegate` impl per `#[derive_delegate]` attribute, and one prefix impl per `#[prefix]` attribute — returning the `Vec` the entry function emits. +- **preprocess** strips the CGP modifier attributes (`#[derive_delegate]`, `#[prefix]`, and the rest) off the trait, separating them from the plain trait the later stages transform. +- **eval** is the core derivation: it builds the provider trait, the consumer and provider blanket impls, and the component marker struct. +- **to_items** renders everything into the final `Vec`, appending the standard provider impls (`UseContext`, `RedirectLookup`, and one `UseDelegate` or prefix impl per modifier attribute). ## Generated items -The macro emits five core items followed by the standard provider impls, and the emission order is fixed by `EvaluatedCgpComponent::to_items`: consumer trait, consumer blanket impl, provider trait, provider blanket impl, component struct, then the provider impls. This order is what the canonical snapshot in `component_macro.rs` pins, so it is a contract, not an incidental detail. - -The **consumer trait** is emitted unchanged from the preprocessed `ItemTrait` — the macro clones it into the output verbatim, minus the CGP attributes stripped during preprocess. +The macro emits five core items in a fixed order — consumer trait, consumer blanket impl, provider trait, provider blanket impl, component struct — followed by the standard provider impls. The order is what the canonical snapshot pins, so it is a contract rather than an incidental detail. -The **provider trait** is built by `PreprocessedCgpComponent::to_provider_trait` (in `preprocessed/to_provider_trait.rs`). It clones the consumer trait, renames it to the provider identifier, inserts the context type parameter (`__Context__` by default) at the front of the generics, and moves the consumer trait's supertraits into a `__Context__: ` predicate in the `where` clause. It then replaces the trait's sole supertrait with the `IsProviderFor` bound, where the `Params` tuple comes from [`parse_is_provider_params`](../functions/parse/is_provider_params.md) over the consumer generics. Finally it rewrites every `self`/`Self` in the signatures to the context value and type using the `ReplaceSelfType`, `ReplaceSelfReceiver`, and `ReplaceSelfValue` visitors, so a method that took `&self` now takes `__context__: &__Context__`. Local associated types declared by the trait are collected first and passed to the type visitor as `skip_assoc_types`, so a reference to one of the trait's own associated types is left qualified rather than being rewritten onto the context. +The interesting work is deriving the provider trait from the consumer trait: the original `Self` becomes an explicit leading context parameter, `self`/`Self` in every signature are rewritten to the context (via the `replace_self` visitors), and the trait's sole supertrait becomes an [`IsProviderFor`](../../reference/traits/is_provider_for.md) bound that captures the component and its parameters. A method that took `&self` ends up taking the context by value-name: -The **provider blanket impl** is built alongside the provider trait by `to_provider_trait_and_blanket_impl` (in `preprocessed/to_provider_blanket_impl.rs`), which returns both so they share one construction of the provider trait. It implements the provider trait for a fresh `__Provider__` parameter under two `where` predicates: `__Provider__: DelegateComponent + IsProviderFor`, and `<__Provider__ as DelegateComponent>::Delegate: `. The method bodies forward each call to the delegate through [`provider_trait_to_impl_items`](../functions/derive/delegated_impls.md). The `IsProviderFor` bound sits on `__Provider__` itself, beside `DelegateComponent`, which is what threads a component's dependencies down the delegation chain. - -The **consumer blanket impl** is built by `to_consumer_item_impl` (in `preprocessed/to_consumer_impl.rs`). It implements the consumer trait for `__Context__` under the predicate `__Context__: <__Context__, …>` (plus a `__Context__: ` predicate when the consumer trait has supertraits), and forwards each consumer method to the provider through the same delegated-impl helper. This is the bridge that makes `context.method()` resolve once a context implements the provider trait for itself. - -The **component struct** is built by `to_component_struct` as an `EmptyStruct` from the component name and its generics, emitting `pub struct Component;` (carrying `PhantomData` generics when the component name has type parameters). +```rust +// consumer trait +pub trait CanCalculateArea { + fn area(&self) -> f64; +} + +// derived provider trait +pub trait AreaCalculator<__Context__>: + IsProviderFor +{ + fn area(__context__: &__Context__) -> f64; +} +``` -Beyond the five core items, `to_items` appends the standard provider impls. The **`UseContext` impl** (`evaluated/to_use_context_impl.rs`) implements the provider trait for `UseContext` by routing each method back through the context's own consumer-trait impl, under `__Context__: `. The **`RedirectLookup` impl** (`evaluated/to_redirect_lookup_impl.rs`) implements the provider trait for `RedirectLookup<__Components__, __Path__>`, the mechanism behind namespaces and the `open` statement; when the component has type parameters it appends them to the lookup path through `ConcatPath` (so a parameter `T` extends the path by `PathCons`), and when it has none it looks up `__Path__` directly. Each `#[derive_delegate]` attribute adds a **`UseDelegate` impl** via `to_use_delegate_impls`, and each `#[prefix]` attribute (from a `#[cgp_namespace]`) adds a **prefix impl** via `to_prefix_impls`. +The two blanket impls are the routing machinery and are forwarding shells: the consumer impl makes any context that implements the provider trait for itself gain the consumer trait, and the provider impl lets any provider that delegates the component (via [`DelegateComponent`](../../reference/traits/delegate_component.md)) inherit the provider trait from its delegate. Both forward each method body to the chosen type through the shared [delegated-impl helpers](../functions/derive/delegated_impls.md), which is why their bodies all read as `::method(context, …)`. The `UseContext` and `RedirectLookup` provider impls are two more forwarding shells over the same helpers — one routing back through the context's own consumer impl, the other along a namespace lookup path. ## Behavior and corner cases -A supertrait on the consumer trait is not kept as a supertrait on the provider trait; it becomes a `where` predicate on the context. `to_provider_trait` moves the consumer supertraits into `__Context__: ` and replaces the provider trait's supertrait list with the single `IsProviderFor` bound, so `pub trait CanGreet: HasName` yields a provider trait whose only supertrait is `IsProviderFor<…>` and whose `where` clause carries `__Context__: HasName`. The same `__Context__: HasName` predicate is threaded onto the consumer blanket impl, the `UseContext` impl, and the `RedirectLookup` impl, so every generated impl repeats the supertrait as a context bound. +A **supertrait** on the consumer trait is not kept as a supertrait on the provider trait; it is lowered to a bound on the context, and the same context bound is threaded onto every generated impl. So `pub trait CanGreet: HasName` produces: -A default method body is preserved into the provider trait. Because `to_provider_trait` clones the whole consumer trait including method bodies and only rewrites `self`/`Self`, a consumer method with a default body becomes a provider-trait method with the same body rewritten onto `__context__`; a provider written as an empty `#[cgp_impl]` then inherits that default. This is why an empty provider impl can satisfy a component whose methods all have defaults. +```rust +pub trait Greeter<__Context__>: IsProviderFor +where + __Context__: HasName, +{ /* … */ } +``` -Generic parameters on the component are appended after the context in the provider trait and grouped into the `IsProviderFor` params tuple. A lifetime parameter is kept ahead of `__Context__` (lifetimes must precede type parameters in Rust generics) and is lifted into `Life<'a>` inside the params tuple by `parse_is_provider_params`, so `HasReference<'a, T>` produces `IsProviderFor<…, (Life<'a>, T)>`. In the `RedirectLookup` impl only *type* parameters extend the lookup path — `generic_params_to_path` filters to `GenericParam::Type`, so lifetimes and const parameters are excluded from the `ConcatPath` path even though the lifetime still appears in the params tuple. +A **default method body** is preserved into the provider trait, because the provider trait is a clone of the consumer trait with only `self`/`Self` rewritten. This is what lets an empty `#[cgp_impl]` provider inherit the default and satisfy the component with no method of its own. -The reserved identifiers are emitted literally. The context parameter is `__Context__` unless the `context` key overrides it, the provider parameter in the provider blanket impl is the hardcoded `__Provider__`, and the `RedirectLookup` impl introduces `__Components__` and `__Path__`. These names are chosen to avoid clashing with a user's own type parameters and appear verbatim in the generated code and every snapshot. +**Generic parameters** on the component are appended after the context in the provider trait and collected into the `IsProviderFor` params tuple. A lifetime stays ahead of the context (lifetimes must precede type parameters) and is lifted into `Life<'a>` in that tuple, so `HasReference<'a, T>` yields `IsProviderFor<…, (Life<'a>, T)>`. Only *type* parameters, not lifetimes or const parameters, extend the `RedirectLookup` lookup path. + +The **reserved identifiers** appear literally in the output: the context parameter is `__Context__` (unless the `context` key overrides it), the provider parameter is `__Provider__`, and the `RedirectLookup` impl introduces `__Components__` and `__Path__`. These names are chosen so they never clash with a user's own type parameters. ## Known issues -A const generic parameter on the component causes a panic rather than a clean error. `parse_is_provider_params` reaches `unimplemented!("const generic parameters are not yet supported in CGP traits")` for a `GenericParam::Const`, so `#[cgp_component]` on a trait with a const generic aborts macro expansion with a panic instead of returning a `syn::Error` pointing at the offending parameter. The correct behavior would be to reject the input with a spanned error, or to support const parameters in the params tuple; until then, components cannot carry const generics. This limitation has no expansion snapshot (the macro cannot produce output) and is a candidate for a failure case in `cgp-macro-tests`. +A const generic parameter on the component causes a **panic** rather than a clean error: building the params tuple hits an `unimplemented!` for const parameters (see [parse_is_provider_params](../functions/parse/is_provider_params.md)). Applying `#[cgp_component]` to a trait with a const generic therefore aborts expansion with a panic instead of a spanned `syn::Error`; the correct behavior would be a clean rejection or genuine const support. Because the macro produces no output, this case has no expansion snapshot and is a candidate failure case for `cgp-macro-tests`. ## Snapshots -The canonical full-expansion snapshot and the macro's distinct variants live in the concept targets that own the corresponding feature, per [crates/tests/CLAUDE.md](../../../crates/tests/CLAUDE.md); this section is the central index of which `#[cgp_component]` expansions are pinned and which are not. +Every `snapshot_cgp_component!` invocation across the suite is indexed here, since these snapshots all belong to this entrypoint: -- The plain, no-parameter expansion is pinned in [basic_delegation/component_macro.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs) — a simple consumer trait with one method, the reference expansion other concepts reuse without re-snapshotting. -- The supertrait-plus-default-method variant is pinned in [basic_delegation/default_methods.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs) — shows the supertrait lowered to a `__Context__` `where` predicate and a default body copied into the provider trait. -- The lifetime-and-type-parameter variant is pinned in [generic_components/component_lifetime.rs](../../../crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs) — shows the lifetime kept ahead of `__Context__`, lifted to `Life<'a>` in the params tuple, and the type parameter appended to the `RedirectLookup` path via `ConcatPath`. -- The namespace and prefix variants — the prefix impls `to_prefix_impls` emits — are pinned across the `namespaces` target, including [namespaces/namespace_basic.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_basic.rs), [namespaces/namespace_symbol_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_symbol_path.rs), [namespaces/namespace_type_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_type_path.rs), [namespaces/namespace_multi.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_multi.rs), [namespaces/redirect_lookup.rs](../../../crates/tests/cgp-tests/tests/namespaces/redirect_lookup.rs), [namespaces/default_impls.rs](../../../crates/tests/cgp-tests/tests/namespaces/default_impls.rs), and [namespaces/prefix_default_namespace.rs](../../../crates/tests/cgp-tests/tests/namespaces/prefix_default_namespace.rs). +- [basic_delegation/component_macro.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs) — the canonical plain expansion (one method, no parameters). +- [basic_delegation/default_methods.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs) — a supertrait lowered to a context `where`-bound plus a default method body copied into the provider trait. +- [generic_components/component_lifetime.rs](../../../crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs) — a lifetime kept ahead of `__Context__`, lifted to `Life<'a>`, with a type parameter extending the `RedirectLookup` path via `ConcatPath`. +- [namespaces/namespace_basic.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_basic.rs), [namespaces/namespace_symbol_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_symbol_path.rs), [namespaces/namespace_type_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_type_path.rs), [namespaces/namespace_multi.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_multi.rs), [namespaces/redirect_lookup.rs](../../../crates/tests/cgp-tests/tests/namespaces/redirect_lookup.rs), [namespaces/default_impls.rs](../../../crates/tests/cgp-tests/tests/namespaces/default_impls.rs), [namespaces/prefix_default_namespace.rs](../../../crates/tests/cgp-tests/tests/namespaces/prefix_default_namespace.rs) — the namespace and prefix-impl variants. -Two variants have no snapshot yet. There is no snapshot of the `UseDelegate` impl that a `#[derive_delegate]` attribute adds to a `#[cgp_component]` definition — that attribute's output is exercised through the error and handler families rather than pinned on a bare component here (see [reference/attributes/derive_delegate.md](../../reference/attributes/derive_delegate.md)). And there is no snapshot of a component carrying a type parameter but no lifetime, distinct from the combined lifetime-and-type case above; the type-only path through `generic_params_to_path` is therefore only covered incidentally. +Two variants have no snapshot yet: the `UseDelegate` impl a `#[derive_delegate]` attribute adds to a bare component (exercised through the error and handler families instead), and a component carrying a type parameter but no lifetime, distinct from the combined lifetime-and-type case above. ## Tests -Beyond the snapshots above, the behavioral tests in [crates/tests/cgp-tests](../../../crates/tests/cgp-tests) verify that the generated wiring actually works: [basic_delegation/default_methods.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs) confirms at run time that an empty provider impl picks up the default method bodies and that `App.greet()` returns the expected string, and [generic_components/component_lifetime.rs](../../../crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs) checks the lifetime-carrying component wires and passes `check_components!`. The failure case in [cgp-macro-tests/tests/parser_rejections/cgp_component.rs](../../../crates/tests/cgp-macro-tests/tests/parser_rejections/cgp_component.rs) asserts that applying the macro to a non-trait item (a struct) is rejected at parse time rather than producing garbage output. +The behavioral tests confirm the generated wiring works: + +- [basic_delegation/default_methods.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs) checks at run time that an empty provider impl inherits the default bodies and `App.greet()` returns the expected string. +- [generic_components/component_lifetime.rs](../../../crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs) wires the lifetime-carrying component and passes `check_components!`. +- [cgp-macro-tests/tests/parser_rejections/cgp_component.rs](../../../crates/tests/cgp-macro-tests/tests/parser_rejections/cgp_component.rs) asserts the macro rejects a non-trait item at parse time. ## Source -The entry point is `cgp_component` in [cgp-macro-lib/src/cgp_component.rs](../../../crates/macros/cgp-macro-lib/src/cgp_component.rs). The pipeline and its AST types live in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/): argument parsing in `args/`, the provider trait and both blanket impls in `preprocessed/`, and the standard provider impls in `evaluated/`. The AST stack is documented in [asts/cgp_component.md](../asts/cgp_component.md); the shared codegen helpers it calls are documented in [functions/derive/delegated_impls.md](../functions/derive/delegated_impls.md) and [functions/parse/is_provider_params.md](../functions/parse/is_provider_params.md); the `parse_internal!` macro used throughout is documented in [macros/parse_internal.md](../macros/parse_internal.md). +The entry point is `cgp_component` in [cgp-macro-lib/src/cgp_component.rs](../../../crates/macros/cgp-macro-lib/src/cgp_component.rs); the pipeline and its AST types live in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/) and are documented in [asts/cgp_component.md](../asts/cgp_component.md). The forwarding bodies come from the [delegated-impl helpers](../functions/derive/delegated_impls.md), the params tuple from [parse_is_provider_params](../functions/parse/is_provider_params.md), and all generated fragments are built with [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/entrypoints/cgp_computer.md b/docs/implementation/entrypoints/cgp_computer.md new file mode 100644 index 00000000..1e356ebe --- /dev/null +++ b/docs/implementation/entrypoints/cgp_computer.md @@ -0,0 +1,67 @@ +# `#[cgp_computer]` — implementation + +`#[cgp_computer]` turns a plain function into a [`Computer`](../../reference/components/computer.md) (or `AsyncComputer`) provider by emitting a `#[cgp_new_provider]` impl that calls the function and a `delegate_components!` block that promotes the rest of the handler family from that base. This document covers how the macro is built; for the accepted syntax and the full expansion a user sees, read the reference document [reference/macros/cgp_computer.md](../../reference/macros/cgp_computer.md). + +## Entry point + +The macro is the `cgp_computer` function in [cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs). Unlike the `cgp-macro-lib` macros, it is a self-contained procedural function rather than a driver over a `cgp-macro-core` AST stack: it parses the body into a `syn::ItemFn`, resolves the provider name, inspects the signature, and assembles the output with `quote!` directly. The only piece it borrows from the core crate is `to_camel_case_str`, used to derive the default provider name. + +The provider name comes from the attribute: when the attribute is empty the function name is converted to PascalCase (`add` becomes `Add`), otherwise the attribute tokens are parsed as the provider identifier. A `self` receiver on the function is rejected with a spanned error, since a handler provider has no receiver. + +## Pipeline + +There is no staged AST pipeline; the function branches on two independent axes read off the signature and emits the three items in one pass. + +- **Sync vs. async** — `fn_sig.asyncness` selects between a [`Computer`](../../reference/components/computer.md) base (the `compute` method) and an `AsyncComputer` base (an `async fn compute_async` that `.await`s the call). +- **Value vs. `Result`** — the function's return type is re-parsed as a [`MaybeResultType`](../../../crates/macros/cgp-extra-macro-lib/src/parse/maybe_result.rs), a small speculative parser that reports whether the output is written as `Result<_, E>`. This choice does not change the base impl (the `Output` associated type is the return type verbatim); it only selects which promotion bundle the `delegate_components!` block wires the rest of the family to. + +## Generated items + +The macro emits three items in order: the original function unchanged, a `#[cgp_new_provider]` impl of the base trait, and a `delegate_components!` block. The base impl collects the function's parameters into a single input tuple and destructures it back into positional `arg_0, arg_1, …` bindings inside the method body before calling the function: + +```rust +// #[cgp_computer] fn add(a: u64, b: u64) -> u64 { a + b } +#[cgp_new_provider] +impl<__Context__, __Code__> Computer<__Context__, __Code__, (u64, u64)> for Add { + type Output = u64; + + fn compute(_context: &__Context__, _code: PhantomData<__Code__>, (arg_0, arg_1): (u64, u64)) -> Self::Output { + add(arg_0, arg_1) + } +} +``` + +The function's own generics and `where` clause are cloned onto the impl, and the reserved `__Context__` and `__Code__` type parameters are appended after them, so a generic function stays generic in its provider. The `delegate_components!` block then routes every remaining handler component to a promotion bundle chosen by the two axes: + +- **sync, value** → `PromoteComputer`, over the seven non-`Computer` components. +- **sync, `Result`** → `PromoteTryComputer`, over the same seven components. +- **async, value** → `PromoteAsyncComputer`, over the smaller async set (`AsyncComputerRefComponent`, `HandlerComponent`, `HandlerRefComponent`). +- **async, `Result`** → `PromoteHandler`, over the same async set. + +The async branches delegate fewer components because the synchronous members of the family are not derivable from an async base. + +## Behavior and corner cases + +A **`self` receiver** is rejected with a spanned `syn::Error` ("Computer functions cannot have a receiver"); every other parameter is treated as part of the input tuple. Parameter *patterns* are discarded — each input is rebound positionally as `arg_i`, so a destructuring pattern in the source signature is replaced by a plain binding. + +A **reference parameter** is kept verbatim in the input-tuple type, so `fn f(value: &Value)` yields an input tuple `(&Value)`; the `PromoteComputer` bundle's `…Ref` entries then make the provider serve the `…Ref` components as well. + +The **`Result` detection is purely syntactic**. `MaybeResultType` forks the token stream and checks whether the return type's leading identifier is literally `Result`; a type-aliased result or a `Result` under a different name reads as the value case and wires `PromoteComputer` rather than `PromoteTryComputer`. + +An **omitted return type** defaults to `()`, so a unit-returning function produces a value-case `Computer` with `Output = ()`. + +## Tests + +The behavioral tests exercise the generated provider across the handler family: + +- [handlers/computer_macro.rs](../../../crates/tests/cgp-tests/tests/handlers/computer_macro.rs) — a synchronous infallible function, a `Result`-returning function, and a generic function, each called as `compute`, `try_compute`, `compute_async`, and `handle` plus their `…Ref` variants. +- [handlers/handler_macro.rs](../../../crates/tests/cgp-tests/tests/handlers/handler_macro.rs) — an `async` function (value and `Result` bodies) reached through the async promotion into `Handler`. +- [handlers/pipe_computers.rs](../../../crates/tests/cgp-tests/tests/handlers/pipe_computers.rs), [handlers/pipe_handlers.rs](../../../crates/tests/cgp-tests/tests/handlers/pipe_handlers.rs) — `#[cgp_computer]` providers composed through `PipeHandlers`. +- [dispatching/compose.rs](../../../crates/tests/cgp-tests/tests/dispatching/compose.rs) — `#[cgp_computer]` field-reader providers composed into a higher-order provider. +- [monadic_handlers/ok_monadic.rs](../../../crates/tests/cgp-tests/tests/monadic_handlers/ok_monadic.rs), [monadic_handlers/err_monadic.rs](../../../crates/tests/cgp-tests/tests/monadic_handlers/err_monadic.rs), [monadic_handlers/ok_err_monadic_trans.rs](../../../crates/tests/cgp-tests/tests/monadic_handlers/ok_err_monadic_trans.rs) — `#[cgp_computer]` providers chained through the monadic combinators. + +There is no dedicated `snapshot_cgp_computer!` macro; the macro's expansion is not pinned by a snapshot and is exercised only behaviorally. + +## Source + +The entry point is `cgp_computer` in [cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs), forwarded from the proc-macro shim in [cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs). The `Result`-versus-value split is [`MaybeResultType`](../../../crates/macros/cgp-extra-macro-lib/src/parse/maybe_result.rs). The emitted items lean on constructs documented separately — the base impl on [`#[cgp_new_provider]`](cgp_new_provider.md), the wiring on [`delegate_components!`](delegate_components.md) — and the input-less sibling macro is [`#[cgp_producer]`](cgp_producer.md). diff --git a/docs/implementation/entrypoints/cgp_fn.md b/docs/implementation/entrypoints/cgp_fn.md new file mode 100644 index 00000000..cefff4d8 --- /dev/null +++ b/docs/implementation/entrypoints/cgp_fn.md @@ -0,0 +1,98 @@ +# `#[cgp_fn]` — implementation + +`#[cgp_fn]` turns one plain Rust function into a single-implementation capability by deriving a trait carrying the method and a blanket impl of that trait over a generic context, pulling every `#[implicit]` argument out of the signature and reading it from the context's fields. This document covers how that works internally; for the accepted syntax and the complete expansion a user sees, read the reference document [reference/macros/cgp_fn.md](../../reference/macros/cgp_fn.md). + +## Entry point + +The macro is driven by the thin `cgp_fn` function in [cgp-macro-lib/src/cgp_fn.rs](../../../crates/macros/cgp-macro-lib/src/cgp_fn.rs), which parses the attribute into an optional trait-name `Ident` and the item into a `syn::ItemFn`, then runs the two-stage pipeline and emits the result. + +```rust +let item_cgp_fn = ItemCgpFn { ident, item_fn }; +let items = item_cgp_fn.preprocess()?.to_items()?; +``` + +Two failures surface at the boundary: applying the macro to a non-function item fails at `parse2::`, and a malformed attribute (anything other than a single optional identifier) fails at `parse2::>`. All real logic lives in `cgp-macro-core`. + +## Pipeline + +The macro moves through two stages, each a method on the AST type the previous one produced; the [`cgp_fn` AST stack](../asts/cgp_fn.md) documents those types in full. + +- **preprocess** normalizes the function into the pieces the emit stage needs: it derives the trait name (the attribute identifier, or the function name converted to PascalCase), extracts the `#[implicit]` arguments out of the signature and prepends their field-reading bindings to the body, splits the companion attributes (`#[uses]`, `#[extend]`, `#[use_type]`, and the rest) out of the raw attribute list, and moves the function's generics aside. +- **to_items** renders the two output items — the trait carrying the method signature, then the blanket impl over `__Context__` carrying the body. + +## Generated items + +`#[cgp_fn]` emits exactly two items in a fixed order: the trait with the method, and the blanket impl of that trait for the reserved context type `__Context__`. There is no provider struct, no component marker, and no wiring — the method becomes available on every context that satisfies the impl's `where` clause. + +The interesting transform is what happens to an `#[implicit]` argument. The argument is removed from the method signature entirely, its field is required as a `HasField` bound on the impl, and a `let` binding that reads the field is spliced onto the front of the body so the original body sees the name unchanged: + +```rust +// input +#[cgp_fn] +pub fn greet(&self, #[implicit] name: &str) { + println!("Hello, {}!", name); +} + +// derived trait — the implicit argument is gone from the signature +pub trait Greet { + fn greet(&self); +} + +// derived blanket impl — the field is a bound, the binding is prepended +impl<__Context__> Greet for __Context__ +where + Self: HasField, +{ + fn greet(&self) { + let name: &str = self.get_field(PhantomData::).as_str(); + println!("Hello, {}!", name); + } +} +``` + +The conversion applied to each binding is chosen by the argument's type, following the same field-mode rules the getter macros use: a `&str` argument reads a `String` field and appends `.as_str()`, an owned value appends `.clone()`, an `Option<&T>` reads an `Option` field and appends `.as_ref()`, an `&[T]` reads an `AsRef<[T]>` field and appends `.as_ref()`, and a plain `&T` is taken by reference with no conversion. A `&mut self` receiver switches the reads to `HasFieldMut`/`get_field_mut`. These modes are shared with `#[cgp_auto_getter]` and `#[cgp_getter]` through the [field-parsing helpers](../asts/cgp_getter.md); the difference is only where the read lands — a prepended `let` in the body here, a getter-method body there. + +## Behavior and corner cases + +**Generic parameters and the `where` clause split deliberately.** Every generic parameter in the function's `<...>` list is copied onto both the generated trait and the impl, while the function's own `where` clause is treated as an impl-side dependency and lands only on the impl, hidden from the trait interface. The implicit `HasField` bounds are always appended last, after any attribute-contributed predicates, so the impl's `where` clause reads user-declared bounds first and field bounds last. + +**The companion attributes are layered into the same two items.** `#[uses(Trait)]` and `#[extend(Trait)]` each push a `Self: Trait` predicate onto the impl; `#[extend(Trait)]` additionally makes `Trait` a supertrait of the generated trait, `#[extend_where(...)]` adds predicates to the trait's own `where` clause, `#[impl_generics(...)]` inserts parameters into the impl generics only, and `#[use_type]`/`#[use_provider]` transform the trait and impl as documented on their own pages. Any attribute the parser does not recognize (for example `#[async_trait]` or `#[allow(...)]`) is preserved as a raw attribute and re-attached to both the trait and the impl. + +**The visibility is moved, not copied.** `preprocess` takes the function's visibility off the inner `ItemFn` and re-applies it to the generated trait, so the emitted method inside the trait is always inherited-visibility while the trait itself carries the `pub` the user wrote. + +**A `&mut self` receiver constrains the implicit arguments.** At most one mutable implicit argument is allowed when the receiver is `&mut self`, and a mutable field reference requires the `&mut self` receiver; a mutable *pattern* on an implicit argument is rejected outright. These checks are enforced during implicit-argument extraction. + +## Known issues + +`#[cgp_fn]` does not support generics on the desugared *method* itself — generic parameters are only ever lifted onto the trait and impl. A method-level generic is silently treated as a trait/impl generic rather than rejected, which is the intended limitation rather than a bug: method-level generics are considered an advanced case better written as an explicit blanket impl or a [`#[cgp_component]`](../../reference/macros/cgp_component.md) provider. + +## Snapshots + +Every `snapshot_cgp_fn!` invocation across the suite is indexed here, since these snapshots all belong to this entrypoint: + +- [implicit_arguments/cgp_fn_greet.rs](../../../crates/tests/cgp-tests/tests/implicit_arguments/cgp_fn_greet.rs) — the canonical plain case: one `#[implicit]` `&str` argument dropped from the signature and read via `HasField` with `.as_str()` applied. +- [implicit_arguments/cgp_fn_custom_trait_name.rs](../../../crates/tests/cgp-tests/tests/implicit_arguments/cgp_fn_custom_trait_name.rs) — `#[cgp_fn(CanCalculateRectangleArea)]` overrides the generated trait name; two owned `f64` implicits each `.clone()`d. +- [implicit_arguments/cgp_fn_mutable.rs](../../../crates/tests/cgp-tests/tests/implicit_arguments/cgp_fn_mutable.rs) — `&mut self` with a mutable implicit argument, reading through `HasFieldMut`/`get_field_mut`. +- [implicit_arguments/cgp_fn_calling_fn.rs](../../../crates/tests/cgp-tests/tests/implicit_arguments/cgp_fn_calling_fn.rs) — one `#[cgp_fn]` capability depending on another through an explicit `where Self:` bound. +- [implicit_arguments/cgp_fn_multi_and_use_type.rs](../../../crates/tests/cgp-tests/tests/implicit_arguments/cgp_fn_multi_and_use_type.rs) — explicit and implicit arguments mixed, generic method parameters, `#[async_trait]` preserved as a raw attribute, and `#[use_type]` importing and renaming abstract types. +- [async_and_send/cgp_fn_async.rs](../../../crates/tests/cgp-tests/tests/async_and_send/cgp_fn_async.rs) — the canonical async expansion, an `async fn` combined with `#[async_trait]`. +- [generic_components/fn_generic_param.rs](../../../crates/tests/cgp-tests/tests/generic_components/fn_generic_param.rs) — a function generic over a type parameter, showing the parameter moved onto both trait and impl. +- [generic_components/fn_impl_generics.rs](../../../crates/tests/cgp-tests/tests/generic_components/fn_impl_generics.rs) — `#[impl_generics(...)]` adding a generic parameter to the impl only, not the trait. +- [impl_side_dependencies/fn_extend.rs](../../../crates/tests/cgp-tests/tests/impl_side_dependencies/fn_extend.rs) — `#[extend(...)]` adding a supertrait bound to the generated trait. +- [impl_side_dependencies/fn_uses.rs](../../../crates/tests/cgp-tests/tests/impl_side_dependencies/fn_uses.rs) — `#[uses(...)]` importing a `Self` trait bound as an impl-side dependency. +- [higher_order_providers/use_provider_fn.rs](../../../crates/tests/cgp-tests/tests/higher_order_providers/use_provider_fn.rs) — `#[use_provider]` on a `#[cgp_fn]`, borrowing another provider's behavior. +- [abstract_types/use_type_fn_alias.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_alias.rs), [use_type_fn_equality.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_equality.rs), [use_type_fn_extend.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_extend.rs), [use_type_fn_foreign.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_foreign.rs), [use_type_fn_foreign_equality.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_foreign_equality.rs), [use_type_fn_nested_foreign.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_nested_foreign.rs), [use_type_fn_equality_cross_trait.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_equality_cross_trait.rs), [use_type_fn_foreign_equality_cross_trait.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_foreign_equality_cross_trait.rs) — the `#[use_type]` variants (local alias, type-equality bound, `#[extend]` form, foreign generic parameter, and their combinations). + +One variant has no snapshot yet: the `#[extend_where(...)]` attribute is exercised by no `snapshot_cgp_fn!` invocation, so its effect on the trait's own `where` clause is unpinned. + +## Tests + +Because `#[cgp_fn]` emits a blanket impl, its snapshot tests double as behavioral checks — the snapshot file also derives a concrete context and asserts it implements the generated trait, so a compile of the file is itself the wiring check. The runtime assertions worth calling out: + +- [implicit_arguments/cgp_fn_greet.rs](../../../crates/tests/cgp-tests/tests/implicit_arguments/cgp_fn_greet.rs) proves any context with a `name: String` field implements the generated `Greet` trait via a `CheckPerson` bound. +- [implicit_arguments/cgp_fn_calling_fn.rs](../../../crates/tests/cgp-tests/tests/implicit_arguments/cgp_fn_calling_fn.rs) confirms one capability calling another resolves through both blanket impls at run time. +- [impl_side_dependencies/fn_uses.rs](../../../crates/tests/cgp-tests/tests/impl_side_dependencies/fn_uses.rs) and [impl_side_dependencies/fn_extend.rs](../../../crates/tests/cgp-tests/tests/impl_side_dependencies/fn_extend.rs) exercise the two ways of stating a dependency and confirm the resulting bounds are satisfiable. + +## Source + +The entry point is `cgp_fn` in [cgp-macro-lib/src/cgp_fn.rs](../../../crates/macros/cgp-macro-lib/src/cgp_fn.rs); the pipeline and its AST types live in [cgp-macro-core/src/types/cgp_fn/](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/) and are documented in [asts/cgp_fn.md](../asts/cgp_fn.md). Implicit-argument extraction and the field-reading bindings come from [cgp-macro-core/src/functions/implicits/](../../../crates/macros/cgp-macro-core/src/functions/implicits/) and the field-mode helpers under [cgp-macro-core/src/functions/field/](../../../crates/macros/cgp-macro-core/src/functions/field/), companion-attribute parsing from [cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs), and all generated fragments are built with [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/entrypoints/cgp_getter.md b/docs/implementation/entrypoints/cgp_getter.md new file mode 100644 index 00000000..385de5a2 --- /dev/null +++ b/docs/implementation/entrypoints/cgp_getter.md @@ -0,0 +1,86 @@ +# `#[cgp_getter]` — implementation + +`#[cgp_getter]` builds a full getter component — everything `#[cgp_component]` produces — and then appends three field-reading provider impls (`UseFields`, `UseField`, `WithProvider`) so a context can bind each getter to a source field by wiring rather than by method name. This document covers how that works internally; for the accepted syntax and the complete expansion a user sees, read the reference document [reference/macros/cgp_getter.md](../../reference/macros/cgp_getter.md). + +## Entry point + +The macro is driven by the `cgp_getter` function in [cgp-macro-lib/src/cgp_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_getter.rs), which parses the attribute into `CgpComponentRawArgs` and the item into a `syn::ItemTrait`, then reuses the `#[cgp_component]` pipeline before layering the getter-specific impls on top. + +```rust +let evaluated = ItemCgpComponent { args, item_trait }.preprocess()?.eval()?; +let item_getter = ItemCgpGetter::try_from(evaluated)?; +let items = item_getter.to_items()?; +``` + +Before building the component, the entry function derives the default provider name specific to getters: if the user gave no provider identifier and the trait name begins with `Has`, the provider defaults to the remainder plus `Getter` (so `HasName` yields `NameGetter`, component `NameGetterComponent`). Only after that does it hand off to the shared component args conversion. Applying the macro to a non-trait item fails at `parse2::`, and a malformed attribute is rejected by the `CgpComponentRawArgs` parser. + +## Pipeline + +The macro runs the entire `#[cgp_component]` pipeline and then a getter-specific emit stage; the getter-side AST types are documented in the [`cgp_getter` AST stack](../asts/cgp_getter.md) and the component stages in the [`cgp_component` AST stack](../asts/cgp_component.md). + +- **preprocess → eval** are the `#[cgp_component]` stages unchanged: they strip the CGP modifier attributes off the trait, then derive the provider trait, the two routing blanket impls, and the component marker, producing an `EvaluatedCgpComponent`. +- **parse getter fields** happens in `ItemCgpGetter::try_from`, which parses each method of the consumer trait into a `GetterField` (its field name, field type, return type, receiver mode, and field mode) and captures an optional single associated return type. +- **to_items** emits the component's own items first, then appends the three getter provider impls. + +## Generated items + +`#[cgp_getter]` emits the five core `#[cgp_component]` items plus the standard `UseContext`/`RedirectLookup` provider impls, and then adds three more provider impls that all read from `HasField`. The reference document shows the full expansion; the point worth understanding here is what distinguishes the three added impls. + +- **`UseFields`** implements the getter by reading the field named after the method — the same behavior a `#[cgp_auto_getter]` blanket impl gives, but expressed as a provider a context can wire. +- **`UseField<__Tag__>`** implements the getter by reading the field named `__Tag__`, a *free* generic parameter, so wiring `UseField` makes the getter read `first_name` regardless of the method name. This is the whole reason `#[cgp_getter]` exists rather than `#[cgp_auto_getter]`. +- **`WithProvider<__Provider__>`** implements the getter by delegating to an inner `FieldGetter`/`MutFieldGetter` provider, so the field access itself can be supplied by another provider. + +Each of these reads the field through the same getter-method body the auto-getter uses — a `get_field(PhantomData::)` call with the field-mode conversion appended. The `UseField` impl keys on `__Tag__`: + +```rust +// for `fn foo(&self) -> &str` reading a String field +impl<__Context__, __Tag__> FooGetter<__Context__> for UseField<__Tag__> +where + __Context__: HasField<__Tag__, Value = String>, +{ + fn foo(__context__: &__Context__) -> &str { + __context__.get_field(PhantomData::<__Tag__>).as_str() + } +} +``` + +Every provider-trait impl is paired with a matching `IsProviderFor` impl carrying the same bounds, exactly as the component macro pairs its own impls, so wiring failures still name the missing `HasField` bound. + +## Behavior and corner cases + +**The `UseField` and `WithProvider` impls are only emitted for a single-getter trait.** Both `to_use_field_impl` and `to_with_provider_impl` return `None` when the trait declares more than one getter method, because a per-field tag or per-field inner provider is meaningless once several fields are in play; the `UseFields` impl, keyed by method name, is always emitted. + +**A getter can read a field of a type other than the context.** When a method takes a typed receiver rather than `&self` — `fn foo_bar(foo: &Self::Foo) -> &Self::Bar` — the receiver's `Self` is rewritten to the context and the generated impls read the field out of that receiver type instead of the context. The provider impls then bound that receiver type, not the context, with the `HasField` requirement. + +**A single associated return type is supported and inferred from the field.** A getter trait may declare one `type Name;` used as the return type; the associated type is added as an extra generic parameter to each provider impl, set to itself via `type Name = Name;`, and any bound on it (for example `Name: Display`) is carried onto the impl with `Self::Name` rewritten to the parameter. More than one associated type, or an associated type alongside more than one method, is rejected during field parsing. + +**The return-type shorthands are shared with the auto-getter.** The `&str`-reads-`String`, `Option<&T>`-reads-`Option`, `&[T]`-reads-`AsRef<[T]>`, `MRef<'_, T>`, and owned-`.clone()` conversions all come from the shared field-mode parsing, so `#[cgp_getter]` and [`#[cgp_auto_getter]`](cgp_auto_getter.md) treat a given signature identically — they differ only in the items they emit around the shared getter-method body. + +## Snapshots + +Every `snapshot_cgp_getter!` invocation across the suite is indexed here, since these snapshots all belong to this entrypoint: + +- [getters/string.rs](../../../crates/tests/cgp-tests/tests/getters/string.rs) — the canonical full expansion: a `&str` getter over a `String` field, showing all five component items plus the `UseContext`, `RedirectLookup`, `UseFields`, `UseField`, and `WithProvider` impls. +- [getters/clone.rs](../../../crates/tests/cgp-tests/tests/getters/clone.rs) — an owned return `.clone()`d out by value. +- [getters/mref.rs](../../../crates/tests/cgp-tests/tests/getters/mref.rs) — an `MRef<'_, String>` return wrapping the borrow in `MRef::Ref`. +- [getters/option.rs](../../../crates/tests/cgp-tests/tests/getters/option.rs) — an `Option<&String>` return reading an `Option` field via `.as_ref()`. +- [getters/slice.rs](../../../crates/tests/cgp-tests/tests/getters/slice.rs) — a `&[u8]` return reading any `AsRef<[u8]> + 'static` field via `.as_ref()`. +- [getters/non_self.rs](../../../crates/tests/cgp-tests/tests/getters/non_self.rs) — a non-`self` getter reading a field out of another type (`&Self::Foo`). +- [getters/string_custom_name.rs](../../../crates/tests/cgp-tests/tests/getters/string_custom_name.rs) — `#[cgp_getter(GetString)]` overriding the provider name (and component). +- [getters/string_custom_spec.rs](../../../crates/tests/cgp-tests/tests/getters/string_custom_spec.rs) — the brace-spec form overriding provider and component names independently. +- [getters/assoc_type_getter.rs](../../../crates/tests/cgp-tests/tests/getters/assoc_type_getter.rs) — a local associated return type, showing the associated-type parameter threaded through every provider impl. +- [getters/assoc_type_self_referential.rs](../../../crates/tests/cgp-tests/tests/getters/assoc_type_self_referential.rs) — a self-referential associated-type bound with the source field bound by wiring to a differently-named field. +- [getters/abstract_type_extend.rs](../../../crates/tests/cgp-tests/tests/getters/abstract_type_extend.rs), [getters/abstract_type_use_type.rs](../../../crates/tests/cgp-tests/tests/getters/abstract_type_use_type.rs) — getters whose return type is an abstract type imported from another component via `#[extend]` and `#[use_type]`; each file pins both the auto and the full getter variant. + +The `UseDelegate`-table dispatch form of a getter is snapshotted separately in [dispatching/use_delegate_getter.rs](../../../crates/tests/cgp-tests/tests/dispatching/use_delegate_getter.rs), which the dispatching concept owns rather than this entrypoint. One variant has no snapshot yet: a getter component carrying its own generic parameter (distinct from the auto-getter's `auto_getter_generic.rs`). + +## Tests + +The getter snapshot files also wire concrete contexts and assert the getters resolve, so the same files carry the behavioral checks: + +- [getters/string.rs](../../../crates/tests/cgp-tests/tests/getters/string.rs) and [getters/assoc_type_self_referential.rs](../../../crates/tests/cgp-tests/tests/getters/assoc_type_self_referential.rs) confirm that wiring `UseField` makes the getter read a field whose name differs from the method. +- [getters/clone.rs](../../../crates/tests/cgp-tests/tests/getters/clone.rs), [getters/mref.rs](../../../crates/tests/cgp-tests/tests/getters/mref.rs), [getters/option.rs](../../../crates/tests/cgp-tests/tests/getters/option.rs), and [getters/slice.rs](../../../crates/tests/cgp-tests/tests/getters/slice.rs) verify each return-type shorthand at run time. + +## Source + +The entry point is `cgp_getter` in [cgp-macro-lib/src/cgp_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_getter.rs), which derives the `Has…` → `…Getter` default name and reuses the component pipeline. The getter-specific stack lives in [cgp-macro-core/src/types/cgp_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/) and is documented in [asts/cgp_getter.md](../asts/cgp_getter.md): `item.rs` assembles the items, `to_use_fields_impl.rs`/`use_field.rs`/`with_provider.rs` build the three added provider impls. The component stages it reuses are in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/), documented in [asts/cgp_component.md](../asts/cgp_component.md). Getter-method parsing and the return-type shorthands are shared with `#[cgp_auto_getter]` in [cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs) and [cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), and all generated fragments are built with [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/entrypoints/cgp_impl.md b/docs/implementation/entrypoints/cgp_impl.md new file mode 100644 index 00000000..f43e29d7 --- /dev/null +++ b/docs/implementation/entrypoints/cgp_impl.md @@ -0,0 +1,82 @@ +# `#[cgp_impl]` — implementation + +`#[cgp_impl]` lets a provider be written in consumer-trait clothing — an `impl Trait for Context` block that keeps `self`/`Self` — and lowers it into the provider-trait form that CGP requires, then hands that form to the same machinery [`#[cgp_provider]`](cgp_provider.md) drives. This document covers how the lowering works internally; for the accepted syntax and the full before/after expansion, read the reference document [reference/macros/cgp_impl.md](../../reference/macros/cgp_impl.md). + +## Entry point + +The macro is driven by the `cgp_impl` function in [cgp-macro-lib/src/cgp_impl.rs](../../../crates/macros/cgp-macro-lib/src/cgp_impl.rs). It parses the attribute into an `ImplArgs` (the optional `new` keyword, the provider type, and an optional `: ComponentType` override) and the item into a `syn::ItemImpl`, then runs the two-step lowering and emits the result: + +```rust +let item_cgp_impl = ItemCgpImpl { args, item_impl }; +let lowered = item_cgp_impl.lower()?; +let bare_impls = lowered.lower()?; +``` + +The first `lower` produces a `LoweredCgpImpl`; the second turns that into either a raw provider impl (fed through `#[cgp_provider]`) or an untouched consumer impl. The entry function emits `bare_impls` followed by any `default_impls` the block's `#[default_impl]` attributes generated. A malformed attribute is rejected while parsing `ImplArgs`, and applying the macro to a non-`impl` item fails at `syn::parse2::`. + +## Pipeline + +The macro moves through two lowering stages, each a method on the AST type the previous one produced; the [`cgp_impl` AST stack](../asts/cgp_impl.md) documents those types in full. + +- **`ItemCgpImpl::lower`** processes the companion attributes and normalizes the impl header. It strips the CGP modifier attributes (`#[implicit]` arguments, `#[uses]`, `#[use_type]`, `#[use_provider]`, `#[default_impl]`) off the block, folds each into the impl generics or method bodies, and — when the `for Context` clause is omitted — inserts the reserved `__Context__` parameter so later stages always see an explicit context. It records the provider trait path and the context type on the resulting `LoweredCgpImpl`. +- **`LoweredCgpImpl::lower`** performs the consumer-to-provider rewrite: it swaps the provider type into the `Self` position, moves the context to the leading argument of the provider trait, rewrites `self`/`Self` with the [`replace_self` visitors](../asts/cgp_impl.md#the-replace_self-visitors), and hands the result to [`#[cgp_provider]`](cgp_provider.md)'s `ItemCgpProvider::lower`. The `#[cgp_impl(Self)]` special case skips the rewrite entirely and passes the block through unchanged. + +## Generated items + +For a normal provider, the macro emits exactly what `#[cgp_provider]` emits — the provider impl, its derived `IsProviderFor` impl, and (when `new` is set) the provider struct — plus one delegation impl per `#[default_impl]` attribute. The interesting work is upstream of that handoff: turning consumer-style syntax into the provider impl. + +The lowering swaps the `Self` type to the provider, adds the context as the provider trait's leading type argument, and rewrites the receiver into a context parameter. A method that took `&self` becomes a static method taking the context by a snake-cased, double-underscored name derived from the context type: + +```rust +// consumer-style input +#[cgp_impl(new ValueToString)] +impl FooProvider for Context { + fn foo(&self, value: u32) -> String { value.to_string() } +} + +// lowered provider impl handed to #[cgp_provider] +impl FooProvider for ValueToString { + fn foo(__context__: &Context, value: u32) -> String { value.to_string() } +} +``` + +When the `for Context` clause is omitted, the inserted parameter is `__Context__`, so the same rewrite produces `__context__: &__Context__`. Both the explicit `Context` and the default `__Context__` snake-case to the same `__context__` receiver identifier. + +## Behavior and corner cases + +The **receiver identifier** is computed from the context type: if the context type is a bare identifier it is snake-cased and the result used as the parameter name, and any context type that is not a plain identifier falls back to the literal `__context__`. `Context` and `__Context__` both yield `__context__`. Every `self` in a body is rewritten to that identifier, every `Self` type to the context type, via the three `replace_self` visitors run in sequence. + +A **`for Context` clause is optional**, and omitting it is the idiomatic form. When present, the `Self` type of the block *is* the context and the trait path is the provider trait; when absent, `ItemCgpImpl::lower` treats the block's `Self` type as the provider trait path and inserts `__Context__` at the front of the impl generics. + +**Local associated types are preserved by name.** A `type Output = …` the block declares itself is collected before the rewrite so the `replace_self` type visitor leaves `Self::Output` alone rather than rewriting it to the context — only imported abstract types (`Self::Error` from `#[use_type]`) and receiver `self`/`Self` are rewritten. + +The **companion attributes** are applied in `ItemCgpImpl::lower` before the provider rewrite: `#[implicit]` parameters are extracted from each signature and turned into `HasField` bounds on the context (and reads in the body), `#[uses(...)]` and `#[use_provider(...)]` add `Self` trait bounds to the impl generics, `#[use_type(...)]` imports an abstract type and rewrites its occurrences, and each `#[default_impl]` becomes a separate `DelegateComponent`-style impl emitted alongside the provider. + +The **`#[cgp_impl(Self)]` passthrough** bypasses the whole rewrite: when the provider type is the literal `Self`, `LoweredCgpImpl::lower` returns the original `impl` block unchanged as an ordinary consumer-trait impl, so companion attributes still apply while the body keeps its `self` receiver. This form requires the `for Context` clause; omitting it is rejected with a spanned "Expected context type to be specified" error. + +## Known issues + +The `#[cgp_impl(Self)]` form requires an explicit `for Context` clause and errors cleanly when it is missing; there are no other known limitations specific to this macro beyond those inherited from [`#[cgp_provider]`](cgp_provider.md) (see its Known issues). + +## Snapshots + +Every `snapshot_cgp_impl!` invocation across the suite is indexed here, since these snapshots all belong to this entrypoint: + +- [basic_delegation/provider_macro.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/provider_macro.rs) — the canonical plain expansion: `#[cgp_impl(new ValueToString)]` on an explicit `impl FooProvider for Context`, showing the `Self`-to-provider swap, the leading-context insertion, and `&self` becoming `__context__: &Context`. +- [implicit_arguments/cgp_impl_implicit.rs](../../../crates/tests/cgp-tests/tests/implicit_arguments/cgp_impl_implicit.rs) — `#[implicit]` arguments dropped from the signature and turned into `HasField` reads, with the implicit `__Context__` inserted (the `for` clause omitted). +- [higher_order_providers/use_provider_impl.rs](../../../crates/tests/cgp-tests/tests/higher_order_providers/use_provider_impl.rs) — a generic higher-order provider `ScaledArea` with `#[use_provider]` completing the inner provider's bound. +- [namespaces/default_impls.rs](../../../crates/tests/cgp-tests/tests/namespaces/default_impls.rs) — several `#[cgp_impl]` blocks (`ShowString`, `ShowWithDisplay`, `ShowU32`) providing a generic component, exercising the `#[default_impl]` companion attribute alongside the provider rewrite. + +The `#[cgp_impl(Self)]` bare-impl passthrough has no snapshot yet, and neither does a `#[cgp_impl]` carrying an explicit `: ComponentType` override. + +## Tests + +The behavioral tests confirm the lowered wiring works: + +- [basic_delegation/provider_macro.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/provider_macro.rs) wires `FooProviderComponent` to the generated `ValueToString` and checks the call resolves at run time. +- [implicit_arguments/cgp_impl_implicit.rs](../../../crates/tests/cgp-tests/tests/implicit_arguments/cgp_impl_implicit.rs) wires the implicit-argument provider through `delegate_and_check_components!` and confirms the field reads compute the area. +- [higher_order_providers/use_provider_impl.rs](../../../crates/tests/cgp-tests/tests/higher_order_providers/use_provider_impl.rs) wires the scaled higher-order provider onto a context and runs it. + +## Source + +The entry point is `cgp_impl` in [cgp-macro-lib/src/cgp_impl.rs](../../../crates/macros/cgp-macro-lib/src/cgp_impl.rs); the two lowering stages and their AST types live in [cgp-macro-core/src/types/cgp_impl/](../../../crates/macros/cgp-macro-core/src/types/cgp_impl/) and are documented in [asts/cgp_impl.md](../asts/cgp_impl.md). The `self`/`Self` rewriting is done by the `replace_self` visitors in [cgp-macro-core/src/visitors/replace_self/](../../../crates/macros/cgp-macro-core/src/visitors/replace_self/). The handoff target — the provider impl and its `IsProviderFor` derivation — is documented in [entrypoints/cgp_provider.md](cgp_provider.md) and [asts/cgp_provider.md](../asts/cgp_provider.md). diff --git a/docs/implementation/entrypoints/cgp_namespace.md b/docs/implementation/entrypoints/cgp_namespace.md new file mode 100644 index 00000000..e1f702c1 --- /dev/null +++ b/docs/implementation/entrypoints/cgp_namespace.md @@ -0,0 +1,92 @@ +# `cgp_namespace!` — implementation + +`cgp_namespace!` builds a reusable, inheritable wiring table — a *namespace* — by parsing a `delegate_components!`-style body with a namespace header and emitting a lookup trait, an optional marker struct, and one `impl` of that trait per entry. This document covers how that works internally; for the accepted syntax and the complete expansion a user sees, read the reference document [reference/macros/cgp_namespace.md](../../reference/macros/cgp_namespace.md). + +## Entry point + +The macro is driven by the thin `cgp_namespace` function in [cgp-macro-lib/src/cgp_namespace.rs](../../../crates/macros/cgp-macro-lib/src/cgp_namespace.rs). Unlike the attribute macros, it is a function-like macro: it parses the whole body into a single `NamespaceTable`, evaluates it, and renders the result. + +```rust +let namespace_table: NamespaceTable = parse2(body)?; +Ok(namespace_table.eval()?.to_token_stream()) +``` + +There is no separate attribute to parse — the header (`new`, the namespace name, the optional `: parent`, and the generic list) and the entry table are all part of the one `NamespaceTable`, whose `Parse` impl enforces the grammar. A malformed header or entry is rejected there. + +## Pipeline + +The macro is a two-step pipeline: parse into a `NamespaceTable`, then `eval` into an `EvaluatedNamespaceTable` that renders itself with `ToTokens`. The [`namespace` AST stack](../asts/namespace.md) documents those types in full. + +- **parse** reads the header and the entry table. The entry table is the same `DelegateEntries` type that `delegate_components!` parses, so a namespace body accepts the same mappings, array keys, `open`/`namespace`/`for` statements, and `=>` redirects. +- **eval** builds each output item: the lookup trait (only with `new`), the marker struct (only with `new`), one `impl` per evaluated entry, and — when a parent is named — a leading inheritance `impl`. These are collected into the `EvaluatedNamespaceTable`, which emits them in a fixed order through its `ToTokens`. + +## Generated items + +A `new` namespace emits, in order, the marker struct `__{Namespace}Components`, the lookup trait `{Namespace}<__Table__>` carrying a single `type Delegate;`, and one `impl {Namespace}<__Table__> for {Key}` per entry; omitting `new` emits only the per-entry impls, so the trait and struct must already be declared elsewhere. When the header names a parent (`: DefaultNamespace`), an inheritance impl is inserted ahead of the entry impls. The struct-then-trait-then-impls order is what the canonical snapshots pin. + +Each entry lowers to one impl of the lookup trait, keyed on the entry's key type, whose `Delegate` associated type is the entry's target. A `=>` redirect points the delegate at a `RedirectLookup` along the entry's type-level path, while a plain `:` mapping points it straight at a provider. So a redirect and a direct mapping produce the same shape of impl with a different `Delegate`: + +```rust +// new MyNamespace { FooProviderComponent => @MyApp.MyFooComponent, } +impl<__Table__> MyNamespace<__Table__> for FooProviderComponent { + type Delegate = RedirectLookup<__Table__, PathCons>>; +} + +// new DefaultShowComponents { [String, u64]: ShowWithDisplay, } +impl<__Table__> DefaultShowComponents<__Table__> for String { + type Delegate = ShowWithDisplay; +} +``` + +The `@`-path in a redirect desugars along the same rules as elsewhere in CGP: a lowercase segment (`@my_app`) becomes a `Symbol!` in the `PathCons` spine, an uppercase segment (`@MyApp`) stays a type name, and the segments nest right-to-left into `PathCons<…, Nil>`. An array key expands to one impl per component in the array, all sharing the same `Delegate`. + +The **inheritance impl** is what makes a namespace extend a parent. It is built through the same for-entry machinery `delegate_components!` uses, and lowers a parent-namespace clause into a blanket impl that reads each of the parent's entries and re-emits it under the child, so the child inherits every wiring the parent defines: + +```rust +// new ExtendedNamespace: DefaultNamespace { } +impl<__Table__, __Key__, __Value__> ExtendedNamespace<__Table__> for __Key__ +where + __Key__: DefaultNamespace<__ExtendedNamespaceComponents>, + __Key__: DefaultNamespace<__Table__, Delegate = __Value__>, +{ + type Delegate = __Value__; +} +``` + +A `=>` entry in the child body then layers a *path-prefix rewrite* on top of the inheritance: an entry like `@cgp.core.error => @app` emits an impl keyed on the `PathCons` spine of the source prefix followed by a `__Wildcard__` tail, whose delegate redirects to the same wildcard under the rewritten prefix. This is how a child namespace shadows one branch of an inherited path without touching the rest. + +## Behavior and corner cases + +The **`new` keyword** is the switch between defining a namespace and extending an existing one. With `new`, the trait and marker struct are emitted; without it, only the entry impls are, and the caller is responsible for having declared the trait. This is why an inheriting namespace and a plain grouping both start with `new` in practice. + +The **`__Table__` parameter** threads the caller's own table through every impl, so a namespace is not tied to one context: the lookup trait is generic over `__Table__`, each entry impl carries it, and a `RedirectLookup` delegate re-routes lookups back through it. That is what lets many contexts share one namespace, each supplying its own `__Table__`. + +The **reserved identifiers** appear literally in the output. The lookup trait's table parameter is `__Table__`; the inheritance impl introduces `__Key__` and `__Value__`; and a path-prefix rewrite introduces `__Wildcard__` for the inherited tail. The marker struct is always `__{Namespace}Components`, formed by prefixing the namespace identifier with `__` and suffixing `Components`. + +The body **reuses the `delegate_components!` grammar wholesale** — array keys, the leading `open { … }` header, `namespace`/`for` statements, and both `:` and `=>` mappings all parse, because the entries are a `DelegateEntries`. Anything `delegate_components!` accepts in a table, a namespace body accepts too. + +## Snapshots + +Every `snapshot_cgp_namespace!` invocation across the suite is indexed here, since these snapshots all belong to this entrypoint: + +- [namespaces/namespace_basic.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_basic.rs) — a `new` namespace with one `=>` redirect to a bare component, showing the struct, trait, and single `RedirectLookup` impl over a two-element path. +- [namespaces/namespace_symbol_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_symbol_path.rs) — the same shape with a lowercase leading segment (`@my_app.…`), so the path's head is a `Symbol!` rather than a type name. +- [namespaces/namespace_type_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_type_path.rs) — an uppercase leading segment (`@MyApp.…`) that stays a type name in the `PathCons` spine. +- [namespaces/namespace_multi.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_multi.rs) — two namespaces defined in one module (`MyNamespace` with a type-path head, `OtherNamespace` with a symbol head), confirming distinct marker structs and traits. +- [namespaces/extended.rs](../../../crates/tests/cgp-tests/tests/namespaces/extended.rs) — a `: DefaultNamespace` parent with a `@cgp.core.error => @app` prefix rewrite, capturing both the inheritance blanket impl and the wildcard-tail path-rewrite impl. +- [namespaces/default_impls.rs](../../../crates/tests/cgp-tests/tests/namespaces/default_impls.rs) — an array-key direct-mapping namespace (`[String, u64]: ShowWithDisplay`) expanding to one impl per key, and an empty `: DefaultNamespace` extension emitting only the inheritance impl. + +One variant has no dedicated `snapshot_cgp_namespace!` yet: a namespace body carrying a `namespace` or `for` statement (as opposed to plain mappings and `=>` redirects), which is exercised only through the wiring tests below. + +## Tests + +The behavioral tests confirm the generated namespaces wire correctly: + +- [namespaces/namespace_group.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_group.rs) wires a context to a namespace and checks the grouped components resolve. +- [namespaces/extended_namespace_wiring.rs](../../../crates/tests/cgp-tests/tests/namespaces/extended_namespace_wiring.rs) checks that an extended namespace inherits its parent's entries and that the child's prefix rewrite takes effect. +- [namespaces/default_impls_wiring.rs](../../../crates/tests/cgp-tests/tests/namespaces/default_impls_wiring.rs) checks that a `DefaultNamespace`-based namespace supplies defaults a context can override. +- [namespaces/multi_param_namespace.rs](../../../crates/tests/cgp-tests/tests/namespaces/multi_param_namespace.rs) and [namespaces/prefix_default_namespace.rs](../../../crates/tests/cgp-tests/tests/namespaces/prefix_default_namespace.rs) exercise parameterized namespaces and the `#[prefix(...)]` join that attaches a component to one. + +## Source + +The entry point is `cgp_namespace` in [cgp-macro-lib/src/cgp_namespace.rs](../../../crates/macros/cgp-macro-lib/src/cgp_namespace.rs); the pipeline and its AST types live in [cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/) and are documented in [asts/namespace.md](../asts/namespace.md). The entry table reuses the `DelegateEntries` grammar from [cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/), the inheritance impl comes from `inherit.rs`, and the `RedirectLookup` marker and every generated fragment are built with [parse_internal!](../macros/parse_internal.md). The `#[prefix(...)]` attribute that attaches a component to a namespace is handled as part of `#[cgp_component]`; see [entrypoints/cgp_component.md](cgp_component.md). diff --git a/docs/implementation/entrypoints/cgp_new_provider.md b/docs/implementation/entrypoints/cgp_new_provider.md new file mode 100644 index 00000000..0f9b6be5 --- /dev/null +++ b/docs/implementation/entrypoints/cgp_new_provider.md @@ -0,0 +1,42 @@ +# `#[cgp_new_provider]` — implementation + +`#[cgp_new_provider]` is [`#[cgp_provider]`](cgp_provider.md) with the `new` keyword forced on: it runs the identical lowering but also declares the provider struct, so a provider impl and its `Self` type are defined in one place. This document covers only what distinguishes it from `#[cgp_provider]`; for the accepted syntax and the full expansion, read the reference document [reference/macros/cgp_new_provider.md](../../reference/macros/cgp_new_provider.md). + +## Entry point + +The macro is driven by the `cgp_new_provider` function in [cgp-macro-lib/src/cgp_new_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_new_provider.rs). It parses the same `ProviderArgs` and the same `syn::ItemImpl` as `#[cgp_provider]`, sets `args.new` to enabled, and then runs the identical `ItemCgpProvider::lower`: + +```rust +let mut args: ProviderArgs = parse2(attr)?; +args.new = Some(Keyword::default()); +let lowered = ItemCgpProvider { args, item_impl }.lower()?; +``` + +Because everything downstream is shared, the argument grammar, the error paths, and the corner cases are exactly those of `#[cgp_provider]` — the attribute takes only the optional component-type override (the `new` keyword is implied by the macro name, not written in the argument). + +## Pipeline + +The pipeline is `#[cgp_provider]`'s single `ItemCgpProvider::lower` stage; the [`cgp_provider` AST stack](../asts/cgp_provider.md) documents it in full. The only behavioral difference is that `new` is always set, so `to_provider_struct` always emits a struct rather than returning `None`. + +## Generated items + +The macro emits the provider impl (verbatim), the derived `IsProviderFor` impl, and the provider struct — the same three items as `#[cgp_impl(new …)]` and the same first two as `#[cgp_provider]`. See [`#[cgp_provider]`'s Generated items](cgp_provider.md#generated-items) for how the `IsProviderFor` arguments are assembled, and its [Behavior and corner cases](cgp_provider.md#behavior-and-corner-cases) for the struct shape (unit struct for a plain name, `PhantomData` field for a generic provider). + +## Known issues + +None beyond those inherited from [`#[cgp_provider]`](cgp_provider.md#known-issues): a const argument in the provider trait's arguments is rejected with a spanned error. + +## Snapshots + +`#[cgp_new_provider]` has no `snapshot_cgp_new_provider!` invocation across the suite, so its expansion is not pinned directly. The equivalent output is covered indirectly by the `#[cgp_impl(new …)]` snapshots — which desugar to `#[cgp_new_provider]` — indexed in [`#[cgp_impl]`'s Snapshots section](cgp_impl.md#snapshots), and by the const-generic and lifetime `snapshot_cgp_provider!` cases indexed in [`#[cgp_provider]`'s Tests section](cgp_provider.md#tests). A dedicated `#[cgp_new_provider]` snapshot — showing the struct declaration emitted directly rather than via the `#[cgp_impl]` sugar — is a missing variant. + +## Tests + +`#[cgp_new_provider]` is exercised directly in real wiring: + +- [dispatching/compose.rs](../../../crates/tests/cgp-tests/tests/dispatching/compose.rs) defines composed providers with `#[cgp_new_provider]` and wires them into a context. +- [async_and_send/spawn.rs](../../../crates/tests/cgp-tests/tests/async_and_send/spawn.rs) defines a generic `SpawnAndRun` provider with `#[cgp_new_provider]`, exercising the `PhantomData`-field struct shape. + +## Source + +The entry point is `cgp_new_provider` in [cgp-macro-lib/src/cgp_new_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_new_provider.rs). All of the generation logic — including the struct declaration built by `to_provider_struct` when `new` is set — is shared with `#[cgp_provider]` in [cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/), documented in [asts/cgp_provider.md](../asts/cgp_provider.md). The struct-declaring sugar [`#[cgp_impl(new …)]`](cgp_impl.md) desugars to this macro. diff --git a/docs/implementation/entrypoints/cgp_producer.md b/docs/implementation/entrypoints/cgp_producer.md new file mode 100644 index 00000000..f7afb7ea --- /dev/null +++ b/docs/implementation/entrypoints/cgp_producer.md @@ -0,0 +1,53 @@ +# `#[cgp_producer]` — implementation + +`#[cgp_producer]` turns a no-argument function into a [`Producer`](../../reference/components/producer.md) provider by emitting a `#[cgp_new_provider]` impl that calls the function and a `delegate_components!` block that promotes the whole handler family from it. This document covers how the macro is built; for the accepted syntax and the full expansion, read the reference document [reference/macros/cgp_producer.md](../../reference/macros/cgp_producer.md). + +## Entry point + +The macro is the `cgp_producer` function in [cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs). Like [`#[cgp_computer]`](cgp_computer.md), it is a self-contained procedural function rather than a driver over a `cgp-macro-core` AST stack: it parses the body into a `syn::ItemFn`, resolves the provider name (the attribute tokens if present, otherwise the function name in PascalCase via `to_camel_case_str`), validates the signature, and assembles the output with `quote!`. + +## Pipeline + +There is no staged AST pipeline and, unlike `#[cgp_computer]`, no branching — a producer has exactly one shape. The function validates the signature against the producer's constraints and then emits a fixed set of three items. The three constraints are each checked before any code is generated: + +- **no parameters** — a producer takes no input and no `self` receiver. +- **not `async`** — the `Producer` trait is synchronous. +- **no generic parameters** — the producer impl introduces only the reserved context and code parameters. + +Each violation returns a spanned `syn::Error` pointing at the offending part of the signature. + +## Generated items + +The macro emits three items: the original function unchanged, a `#[cgp_new_provider]` impl of the [`Producer`](../../reference/components/producer.md) trait, and a `delegate_components!` block. The impl introduces the reserved `__Context__` and `__Code__` parameters, ignores both in its `produce` body, and simply calls the function: + +```rust +// #[cgp_producer] fn magic_number() -> u64 { 42 } +#[cgp_new_provider] +impl<__Context__, __Code__> Producer<__Context__, __Code__> for MagicNumber { + type Output = u64; + + fn produce(_context: &__Context__, _code: PhantomData<__Code__>) -> Self::Output { + magic_number() + } +} +``` + +The `delegate_components!` block then routes all eight handler components — including `ComputerComponent`, which `#[cgp_computer]` never delegates because the computer *is* its own base — to the single `PromoteProducer` bundle. Because a producer ignores its input, that bundle lets every handler shape yield the produced value regardless of any input it is handed. There is no `Result` analysis: the `Output` associated type is the return type verbatim, whether or not it is a `Result`. + +## Behavior and corner cases + +An **omitted return type** defaults to `()`, so a producer written with no return arrow yields `Output = ()`. + +The three signature checks are the macro's only corner cases, and all reject rather than reinterpret: a parameter, an `async` keyword, or a generic parameter each aborts expansion with a spanned error rather than being silently accepted. This is stricter than `#[cgp_computer]`, which accepts parameters, `async`, and generics. + +## Tests + +The behavioral test exercises the generated provider across the handler family: + +- [handlers/producer_macro.rs](../../../crates/tests/cgp-tests/tests/handlers/producer_macro.rs) — an input-free function called as `produce`, `compute`, `try_compute`, `compute_async`, and `handle` plus their `…Ref` variants, all yielding the same value. + +There is no dedicated `snapshot_cgp_producer!` macro; the macro's expansion is not pinned by a snapshot and is exercised only behaviorally. + +## Source + +The entry point is `cgp_producer` in [cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs), forwarded from the proc-macro shim in [cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs). The emitted items lean on [`#[cgp_new_provider]`](cgp_new_provider.md) for the base impl and [`delegate_components!`](delegate_components.md) for the wiring; the input-carrying sibling macro is [`#[cgp_computer]`](cgp_computer.md). diff --git a/docs/implementation/entrypoints/cgp_provider.md b/docs/implementation/entrypoints/cgp_provider.md new file mode 100644 index 00000000..66650987 --- /dev/null +++ b/docs/implementation/entrypoints/cgp_provider.md @@ -0,0 +1,73 @@ +# `#[cgp_provider]` — implementation + +`#[cgp_provider]` takes a provider-trait impl written directly on a provider struct, passes it through unchanged, and derives the matching [`IsProviderFor`](../../reference/traits/is_provider_for.md) impl from the same `where` clause so the provider's dependencies can never drift out of sync. This document covers how that derivation works internally; for the accepted syntax and the full expansion, read the reference document [reference/macros/cgp_provider.md](../../reference/macros/cgp_provider.md). + +## Entry point + +The macro is driven by the `cgp_provider` function in [cgp-macro-lib/src/cgp_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_provider.rs). It parses the item into a `syn::ItemImpl` and the attribute into a `ProviderArgs` (an optional `new` keyword and an optional component-type override), then lowers the impl and emits the result: + +```rust +let item = ItemCgpProvider { args, item_impl }; +let lowered = item.lower()?; +``` + +The sibling [`#[cgp_new_provider]`](cgp_new_provider.md) shares this whole stack: its `cgp_new_provider` entry parses the same `ProviderArgs`, forces `args.new = Some(...)`, and then runs the identical `ItemCgpProvider::lower`. The two macros differ only in whether the provider struct is declared. A malformed attribute is rejected while parsing `ProviderArgs`, and a non-`impl` item fails at `syn::parse2::`. + +## Pipeline + +The macro has a single lowering stage, `ItemCgpProvider::lower`, which produces a `LoweredCgpProvider` bundling three items; the [`cgp_provider` AST stack](../asts/cgp_provider.md) documents those types in full. Within that one stage the work splits three ways: + +- deriving the **component type** — defaulting to the provider trait's name with a `Component` suffix, or using the attribute's explicit override; +- deriving the **`IsProviderFor` impl** — cloning the provider impl, stripping its body and associated types, and swapping the trait for `IsProviderFor`; +- deriving the **provider struct** — emitted only when `new` is set. + +## Generated items + +The macro emits the provider impl (verbatim), the derived `IsProviderFor` impl, and — for `#[cgp_new_provider]` or `#[cgp_impl(new …)]` — the provider struct, in that order. The one piece of real synthesis is the `IsProviderFor` impl. + +Its trait arguments are split out of the provider trait's own arguments: the first is the component type, the second is the provider trait's **leading** type argument (the context), and the third is a tuple of every **remaining** type parameter. A lifetime among the remaining arguments is lifted into `Life<'a>` in that tuple. So a multi-parameter provider trait yields a grouped `Params` tuple: + +```rust +// provider impl +impl ComputerRef for FirstNameToString +where Context: HasField { /* … */ } + +// derived alongside it +impl + IsProviderFor for FirstNameToString +where Context: HasField {} +``` + +The derived impl keeps the original generic parameters and `where` clause verbatim, so it holds under exactly the conditions the provider impl holds. Its body and associated types are cleared, and its `defaultness`/`unsafety` are dropped. + +## Behavior and corner cases + +The **component type defaults** from the provider trait's identifier: `component_type()` reads the trait path, takes its identifier, and appends `Component`, so implementing `AreaCalculator` targets `AreaCalculatorComponent`. The optional attribute argument overrides this with an explicit type — the only thing the attribute changes. + +The **context is the first type argument** of the provider trait, and it must be present. `ProviderImplArgs::from_generic_args` walks the trait's arguments in order, takes the first *type* argument as the context, and collects the rest into the `Params` tuple; lifetimes always go into the tuple (lifted to `Life<'a>`) regardless of position. A provider trait path with no type argument at all is rejected with a spanned error. + +The **`new` keyword controls the struct**, whose shape is read from the impl's `Self` type by `to_provider_struct`. A plain provider name yields a unit `pub struct Name;`. A generic provider yields a struct with a `PhantomData` field binding its parameters — a lifetime parameter is bound via `Life<'a>` inside the `PhantomData` tuple: + +```rust +// #[cgp_new_provider] impl Runner for SpawnAndRun +pub struct SpawnAndRun(pub ::core::marker::PhantomData<(InCode)>); +``` + +The **provider-name rewrite in the generics** keeps the `IsProviderFor` bounds honest: `replace_provider_in_generics` rewrites any `Provider: SomeTrait` bound in the `where` clause into an `IsProviderFor` bound, so a higher-order provider's inner-provider dependency surfaces in error messages as an `IsProviderFor` obligation rather than a raw provider-trait bound. + +## Known issues + +A **const argument in the provider trait's arguments** is rejected with a spanned error rather than supported: `ProviderImplArgs::from_generic_args` returns "const arguments are not supported in provider impl trait arguments" if a `const` appears among the trait's type arguments. A const generic on the *provider struct* is fine — it flows through untouched — so this limits only const parameters that sit in the provider trait's own argument list. + +## Tests + +`#[cgp_provider]` is exercised both by expansion snapshots (see [`#[cgp_component]`](cgp_component.md#snapshots) for the `snapshot_cgp_provider!` index, which lives with the component feature) and by direct behavioral use: + +- [generic_components/component_const.rs](../../../crates/tests/cgp-tests/tests/generic_components/component_const.rs) snapshots a const-generic provider `UseConstant`, with the const on the struct flowing through to the `IsProviderFor` impl unchanged. +- [generic_components/component_generic_const.rs](../../../crates/tests/cgp-tests/tests/generic_components/component_generic_const.rs) snapshots the same const-generic provider carrying an impl-side dependency that ties the const's type to the context's abstract `Unit`. +- [generic_components/component_lifetime.rs](../../../crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs) snapshots a lifetime-carrying `UseField` provider, showing the lifetime lifted into `Life<'a>` in the `Params` tuple. +- [dispatching/compose.rs](../../../crates/tests/cgp-tests/tests/dispatching/compose.rs) and [async_and_send/spawn.rs](../../../crates/tests/cgp-tests/tests/async_and_send/spawn.rs) exercise `#[cgp_provider]` and `#[cgp_new_provider]` directly in real wiring. + +## Source + +The entry points are `cgp_provider` in [cgp-macro-lib/src/cgp_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_provider.rs) and `cgp_new_provider` in [cgp-macro-lib/src/cgp_new_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_new_provider.rs). The shared lowering and its AST types live in [cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/) and are documented in [asts/cgp_provider.md](../asts/cgp_provider.md); the `IsProviderFor` derivation itself is in [cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs), and the provider-name-to-`IsProviderFor` rewrite in the [`replace_provider` visitor](../../../crates/macros/cgp-macro-core/src/visitors/replace_provider.rs). This macro is the handoff target of [`#[cgp_impl]`](cgp_impl.md). diff --git a/docs/implementation/entrypoints/cgp_type.md b/docs/implementation/entrypoints/cgp_type.md new file mode 100644 index 00000000..d922de40 --- /dev/null +++ b/docs/implementation/entrypoints/cgp_type.md @@ -0,0 +1,85 @@ +# `#[cgp_type]` — implementation + +`#[cgp_type]` builds an abstract-type component by running the `#[cgp_component]` pipeline over a trait carrying one associated type, then appending the two provider impls (`UseType` and `WithProvider`) that let a context choose the concrete type through wiring. This document covers how that works internally; for the accepted syntax and the full expansion, read the reference document [reference/macros/cgp_type.md](../../reference/macros/cgp_type.md). + +## Entry point + +The macro is driven by the `cgp_type` function in [cgp-macro-lib/src/cgp_type.rs](../../../crates/macros/cgp-macro-lib/src/cgp_type.rs). It follows the canonical entry-point shape but with one preparatory step unique to this macro: after parsing the attribute into `CgpComponentRawArgs` and the item into a `syn::ItemTrait`, it extracts the trait's single associated type and, when the user gave no provider name, defaults `provider_ident` to `{Type}TypeProvider` — keyed off the *associated type's* identifier, not the trait's. It then feeds the args and trait into the shared `#[cgp_component]` pipeline and wraps the result in an `ItemCgpType` for the extra codegen. + +```rust +if raw_args.provider_ident.is_none() { + raw_args.provider_ident = Some(Ident::new( + &format!("{}TypeProvider", item_type.ident), + item_type.ident.span(), + )); +} + +let evaluated = item_cgp_component.preprocess()?.eval()?; +let item_cgp_type = ItemCgpType { item_component: evaluated }; +let items = item_cgp_type.to_items()?; +``` + +Three failures surface here: a malformed attribute is rejected while parsing `CgpComponentRawArgs`; a non-trait item fails at `syn::parse2::`; and a trait whose body is not exactly one plain (non-generic, `where`-free) associated type is rejected by `extract_item_type_from_trait`. + +## Pipeline + +`#[cgp_type]` reuses the `#[cgp_component]` pipeline for the component itself and adds a final rendering step of its own. The two shared stages, `preprocess` and `eval`, are exactly the ones documented for the [`cgp_component` entrypoint](cgp_component.md) and are owned by the [`cgp_component` AST stack](../asts/cgp_component.md); this macro does not re-implement them. + +- **preprocess → eval** run the standard `#[cgp_component]` derivation over the associated-type trait, producing an `EvaluatedCgpComponent` — the consumer trait, provider trait, both blanket impls, and the component marker. +- **to_items** is where `#[cgp_type]` diverges: `ItemCgpType::to_items` first calls the evaluated component's own `to_items` (emitting the five core items plus the `UseContext` and `RedirectLookup` provider impls), then appends the `UseType` and `WithProvider` provider impls. The [`cgp_type` AST stack](../asts/cgp_type.md) documents `ItemCgpType`. + +## Generated items + +The macro emits the entire `#[cgp_component]` output for the trait — described in the [`cgp_component` entrypoint document](cgp_component.md), except that every blanket impl forwards an *associated type* rather than a method body — followed by two abstract-type provider impls. Each of the two extra impls is paired with a matching `IsProviderFor` impl carrying the same bounds, produced through the shared [`ItemProviderImpl`/`ItemProviderImpls`](../asts/cgp_type.md) machinery. + +The first extra impl is the `UseType` blanket impl, the heart of the macro. It implements the provider trait for `UseType` by setting the abstract associated type to the free generic parameter, so wiring a component to `UseType` supplies `f64` as the type with no bespoke provider: + +```rust +impl ScalarTypeProvider<__Context__> for UseType { + type Scalar = Scalar; +} +``` + +The second is a `WithProvider` bridge that adapts the built-in `TypeProvider` machinery into this component, so a `#[cgp_type]` component can be backed by any generic `TypeProvider`: + +```rust +impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> + for WithProvider<__Provider__> +where + __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, +{ + type Scalar = Scalar; +} +``` + +## Behavior and corner cases + +A **bound on the associated type** is threaded not only into the provider trait (that comes for free from the shared component pipeline) but also onto both extra impls. `to_item_provider_impls` reads the bound with [`get_bounds_and_replace_self_assoc_type`](../../../crates/macros/cgp-macro-core/src/visitors/self_assoc_type.rs), which rewrites any `Self::Scalar` inside the bound to the free `Scalar` parameter, then adds it as a `where Scalar: ` predicate on both the `UseType` and `WithProvider` impls. A self-referential bound such as `type Scalar: Mul + Clone` therefore emits `where Scalar: Mul + Clone`. + +**Generic parameters** on the trait are handled entirely by the shared component pipeline and then reused: `to_item_provider_impls` clones the provider trait's generics and inserts the associated-type name (and, for `WithProvider`, `__Provider__`) as leading impl parameters, so a `?Sized` or otherwise-bounded parameter carries through onto the extra impls unchanged. + +The **provider-name default** is the one behavior `#[cgp_type]` adds ahead of the pipeline: an omitted provider name becomes `{Type}TypeProvider` (from the associated type), where a bare `#[cgp_component]` would instead reject a missing name. A supplied name — `#[cgp_type(ProvideFooType)]` — overrides this exactly as it does for `#[cgp_component]`. + +## Snapshots + +Every `snapshot_cgp_type!` invocation across the suite is indexed here; the canonical variants live in the `abstract_types` target, with one `UseDelegate`-focused variant owned by the dispatch target: + +- [abstract_types/cgp_type_macro.rs](../../../crates/tests/cgp-tests/tests/abstract_types/cgp_type_macro.rs) — the canonical plain expansion (one associated type, default `ScalarTypeProvider` name), showing the full component output plus the `UseType` and `WithProvider` impls. +- [abstract_types/cgp_type_bounded.rs](../../../crates/tests/cgp-tests/tests/abstract_types/cgp_type_bounded.rs) — the associated type bounded by another abstract-type component (`type Types: HasScalarType`), with the bound propagating onto the `UseType` and `WithProvider` impls. +- [abstract_types/cgp_type_self_referential.rs](../../../crates/tests/cgp-tests/tests/abstract_types/cgp_type_self_referential.rs) — a self-referential bound (`type Scalar: Mul + Clone`), where `Self::Scalar` is rewritten to the free parameter in the extra impls' `where` clause. +- [abstract_types/cgp_type_unsized.rs](../../../crates/tests/cgp-tests/tests/abstract_types/cgp_type_unsized.rs) — a `#[cgp_type(ProvideFooType)]` overriding the default name together with a `?Sized` generic parameter threaded through every generated item. +- [dispatching/use_delegate_getter.rs](../../../crates/tests/cgp-tests/tests/dispatching/use_delegate_getter.rs) — a multi-parameter `#[cgp_type]` with `#[derive_delegate]` attributes, pinning the `UseDelegate` dispatch-provider impls; owned by the dispatch concept rather than repeated in the abstract-types target. + +No snapshot yet captures the keyed argument form (`#[cgp_type { provider: …, context: … }]`) distinct from the bare-name override. + +## Tests + +The behavioral tests confirm the generated wiring and the `UseType` route work: + +- [abstract_types/cgp_type_bounded.rs](../../../crates/tests/cgp-tests/tests/abstract_types/cgp_type_bounded.rs) wires a context whose abstract type is itself an abstract-type component and checks the bound is enforced. +- [abstract_types/cgp_type_self_referential.rs](../../../crates/tests/cgp-tests/tests/abstract_types/cgp_type_self_referential.rs) wires a self-referentially bounded type through `delegate_components!` and passes its check. +- [abstract_types/cgp_type_unsized.rs](../../../crates/tests/cgp-tests/tests/abstract_types/cgp_type_unsized.rs) exercises a `?Sized` abstract type together with a dependent getter. + +## Source + +The entry point is `cgp_type` in [cgp-macro-lib/src/cgp_type.rs](../../../crates/macros/cgp-macro-lib/src/cgp_type.rs). The extra codegen lives in [cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs) and is documented in [asts/cgp_type.md](../asts/cgp_type.md); the shared component pipeline it wraps is in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/), documented in [entrypoints/cgp_component.md](cgp_component.md). The associated-type-bound rewriting comes from [`get_bounds_and_replace_self_assoc_type`](../../../crates/macros/cgp-macro-core/src/visitors/self_assoc_type.rs), and the paired provider/`IsProviderFor` impls from `ItemProviderImpl` in [cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs). All generated fragments are built with [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/entrypoints/check_components.md b/docs/implementation/entrypoints/check_components.md new file mode 100644 index 00000000..aeef8715 --- /dev/null +++ b/docs/implementation/entrypoints/check_components.md @@ -0,0 +1,63 @@ +# `check_components!` — implementation + +`check_components!` turns each entry of a check table into a compile-time assertion that a context can use a component, by generating a check trait whose supertrait is the assertion and one empty impl per checked entry. This document covers how that works internally; for the accepted syntax and the complete expansion a user sees, read the reference document [reference/macros/check_components.md](../../reference/macros/check_components.md). + +## Entry point + +The macro is driven by the thin `check_components` function in [cgp-macro-lib/src/check_components.rs](../../../crates/macros/cgp-macro-lib/src/check_components.rs). It parses the body into a [`CheckComponentsTables`](../asts/check_components.md) — one `CheckComponentsTable` per context block — renders each to items, and emits them: + +```rust +let tables: CheckComponentsTables = parse2(body)?; +let items = tables.to_items()?; +Ok(quote! { #( #items )* }) +``` + +All real logic lives in `cgp-macro-core`. A malformed table fails while parsing, and an unknown table-level attribute (anything other than `#[check_trait]` or `#[check_providers]`) fails with a spanned error during parsing. + +## Pipeline + +The macro parses into the [`check_components` AST stack](../asts/check_components.md) and then calls `to_items` on each table, which internally runs a single `eval` per table. Parsing splits each table into its attributes, an optional leading generic list, the context type, an optional `where` clause, and the brace-delimited check entries. `eval` builds the check trait once and then, for each evaluated entry, emits one impl of that trait; there is no multi-stage lowering beyond this. + +## Generated items + +Each table emits one check trait followed by one empty impl per checked entry. The trait is an alias whose sole supertrait is the assertion being made, and each impl compiles only if that supertrait holds for the entry. A bare component with no parameters lowers to a unit `__Params__`: + +```rust +// check_components! { Person { GreeterComponent } } +trait __CheckPerson<__Component__, __Params__: ?Sized>: + CanUseComponent<__Component__, __Params__> +{} +impl __CheckPerson for Person {} +``` + +The impl holds only if `Person: CanUseComponent`, which routes through `IsProviderFor` so an unsatisfied transitive bound (a missing `HasField`, say) is what the compiler reports. The generic parameters are literally `__Component__` and `__Params__` in the output, and the check trait name defaults to `__Check{Context}`, derived from the context type's leading identifier. + +A component with parameters places them in the `__Params__` slot — a single parameter directly, multiple as a tuple. The `#[check_providers(...)]` form changes both the supertrait and the implementing type: the trait supertraits `IsProviderFor<__Component__, Context, __Params__>` instead of `CanUseComponent`, and one impl is written for each listed provider rather than for the context, so each provider is asserted independently. + +## Behavior and corner cases + +**Array syntax expands to the cartesian product.** A bracketed key, a bracketed value, or both, expand to one entry per combination before any impl is emitted, so `[A, B]: [P, Q]` yields four impls. The key and value sides are parsed independently (`CheckKey`, `CheckValue`), and each evaluated entry pairs one key with one value. + +**Table-level generics and `where` clauses are merged onto every impl.** A `<'a, I> Context where I: Clone { … }` table threads both onto each generated impl, and a check parameter may itself be generic (`Component: &'a I` or a value carrying its own `` list), whose generics merge with the table's. + +**The error span is moved onto the component.** For the context-checking form the macro overrides the span of the context type in each impl with the span of the checked component (or parameter), so an unsatisfied-constraint error is highlighted on the component the user wrote rather than on the context. The `#[check_providers(...)]` form skips this, since it implements for the providers instead. + +**A component with no value** emits a single unit-params entry; a bracketed value that is empty is treated the same way. + +## Snapshots + +Every `snapshot_check_components!` invocation across the suite is indexed here, since these snapshots belong to this entrypoint: + +- [checking/check_trait.rs](../../../crates/tests/cgp-tests/tests/checking/check_trait.rs) — the standalone check form: multiple check blocks in one invocation, each renamed with `#[check_trait(...)]`, per-entry parameter lists for generic-parameter components, and an array key checked against a parameter list. +- [checking/check_generic.rs](../../../crates/tests/cgp-tests/tests/checking/check_generic.rs) — a generic context (`<'a, I>` plus `where I: Clone`) whose generics and clause are carried onto each impl, a check parameter that uses a generic (`Component: &'a I`), and a component that is itself generic (`BarGetterAtComponent`). +- [checking/check_providers.rs](../../../crates/tests/cgp-tests/tests/checking/check_providers.rs) — the `#[check_providers(...)]` form: the trait supertraits `IsProviderFor` and is implemented for each listed provider rather than for the context. + +No snapshot pins the plainest single-block, single-bare-component case on its own; it is covered implicitly by the richer `check_trait` block above. + +## Tests + +The behavioral coverage for `check_components!` is the compile-time assertion itself: the files listed under Snapshots are compile-only tests, so a successful build is the passing check. Each pins both the expansion (via the snapshot) and the fact that the asserted wiring resolves. There are no `cgp-macro-tests` failure cases for the check family. + +## Source + +The entry point is `check_components` in [cgp-macro-lib/src/check_components.rs](../../../crates/macros/cgp-macro-lib/src/check_components.rs); the tables, entries, keys, and values live in [cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/) and are documented together with the `delegate_and_check_components!` stack in [asts/check_components.md](../asts/check_components.md). The check trait, the `#[check_trait]`/`#[check_providers]` attributes, the `__Check{Context}` name derivation, the supertrait choice, and the span override are all in `table.rs`; the cartesian-product expansion is in `entry.rs`. All generated fragments are built with [parse_internal!](../macros/parse_internal.md). The `delegate_and_check_components!` macro reuses this stack; see its [entrypoint document](delegate_and_check_components.md). diff --git a/docs/implementation/entrypoints/delegate_and_check_components.md b/docs/implementation/entrypoints/delegate_and_check_components.md new file mode 100644 index 00000000..1f596286 --- /dev/null +++ b/docs/implementation/entrypoints/delegate_and_check_components.md @@ -0,0 +1,77 @@ +# `delegate_and_check_components!` — implementation + +`delegate_and_check_components!` wires a context and asserts the wiring in one step, by parsing the shared `DelegateTable`, evaluating its delegation half, and deriving a `CheckComponentsTable` from the delegation keys. This document covers how that fusion works internally; for the accepted syntax and the complete expansion a user sees, read the reference document [reference/macros/delegate_and_check_components.md](../../reference/macros/delegate_and_check_components.md). + +## Entry point + +The macro is driven by the thin `delegate_and_check_components` function in [cgp-macro-lib/src/delegate_and_check_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs). It parses the body into an [`ItemDelegateAndCheckComponents`](../asts/check_components.md) (a wrapper around a `DelegateTable`), derives the check table from it, evaluates the delegation half through the shared `DelegateTable`, and emits both halves: + +```rust +let item: ItemDelegateAndCheckComponents = parse2(body)?; +let check_table = item.to_check_components()?; +let evaluated_table = item.table.eval()?; +let check_items = check_table.to_items()?; +Ok(quote! { #evaluated_table #( #check_items )* }) +``` + +All real logic lives in `cgp-macro-core`. The macro shares both stacks it fuses: the [`delegate_component` stack](../asts/delegate_component.md) for the wiring half and the [`check_components` stack](../asts/check_components.md) for the checking half. + +## Pipeline + +The macro reuses two existing pipelines rather than defining its own. The delegation half is exactly `DelegateTable::eval`, unchanged from [`delegate_components!`](delegate_components.md), so the wiring impls are identical to what that macro emits. The checking half is derived: `to_check_components` reads the delegation keys, converts each into a check entry, and packages them into a `CheckComponentsTable` whose `to_items` is exactly the [`check_components!`](check_components.md) pipeline. The only new work is the key-to-check-entry conversion and the per-entry `#[check_params]`/`#[skip_check]` handling. + +## Generated items + +The macro emits the delegation impls first — a `DelegateComponent` impl and an `IsProviderFor` forwarding impl per entry, exactly as `delegate_components!` produces — then the check trait and one impl per non-skipped entry, exactly as `check_components!` produces. The derived check trait defaults to `__CanUse{Context}` (not `__Check{Context}`), so a `delegate_and_check_components!` and a `check_components!` block can coexist once each in the same module: + +```rust +// delegate_and_check_components! { MyContext { NameGetterComponent: UseField } } +impl DelegateComponent for MyContext { + type Delegate = UseField; +} +impl<__Context__, __Params__> + IsProviderFor for MyContext +where + UseField: IsProviderFor, +{} +// … then the checking half: +trait __CanUseMyContext<__Component__, __Params__: ?Sized>: + CanUseComponent<__Component__, __Params__> +{} +impl __CanUseMyContext for MyContext {} +``` + +A table-level `#[check_trait(Name)]` overrides the derived name. A generic table threads its generics through both halves, since both reuse the same `impl_generics` from the parsed `DelegateTable`. + +## Behavior and corner cases + +**Every delegated key is checked by default.** The conversion walks the delegation entries and produces one bare check entry per key, so wiring an entry with no attribute both delegates and checks it. + +**`#[check_params(...)]` supplies the parameters the check needs.** A component with generic parameters has a parameter-generic `DelegateComponent` impl but a check that needs concrete parameters, so `#[check_params(...)]` provides them: each listed parameter becomes its own check impl, while the single delegation impl stays generic. `#[skip_check]` contributes the delegation impls but no check impl. + +**The two attributes are mutually exclusive and merge across bracket levels.** `#[check_params]` and `#[skip_check]` cannot both apply to one key, and at most one of each may appear. For an array key, a block-level attribute on the bracket merges with each inner key's own attribute — two `#[check_params]` sets union, while combining `#[skip_check]` with `#[check_params]` is an error. + +**Statement forms and non-plain keys are not checked.** The `open`/`namespace`/`for` statements and redirect (`=>`) and `@`-path keys still produce delegation impls through `eval`, but the conversion generates no check entries for them; it validates that they carry no attributes rather than silently ignoring one. Path keys on the delegation side are likewise dropped from the check half. This means a per-value `open` dispatch is wired but not checked. + +## Known issues + +A **per-key generic list on a delegation key is not carried into the check half**. A key that introduces its own generic parameters (` FooKey: …`) would produce a check impl referencing those parameters unbound, since the derived check impl sees only the table-level generics. Such generic keys are therefore unsupported in the checking half; the workaround is `#[skip_check]` on that key and a separate `check_components!` block. The correct behavior would be to thread the per-key generics into the derived check entry as `check_components!` already does for its own generic values. + +## Snapshots + +Every `snapshot_delegate_and_check_components!` invocation across the suite is indexed here, since these snapshots belong to this entrypoint: + +- [checking/delegate_and_check_basic.rs](../../../crates/tests/cgp-tests/tests/checking/delegate_and_check_basic.rs) — the basic form: two entries wired and checked, with the check trait renamed via `#[check_trait(...)]`. +- [checking/delegate_and_check_generic.rs](../../../crates/tests/cgp-tests/tests/checking/delegate_and_check_generic.rs) — a generic context (` MyContext`) threaded through both halves, with the check trait defaulting to `__CanUse{Context}`. +- [checking/delegate_and_check_params.rs](../../../crates/tests/cgp-tests/tests/checking/delegate_and_check_params.rs) — `#[check_params(...)]` supplying parameter tuples, an array key wiring several components to one provider, and a block-level `#[check_params(...)]` on the bracket merged with each entry's own. +- [dispatching/use_delegate_getter.rs](../../../crates/tests/cgp-tests/tests/dispatching/use_delegate_getter.rs) — a `UseDelegate`-table value wired and checked in one step, exercising the legacy nested-table form through this macro. + +One variant has no snapshot: a `#[skip_check]` entry alongside checked entries, which the reference shows but no snapshot pins. + +## Tests + +The snapshot files above are compile-only tests, so a successful build is the passing assertion for both the wiring and the derived check. There are no separate behavioral or `cgp-macro-tests` failure cases for this macro. + +## Source + +The entry point is `delegate_and_check_components` in [cgp-macro-lib/src/delegate_and_check_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs); the wrapper item, key-to-check conversion, and attribute types live in [cgp-macro-core/src/types/delegate_and_check_components/](../../../crates/macros/cgp-macro-core/src/types/delegate_and_check_components/) and are documented with the `check_components!` stack in [asts/check_components.md](../asts/check_components.md). The `__CanUse{Context}` default name and `#[check_trait]` handling are in `item.rs`, the `#[check_params]`/`#[skip_check]` parsing and mutual exclusion in `check_params.rs`, the per-key conversion in `key_with_check_params.rs`, and the walk over delegation entries in `to_keys_with_check_params.rs`. It reuses the [`DelegateTable`](../asts/delegate_component.md) for the wiring half and the [`CheckComponentsTable`](../asts/check_components.md) for the checking half. diff --git a/docs/implementation/entrypoints/delegate_components.md b/docs/implementation/entrypoints/delegate_components.md new file mode 100644 index 00000000..44061233 --- /dev/null +++ b/docs/implementation/entrypoints/delegate_components.md @@ -0,0 +1,101 @@ +# `delegate_components!` — implementation + +`delegate_components!` builds a context's type-level wiring table by parsing a `DelegateTable` from the macro body and lowering each mapping into a `DelegateComponent` impl plus a forwarding `IsProviderFor` impl. This document covers how that lowering works internally; for the accepted syntax and the complete expansion a user sees, read the reference document [reference/macros/delegate_components.md](../../reference/macros/delegate_components.md). + +## Entry point + +The macro is driven by the thin `delegate_components` function in [cgp-macro-lib/src/delegate_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_components.rs). It parses the whole body into a single [`DelegateTable`](../asts/delegate_component.md), rejects any attributes the parser accepted (the table supports none), evaluates the table, and emits the resulting tokens: + +```rust +let table: DelegateTable = parse2(body.clone())?; +table.validate_attributes()?; +let evaluated_table = table.eval()?; +Ok(evaluated_table.to_token_stream()) +``` + +All real logic lives in `cgp-macro-core`. A malformed body fails while parsing `DelegateTable`, and an attribute on the table or any key fails in `validate_attributes` with a spanned "unsupported attribute" error rather than being silently dropped. + +## Pipeline + +The macro has two stages after parsing: attribute rejection and a single `eval`. Parsing produces the whole [`delegate_component` AST stack](../asts/delegate_component.md) — the table, its `new` keyword and optional generic list, the entries (statements plus mappings), and the keys and values inside each mapping. `eval` walks that tree once, lowering every mapping and statement into a flat list of evaluated entries and rendering each into its impl pair. The `open`/`namespace`/`for` statements and the nested-`UseDelegate` values are handled inside `eval` as part of the same walk; there is no separate preprocessing stage. + +## Generated items + +For every table entry the macro emits two impls in order: a `DelegateComponent` impl that records the mapping (the component key, the chosen provider as the `Delegate` type) and an `IsProviderFor` impl that forwards the provider's dependencies back through the table so a missing transitive requirement stays diagnosable. A plain `Key: Provider` mapping lowers directly: + +```rust +// delegate_components! { Rectangle { AreaCalculatorComponent: RectangleArea } } +impl DelegateComponent for Rectangle { + type Delegate = RectangleArea; +} +impl<__Context__, __Params__> + IsProviderFor for Rectangle +where + RectangleArea: IsProviderFor, +{} +``` + +Both `__Context__` and `__Params__` are the reserved identifiers that appear literally in the output. When the body carries a leading `new` keyword, the macro additionally emits the target struct (`struct Rectangle;`, or a generic struct if the target carries parameters), and a nested-`UseDelegate` value lifts its inner table out into its own struct and impls, so a value like `UseDelegate` contributes both the outer entry and a full inner table. + +The `open` header and `@Component.Key` entries lower through the [`RedirectLookup`](cgp_component.md) impl that every `#[cgp_component]` already generates. The header wires each opened component to a redirect rooted at the component name in the context's own table, and each `@`-path entry stores its provider under the extended path key: + +```rust +// open { AreaCalculatorComponent }; → the redirect entry +impl DelegateComponent for MyApp { + type Delegate = RedirectLookup>; +} +// @AreaCalculatorComponent.Rectangle: RectangleArea → a keyed entry on the same table, +// keyed by the redirect path with a trailing wildcard, mapping to RectangleArea +``` + +The per-value entries are ordinary `DelegateComponent`/`IsProviderFor` pairs whose key is the redirect path type; `RedirectLookup` appends the dispatch parameter onto the path at lookup time and reads the result back. + +## Behavior and corner cases + +A **mapping operator** selects which value lowering applies. `:` (Normal) maps the key straight to the named provider; `->` (Direct) sets the `Delegate` to `>::Delegate` and adds a `Value: DelegateComponent` bound, so the entry forwards to the value's own entry for that key; `=>` (Redirect) sets the `Delegate` to `RedirectLookup` along an `@`-path value. The [`delegate_component` AST document](../asts/delegate_component.md) describes each in full. + +An **array key** `[A, B]: Provider` expands to one impl pair per bracketed key, all pointing at the same value, because the key evaluates to a vector of evaluated keys that the mapping iterates. A **per-key or per-table generic list** is merged onto every generated impl: a table-level `<'a, T>` is threaded through each impl's generics, and a key may introduce its own extra generics (` BazKey`) that merge with the table's. + +An **`@`-path key** carries a leading `__Wildcard__` generic and lowers the path to a prefix type ending in that wildcard, which is how a dispatch parameter slots in at lookup time. A **brace group on a path segment** (`@Component.{u32, u64}: P`) expands to one key per element, and the `namespace`/`for` statement forms lower through a shared "for-entry" path that builds a `Namespace<…, Delegate = …>` bound rather than a direct `DelegateComponent` impl; these are the namespace machinery and are detailed in the AST document. + +## Known issues + +The macro's parser is permissive about the body shape and surfaces most mistakes as generic `syn` parse errors rather than tailored diagnostics — for example, an `open` header written after a plain mapping fails to parse because statements must lead the block, but the error points at the unexpected token rather than explaining the ordering rule. There is no failure-case coverage for the delegate family in `cgp-macro-tests`. + +## Snapshots + +Every `snapshot_delegate_components!` invocation across the suite is indexed here, since these snapshots all belong to this entrypoint. The basic-delegation snapshots pin the plain-table forms: + +- [basic_delegation/delegate_components_macro.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/delegate_components_macro.rs) — the canonical `new`-table expansion (two entries) plus the `->` forwarding form that delegates to another table's entry. +- [basic_delegation/delegate_array_key.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/delegate_array_key.rs) — an array key expanding to one impl pair per bracketed key. +- [basic_delegation/delegate_generic_table.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/delegate_generic_table.rs) — a leading `<'a, T1: Clone>` generic list threaded onto every impl, with a key introducing its own extra generic (` BazKey`). + +The namespace snapshots pin the statement and `@`-path forms: + +- [namespaces/open_dispatch.rs](../../../crates/tests/cgp-tests/tests/namespaces/open_dispatch.rs) — the `open { … }` header plus `@Component.Key` per-value entries, including a brace group sharing one provider across several keys. +- [namespaces/multi_param_open.rs](../../../crates/tests/cgp-tests/tests/namespaces/multi_param_open.rs) — an `open` dispatch on a multi-segment `@Component.A.B` path, one segment carrying an entry generic. +- [namespaces/namespace_basic.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_basic.rs), [namespaces/namespace_symbol_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_symbol_path.rs), [namespaces/namespace_type_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_type_path.rs) — the `namespace …;` header forwarding every lookup through a namespace trait, with bare, symbol-path, and type-path `@`-keys. +- [namespaces/namespace_multi.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_multi.rs), [namespaces/namespace_group.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_group.rs) — brace-group and array-group `@`-keys expanding to the cartesian product of segments. +- [namespaces/multi_param_namespace.rs](../../../crates/tests/cgp-tests/tests/namespaces/multi_param_namespace.rs) — multi-segment namespace paths with a per-segment generic. +- [namespaces/extended_namespace_wiring.rs](../../../crates/tests/cgp-tests/tests/namespaces/extended_namespace_wiring.rs) — a namespace table mixing plain and nested-group `@`-paths across several crates' components. +- [namespaces/prefix_default_namespace.rs](../../../crates/tests/cgp-tests/tests/namespaces/prefix_default_namespace.rs) — a `DefaultNamespace` header with fully-qualified `@cgp.core.error.…` paths. +- [namespaces/default_impls_wiring.rs](../../../crates/tests/cgp-tests/tests/namespaces/default_impls_wiring.rs) — the `for in SomeTable { … }` loop form pulling entries from another lookup table. +- [namespaces/redirect_lookup.rs](../../../crates/tests/cgp-tests/tests/namespaces/redirect_lookup.rs) — a `namespace` header producing the `RedirectLookup`-style blanket `DelegateComponent` impl. +- [dispatching/use_delegate_getter.rs](../../../crates/tests/cgp-tests/tests/dispatching/use_delegate_getter.rs) — the legacy `UseDelegate` nested-table value, including a custom `UseDelegate2` wrapper over tuple keys. + +One variant has no snapshot: a bare (non-`new`) single-entry table with a plain type target, distinct from the standalone `new` bundle that owns the canonical snapshot. + +## Tests + +The behavioral tests confirm the generated wiring resolves and compiles: + +- [basic_delegation/delegate_new_struct.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/delegate_new_struct.rs) checks that `new` declares the table struct and the table resolves as written. +- [basic_delegation/delegate_new_array_key.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/delegate_new_array_key.rs) checks the array-key and nested-`new` forms parse and expand together. +- [basic_delegation/delegate_new_generic_struct.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/delegate_new_generic_struct.rs) checks that ` new MyComponents` declares a generic table struct. +- [basic_delegation/delegate_nested_use_delegate.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/delegate_nested_use_delegate.rs) checks a two-level nested `UseDelegate` value builds an inline dispatch table. +- [basic_delegation/delegate_generic_nested_value.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/delegate_generic_nested_value.rs) checks a per-entry `` list threads through both the outer key and the inner generated table struct. +- [basic_delegation/consumer_delegate_getter.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/consumer_delegate_getter.rs) and [basic_delegation/consumer_delegate_generic.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/consumer_delegate_generic.rs) check that a context may satisfy some components by wiring and others by a direct trait impl, and that a generic component resolves independently per type argument. + +## Source + +The entry point is `delegate_components` in [cgp-macro-lib/src/delegate_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_components.rs); the table, its entries, keys, values, and statements live in [cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/) and are documented in [asts/delegate_component.md](../asts/delegate_component.md). Attribute rejection is in `validate_attributes.rs`, the impl pair is built in `mapping/eval.rs`, and all generated fragments are built with [parse_internal!](../macros/parse_internal.md). The `open` and `@`-path forms build on the [`RedirectLookup`](cgp_component.md) impl that `#[cgp_component]` generates. diff --git a/docs/implementation/entrypoints/derive_build_field.md b/docs/implementation/entrypoints/derive_build_field.md new file mode 100644 index 00000000..33c07dad --- /dev/null +++ b/docs/implementation/entrypoints/derive_build_field.md @@ -0,0 +1,54 @@ +# `#[derive(BuildField)]` — implementation + +`#[derive(BuildField)]` emits just the incremental-builder slice of the record machinery: a `__Partial{Name}` companion struct plus the `HasBuilder`, `IntoBuilder`, `PartialData`, `FinalizeBuild`, per-field `UpdateField`, and per-field `HasField` impls that assemble a struct one field at a time. This document covers how that codegen works; for the accepted syntax and the full expansion, read the reference document [reference/derives/derive_build_field.md](../../reference/derives/derive_build_field.md). + +## Entry point + +The macro is driven by the `derive_build_field` function in [cgp-macro-lib/src/derive_build_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_build_field.rs). It parses the input into a `syn::ItemStruct`, wraps it in an `ItemCgpRecord`, and calls `to_build_field_items` — the same method the record path of `#[derive(CgpData)]` uses for its builder slice: + +```rust +let record = ItemCgpRecord { item_struct }; +let items = record.to_build_field_items()?; +``` + +Applying the derive to a non-struct item fails at `syn::parse2`. + +## Pipeline + +There is no multi-stage transform. `ItemCgpRecord::to_build_field_items` names the companion struct `__Partial{ContextName}` and composes the helpers in the [`derive_builder/`](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/) submodule in a fixed order: `derive_builder_struct`, `derive_has_builder_impl`, `derive_into_builder_impl`, `derive_partial_data_impl_from_struct`, `derive_finalize_build_impl`, `derive_update_field_impls`, and `derive_has_field_impls`. The [`cgp_data` AST stack](../asts/cgp_data.md) documents `ItemCgpRecord` and the field-tag types. + +## Generated items + +The derive centers on the partial companion struct `__Partial{Name}`: a clone of the input struct that gains one `MapType` type parameter per field and wraps each field type in that parameter's `Map`. The marker decides how a field is stored — `IsPresent` maps `T` to `T`, `IsNothing` maps it to the unit `()`, and `IsVoid` maps it to the empty `Void` — so a field's present/absent state is encoded in the type: + +```rust +pub struct __PartialPerson<__F0__: MapType, __F1__: MapType> { + pub first_name: <__F0__ as MapType>::Map, + pub last_name: <__F1__ as MapType>::Map, +} +``` + +Around that struct the derive emits the entry and exit points. `HasBuilder` starts an empty builder at `__PartialPerson`; `IntoBuilder` turns an existing value into a fully-present builder at ``; `PartialData` records that any configuration targets the original struct; and `FinalizeBuild` reconstructs the struct but is implemented only for the all-`IsPresent` configuration — so an incomplete build cannot be finalized. It then emits, per field, an `UpdateField` impl that flips one field's marker to `M` and returns the old value alongside the rebuilt partial struct, and a `HasField` impl on the partial type that is in scope only when that field's marker is `IsPresent`: + +```rust +impl<__F1__: MapType> HasField for __PartialPerson { + type Value = String; + fn get_field(&self, _: PhantomData) -> &String { &self.first_name } +} +``` + +The `BuildField` trait itself is *not* emitted. It is a blanket impl in the field crate over any `UpdateField`, so `build_field` is sugar over the generated `update_field` that transitions a field from absent to present; `FinalizeBuild` is likewise a field-crate subtrait of `PartialData`, and the derive supplies only the all-present impl. + +## Behavior and corner cases + +A named field is keyed by [`Symbol!`](../../reference/macros/symbol.md) and a tuple field by [`Index`](../../reference/types/index.md), following the whole family's tagging rule, so a tuple struct produces `UpdateField, _>` impls. The struct's generic parameters and `where` clause are preserved and carried onto the companion struct and every impl, with the field markers added on top and `PartialData::Target` naming the original struct with its own generics. + +An **empty struct** produces a `__Partial{Name}` with no field markers, a trivial `HasBuilder`/`FinalizeBuild`, and no `UpdateField`/`HasField` impls. This derive emits no `HasField`/`HasFieldMut` getters on the original struct and no `HasFields` representation impls — those come from [`#[derive(HasField)]`](derive_has_field.md) and [`#[derive(HasFields)]`](derive_has_fields.md); `BuildField` is purely the construction slice, included wholesale by [`#[derive(CgpRecord)]`](derive_cgp_record.md) and [`#[derive(CgpData)]`](derive_cgp_data.md). + +## Tests + +`#[derive(BuildField)]` has no snapshot macro of its own; the builder items it emits are part of the record expansion pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). The behavioral builder tests in [crates/tests/cgp-tests/tests/extensible_records/](../../../crates/tests/cgp-tests/tests/extensible_records/) exercise the machinery: [record_build_from.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_from.rs) drives `builder`/`build_from`/`build_field`/`finalize_build`, [optional_builder.rs](../../../crates/tests/cgp-tests/tests/extensible_records/optional_builder.rs) the optional-builder path, and [point_cast.rs](../../../crates/tests/cgp-tests/tests/extensible_records/point_cast.rs) the `build_with_default` cast. + +## Source + +The entry point is `derive_build_field` in [cgp-macro-lib/src/derive_build_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_build_field.rs). The codegen is `ItemCgpRecord::to_build_field_items` in [cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), which composes the [derive_builder/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/) helpers (`builder_struct.rs`, `has_builder_impl.rs`, `into_builder_impl.rs`, `partial_data.rs`, `finalize_build_impl.rs`, `update_field_impls.rs`, `has_field_impls.rs`); the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The `BuildField`, `FinalizeBuild`, `UpdateField`, `HasBuilder`, `IntoBuilder`, and `PartialData` traits and the `MapType` markers live under [crates/core/cgp-field/src/](../../../crates/core/cgp-field/src/). diff --git a/docs/implementation/entrypoints/derive_cgp_data.md b/docs/implementation/entrypoints/derive_cgp_data.md new file mode 100644 index 00000000..0e7ddf28 --- /dev/null +++ b/docs/implementation/entrypoints/derive_cgp_data.md @@ -0,0 +1,57 @@ +# `#[derive(CgpData)]` — implementation + +`#[derive(CgpData)]` is the umbrella extensible-data derive: applied to a struct it emits the full record machinery, applied to an enum the full variant machinery, dispatching on shape and reusing the same codegen as the shape-specific `#[derive(CgpRecord)]` and `#[derive(CgpVariant)]`. This document covers how that composition works; for the accepted syntax and the full expansion, read the reference document [reference/derives/derive_cgp_data.md](../../reference/derives/derive_cgp_data.md). + +## Entry point + +The macro is driven by the `derive_cgp_data` function in [cgp-macro-lib/src/cgp_data.rs](../../../crates/macros/cgp-macro-lib/src/cgp_data.rs). It parses the input into an `ItemCgpData` and calls `to_items`: + +```rust +let data: ItemCgpData = parse2(body)?; +let items = data.to_items()?; +``` + +`ItemCgpData` is an enum of `Record(ItemCgpRecord)` or `Variant(ItemCgpVariant)`; its `Parse` impl routes a `struct` to the record arm and an `enum` to the variant arm, rejecting anything else with "expect body to be either a struct or enum". Its `to_items` forwards to the wrapped type's `to_items`, so `CgpData` on a struct emits exactly what `#[derive(CgpRecord)]` emits and `CgpData` on an enum exactly what `#[derive(CgpVariant)]` emits — the two shape-specific derives are `CgpData` restricted to one shape. See the [`cgp_data` AST stack](../asts/cgp_data.md) for those types. + +## Pipeline + +There is no multi-stage transform; the composition happens inside the two `to_items` methods. + +- **`ItemCgpRecord::to_items`** (the struct path) concatenates three slices in order: the per-field `HasField`/`HasFieldMut` getters (the [`#[derive(HasField)]`](derive_has_field.md) output), the five representation impls (the [`#[derive(HasFields)]`](derive_has_fields.md) output), and the incremental builder items (the [`#[derive(BuildField)]`](derive_build_field.md) output). +- **`ItemCgpVariant::to_items`** (the enum path) concatenates three slices in order: the five representation impls over a sum (the enum path of [`#[derive(HasFields)]`](derive_has_fields.md)), the per-variant `FromVariant` constructors (the [`#[derive(FromVariant)]`](derive_from_variant.md) output), and the incremental extractor items (the [`#[derive(ExtractField)]`](derive_extract_field.md) output). + +Each slice is documented in the entrypoint linked beside it; because `CgpData` reuses those exact methods, this document does not repeat the item shapes and points to them instead. + +## Generated items + +For a struct, the fixed emission order is: the `HasField`/`HasFieldMut` getters per field, then `HasFields`, `HasFieldsRef`, `FromFields`, `ToFields`, `ToFieldsRef`, then the builder block — the `__Partial{Name}` struct, `HasBuilder`, `IntoBuilder`, `PartialData`, `FinalizeBuild`, then the per-field `UpdateField` and `HasField` impls. For an enum: `HasFields`, `HasFieldsRef`, `FromFields`, `ToFields`, `ToFieldsRef`, then one `FromVariant` per variant, then the extractor block — the `__Partial{Name}` and `__PartialRef{Name}` enums, `PartialData` for each, `HasExtractor`/`HasExtractorRef`/`HasExtractorMut`, `FinalizeExtract` for each, then the per-variant `ExtractField` impls for both. + +The two views this composes are the *representation* view (the `HasFields` product or sum, convertible with `FromFields`/`ToFields`) and the *incremental* view (the `__Partial…` companion type that tracks per-field presence or per-variant possibility in its type parameters). The reserved companion names are `__Partial{Name}` and, for the borrowed extractor, `__PartialRef{Name}`. The full item shapes live in the building-block entrypoint documents linked above. + +## Behavior and corner cases + +Field tagging follows the same rule as the whole family: a named struct field or an enum variant is keyed by [`Symbol!`](../../reference/macros/symbol.md), and a tuple-struct field by [`Index`](../../reference/types/index.md), so a tuple-struct record exposes `Field, _>` entries and `UpdateField, _>` impls rather than symbol tags. The type's generic parameters and `where` clause are threaded onto every generated impl and onto the `__Partial…` companion types. + +The shape-specific corner cases are inherited from the building blocks rather than introduced here: a single-field tuple struct is special-cased in the `HasFields` product (see [`derive_has_fields`](derive_has_fields.md)), and an enum whose variants are not each single-unnamed-field tuple variants fails in the extractor and `FromVariant` codegen (see [`derive_extract_field`](derive_extract_field.md) and [`derive_from_variant`](derive_from_variant.md)). `CgpData` on such an enum therefore fails the same way, because it runs the same helpers. + +## Snapshots + +Every `snapshot_derive_cgp_data!` invocation across the suite is indexed here, since these snapshots all belong to this entrypoint. The record expansion is owned by the `extensible_records` target and the variant expansion by `extensible_variants`: + +- [extensible_records/record_derive.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_derive.rs) — the canonical named-field record expansion (getters, representation, builder). +- [extensible_records/person_record.rs](../../../crates/tests/cgp-tests/tests/extensible_records/person_record.rs) — multi-character field names, pinning the full `Symbol>` spine with its length prefix. +- [extensible_records/tuple_record.rs](../../../crates/tests/cgp-tests/tests/extensible_records/tuple_record.rs) — a tuple struct, the whole record spine keyed by `Index`. +- [extensible_records/generic_record.rs](../../../crates/tests/cgp-tests/tests/extensible_records/generic_record.rs) — a generic record with a `where` clause threaded through every impl. +- [extensible_records/optional_builder.rs](../../../crates/tests/cgp-tests/tests/extensible_records/optional_builder.rs) — the record expansion under the optional-builder runtime path. +- [extensible_records/point_cast.rs](../../../crates/tests/cgp-tests/tests/extensible_records/point_cast.rs) — the record expansion behind a structural record cast with `build_with_default`. +- [extensible_variants/derive_cgp_data.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/derive_cgp_data.rs) — the canonical concrete-enum variant expansion (representation, `FromVariant`, extractor). +- [extensible_variants/derive_cgp_data_generic.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/derive_cgp_data_generic.rs) — a generic enum, generics lifted onto the `__Partial*` extractor enums, with upcast/downcast. +- [extensible_variants/derive_cgp_data_shape.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/derive_cgp_data_shape.rs) — an enum with struct payloads and multi-character variant names. + +## Tests + +The snapshot tests above also carry runtime assertions that exercise the composed machinery: `person_record.rs` builds an `Employee` from a `Person` via the builder, `optional_builder.rs` drives the optional builder (`set`/`finalize_optional`/`finalize_with_default`), `point_cast.rs` casts a smaller record up into a larger one, and the `derive_cgp_data*` variant snapshots run the extractor and the upcast/downcast casts. The neighboring [record_build_from.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_from.rs), [record_build_with_handlers.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_with_handlers.rs), [shape_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch.rs), [shape_dispatch_ref.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch_ref.rs), and [variant_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/variant_dispatch.rs) exercise the builder and dispatch behaviors on `CgpData` types without pinning a snapshot. + +## Source + +The entry point is `derive_cgp_data` in [cgp-macro-lib/src/cgp_data.rs](../../../crates/macros/cgp-macro-lib/src/cgp_data.rs); the shape dispatch is `ItemCgpData` in [cgp-macro-core/src/types/cgp_data/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/item.rs), documented in [asts/cgp_data.md](../asts/cgp_data.md). The record path is `ItemCgpRecord::to_items` in `record.rs` (see [`derive_cgp_record`](derive_cgp_record.md)) and the variant path `ItemCgpVariant::to_items` in `variant.rs` (see [`derive_cgp_variant`](derive_cgp_variant.md)), both under [cgp-macro-core/src/types/cgp_data/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/). The runtime traits live in [crates/core/cgp-field/src/](../../../crates/core/cgp-field/src/). diff --git a/docs/implementation/entrypoints/derive_cgp_record.md b/docs/implementation/entrypoints/derive_cgp_record.md new file mode 100644 index 00000000..0bc3c49b --- /dev/null +++ b/docs/implementation/entrypoints/derive_cgp_record.md @@ -0,0 +1,28 @@ +# `#[derive(CgpRecord)]` — implementation + +`#[derive(CgpRecord)]` is `#[derive(CgpData)]` restricted to structs: it emits the full extensible-record machinery — the per-field getters, the representation impls, and the incremental builder — and refuses non-struct input. This document covers the entry point and its shared codegen; for the accepted syntax and the full expansion, read the reference document [reference/derives/derive_cgp_record.md](../../reference/derives/derive_cgp_record.md). + +## Entry point + +The macro is driven by the `derive_cgp_record` function in [cgp-macro-lib/src/cgp_record.rs](../../../crates/macros/cgp-macro-lib/src/cgp_record.rs). It parses the input into an `ItemCgpRecord` and calls `to_items`: + +```rust +let record: ItemCgpRecord = parse2(body)?; +let items = record.to_items()?; +``` + +`ItemCgpRecord::Parse` parses a `syn::ItemStruct`, so applying the derive to an enum or other item fails at parse time — this is the only behavioral difference from `#[derive(CgpData)]` on a struct, which reaches the same `to_items` through `ItemCgpData`. + +## Pipeline and generated items + +There is no multi-stage transform. `ItemCgpRecord::to_items` concatenates three slices in a fixed order — the per-field `HasField`/`HasFieldMut` getters, the five representation impls (`HasFields`, `HasFieldsRef`, `FromFields`, `ToFields`, `ToFieldsRef`), and the incremental builder items (`__Partial{Name}`, `HasBuilder`, `IntoBuilder`, `PartialData`, `FinalizeBuild`, then per-field `UpdateField` and `HasField`). These are exactly the outputs of [`#[derive(HasField)]`](derive_has_field.md), [`#[derive(HasFields)]`](derive_has_fields.md), and [`#[derive(BuildField)]`](derive_build_field.md) respectively; this document does not repeat their item shapes. + +The record's corner cases — `Symbol!` versus `Index` tagging, the newtype `HasFields` special case, and generic threading — are the same as those building blocks describe, because `CgpRecord` runs the same helpers. The [`cgp_data` AST stack](../asts/cgp_data.md) documents `ItemCgpRecord` and its methods, and [`derive_cgp_data`](derive_cgp_data.md) covers the umbrella derive this is a restriction of. + +## Tests + +`#[derive(CgpRecord)]` has no snapshot macro of its own; its expansion is identical to the record path of `#[derive(CgpData)]` and is pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). The behavioral record tests in [crates/tests/cgp-tests/tests/extensible_records/](../../../crates/tests/cgp-tests/tests/extensible_records/) — notably [record_build_from.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_from.rs) and [record_build_with_handlers.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_with_handlers.rs) — exercise the builder that this derive produces. + +## Source + +The entry point is `derive_cgp_record` in [cgp-macro-lib/src/cgp_record.rs](../../../crates/macros/cgp-macro-lib/src/cgp_record.rs). The codegen is `ItemCgpRecord::to_items` in [cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), which composes `derive_has_field_impls_from_struct`, `derive_has_fields_impls_from_struct`, and the [derive_builder/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/) helpers; the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The runtime traits live in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). diff --git a/docs/implementation/entrypoints/derive_cgp_variant.md b/docs/implementation/entrypoints/derive_cgp_variant.md new file mode 100644 index 00000000..4f98e45a --- /dev/null +++ b/docs/implementation/entrypoints/derive_cgp_variant.md @@ -0,0 +1,28 @@ +# `#[derive(CgpVariant)]` — implementation + +`#[derive(CgpVariant)]` is `#[derive(CgpData)]` restricted to enums: it emits the full extensible-variant machinery — the representation impls, the `FromVariant` constructors, and the incremental extractor — and refuses non-enum input. This document covers the entry point and its shared codegen; for the accepted syntax and the full expansion, read the reference document [reference/derives/derive_cgp_variant.md](../../reference/derives/derive_cgp_variant.md). + +## Entry point + +The macro is driven by the `derive_cgp_variant` function in [cgp-macro-lib/src/cgp_variant.rs](../../../crates/macros/cgp-macro-lib/src/cgp_variant.rs). It parses the input into an `ItemCgpVariant` and calls `to_items`: + +```rust +let variant: ItemCgpVariant = parse2(body)?; +let items = variant.to_items()?; +``` + +`ItemCgpVariant::Parse` parses a `syn::ItemEnum`, so applying the derive to a struct or other item fails at parse time — the only behavioral difference from `#[derive(CgpData)]` on an enum, which reaches the same `to_items` through `ItemCgpData`. + +## Pipeline and generated items + +There is no multi-stage transform. `ItemCgpVariant::to_items` concatenates three slices in a fixed order — the five representation impls over a *sum* (`HasFields`, `HasFieldsRef`, `FromFields`, `ToFields`, `ToFieldsRef`), the per-variant `FromVariant` constructors, and the incremental extractor items (the `__Partial{Name}` and `__PartialRef{Name}` enums, `PartialData` for each, `HasExtractor`/`HasExtractorRef`/`HasExtractorMut`, `FinalizeExtract` for each, then the per-variant `ExtractField` impls). These are exactly the outputs of the enum path of [`#[derive(HasFields)]`](derive_has_fields.md), [`#[derive(FromVariant)]`](derive_from_variant.md), and [`#[derive(ExtractField)]`](derive_extract_field.md) respectively; this document does not repeat their item shapes. + +The variant corner cases are inherited from those building blocks: variant names are keyed by [`Symbol!`](../../reference/macros/symbol.md), generics are threaded onto every impl and onto the partial enums, and every variant must be a single-unnamed-field tuple variant or the extractor and `FromVariant` codegen fail (see [`derive_extract_field`](derive_extract_field.md)). The [`cgp_data` AST stack](../asts/cgp_data.md) documents `ItemCgpVariant` and its methods, and [`derive_cgp_data`](derive_cgp_data.md) covers the umbrella derive this is a restriction of. + +## Tests + +`#[derive(CgpVariant)]` has no snapshot macro of its own; its expansion is identical to the enum path of `#[derive(CgpData)]` and is pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). The behavioral variant tests in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/) — notably [shape_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch.rs), [shape_dispatch_ref.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch_ref.rs), and [variant_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/variant_dispatch.rs) — exercise the extractor and constructors this derive produces. + +## Source + +The entry point is `derive_cgp_variant` in [cgp-macro-lib/src/cgp_variant.rs](../../../crates/macros/cgp-macro-lib/src/cgp_variant.rs). The codegen is `ItemCgpVariant::to_items` in [cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which composes `derive_has_fields_impls_from_enum`, `derive_from_variant_from_enum`, and the [derive_extractor/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/) helpers; the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The runtime traits live in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). diff --git a/docs/implementation/entrypoints/derive_extract_field.md b/docs/implementation/entrypoints/derive_extract_field.md new file mode 100644 index 00000000..bb1cb166 --- /dev/null +++ b/docs/implementation/entrypoints/derive_extract_field.md @@ -0,0 +1,59 @@ +# `#[derive(ExtractField)]` — implementation + +`#[derive(ExtractField)]` emits just the incremental-extractor slice of the variant machinery: the owned and borrowed `__Partial{Name}` companion enums plus the `HasExtractor`/`HasExtractorRef`/`HasExtractorMut`, `PartialData`, `FinalizeExtract`, and per-variant `ExtractField` impls that peel an enum apart one variant at a time. This document covers how that codegen works; for the accepted syntax and the full expansion, read the reference document [reference/derives/derive_extract_field.md](../../reference/derives/derive_extract_field.md). + +## Entry point + +The macro is driven by the `derive_extract_field` function in [cgp-macro-lib/src/derive_extract_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_extract_field.rs). It parses the input into a `syn::ItemEnum`, wraps it in an `ItemCgpVariant`, and calls `to_extract_field_items` — the same method the enum path of `#[derive(CgpData)]` uses for its extractor slice: + +```rust +let variant = ItemCgpVariant { item_enum }; +let items = variant.to_extract_field_items()?; +``` + +Applying the derive to a non-enum item fails at `syn::parse2`. + +## Pipeline + +There is no multi-stage transform. `ItemCgpVariant::to_extract_field_items` names two companion enums — `__Partial{ContextName}` (owned) and `__PartialRef{ContextName}` (borrowed) — and composes the helpers in the [`derive_extractor/`](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/) submodule. Most helpers run twice, once for each companion enum, selected by a `bool` that adds the borrowing `'__a`/`MapTypeRef` generics for the ref form. The [`cgp_data` AST stack](../asts/cgp_data.md) documents `ItemCgpVariant` and the field-tag types. + +## Generated items + +The derive centers on two partial companion enums. `__Partial{Name}` is a clone of the input enum that gains one `MapType` parameter per variant and wraps each payload in that parameter's `Map`; `IsPresent` keeps the payload and `IsVoid` maps it to the empty `Void`, so a variant's remaining-possibility is encoded in the type. `__PartialRef{Name}` adds a `'__a` lifetime and a `MapTypeRef` parameter that selects a shared or mutable borrow of each payload: + +```rust +pub enum __PartialShape<__F0__: MapType, __F1__: MapType> { + Circle(<__F0__ as MapType>::Map), + Rectangle(<__F1__ as MapType>::Map), +} +``` + +Around the enums the derive emits: `PartialData` for each (both target the original enum); `HasExtractor` (owned, all variants `IsPresent`) with `to_extractor`/`from_extractor` that map each concrete variant across, plus `HasExtractorRef` (over `__PartialRef…<'a, IsRef, …>`) and `HasExtractorMut` (over `IsMut`); a `FinalizeExtract` impl for the all-`IsVoid` configuration of each enum, whose body is `match self {}` because that configuration is uninhabited; and, per variant, an `ExtractField` impl in scope only when that variant's marker is `IsPresent`. The extract impl returns `Ok(value)` on a match and `Err(remainder)` on a miss, where the remainder flips that variant's marker to `IsVoid`: + +```rust +impl<__F1__: MapType> ExtractField for __PartialShape { + type Value = Circle; + type Remainder = __PartialShape; + fn extract_field(self, _: PhantomData) -> Result { /* … */ } +} +``` + +Each failed extraction narrows the remainder by one `IsVoid`, so a chain of `extract_field` calls becomes a provably exhaustive match: once every marker is `IsVoid`, the value inhabits `FinalizeExtract` and can be discharged without a wildcard. The `FinalizeExtract` and `FinalizeExtractResult` traits are defined in the field crate; the derive supplies only the all-void impl. + +## Behavior and corner cases + +A variant's name is keyed by the [`Symbol!`](../../reference/macros/symbol.md) of its identifier, and the enum's generic parameters are threaded onto every impl and onto both companion enums, with the ref enum additionally bounding the type parameters by its `'__a` lifetime. The `HasExtractorRef`/`HasExtractorMut` associated types carry the `where Self: 'a` bound that a borrowed extractor needs. + +This derive emits no `HasFields` representation impls and no `FromVariant` constructors — those come from [`#[derive(HasFields)]`](derive_has_fields.md) and [`#[derive(FromVariant)]`](derive_from_variant.md); `ExtractField` is purely the deconstruction slice, included wholesale by [`#[derive(CgpVariant)]`](derive_cgp_variant.md) and [`#[derive(CgpData)]`](derive_cgp_data.md). + +## Known issues + +The extractor codegen requires every variant to be a single-unnamed-field tuple variant (enforced by `get_variant_type` in the `derive_extractor/utils.rs` helper). A fieldless variant like `Empty`, a multi-field variant like `Pair(A, B)`, or a struct-style variant like `Named { x: A }` makes the macro fail with "Expected variant to contain exactly one unnamed field." There is no per-variant opt-out, so an enum mixing variant shapes cannot derive the extractor at all; the same requirement applies to [`#[derive(FromVariant)]`](derive_from_variant.md) and therefore to `#[derive(CgpVariant)]`/`#[derive(CgpData)]` on such an enum. The reference document records the user-visible form of this limitation in its own Known issues. + +## Tests + +`#[derive(ExtractField)]` has no snapshot macro of its own; the extractor items it emits are part of the variant expansion pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). The behavioral extractor tests in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/) exercise the machinery: [shape_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch.rs) drives the owned extractor, [shape_dispatch_ref.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch_ref.rs) the borrowed extractor, and [variant_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/variant_dispatch.rs) the extract-and-dispatch flow. The single-unnamed-field requirement has no dedicated failure case in `cgp-macro-tests` and is a candidate for one. + +## Source + +The entry point is `derive_extract_field` in [cgp-macro-lib/src/derive_extract_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_extract_field.rs). The codegen is `ItemCgpVariant::to_extract_field_items` in [cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which composes the [derive_extractor/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/) helpers (`extractor_enum.rs`, `partial_data.rs`, `has_extractor_impl.rs`, `finalize_extract_impl.rs`, `extract_field_impls.rs`, `utils.rs`); the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The `ExtractField`, `HasExtractor`/`HasExtractorRef`/`HasExtractorMut`, `FinalizeExtract`, `FinalizeExtractResult`, and `PartialData` traits and the `MapType`/`MapTypeRef` markers live under [crates/core/cgp-field/src/](../../../crates/core/cgp-field/src/). diff --git a/docs/implementation/entrypoints/derive_from_variant.md b/docs/implementation/entrypoints/derive_from_variant.md new file mode 100644 index 00000000..a26bf78a --- /dev/null +++ b/docs/implementation/entrypoints/derive_from_variant.md @@ -0,0 +1,47 @@ +# `#[derive(FromVariant)]` — implementation + +`#[derive(FromVariant)]` emits just the variant-construction slice of the variant machinery: one `FromVariant` impl per variant, so an enum can be built generically from any single variant addressed by a type-level tag. This document covers how that codegen works; for the accepted syntax and the full expansion, read the reference document [reference/derives/derive_from_variant.md](../../reference/derives/derive_from_variant.md). + +## Entry point + +The macro is driven by the `derive_from_variant` function in [cgp-macro-lib/src/derive_from_variant.rs](../../../crates/macros/cgp-macro-lib/src/derive_from_variant.rs). It parses the input into a `syn::ItemEnum`, wraps it in an `ItemCgpVariant`, and calls `to_from_variant_impls` — the same method the enum path of `#[derive(CgpData)]` uses for its constructor slice: + +```rust +let variant = ItemCgpVariant { item_enum }; +let item_impls = variant.to_from_variant_impls()?; +``` + +Applying the derive to a non-enum item fails at `syn::parse2`. + +## Pipeline + +There is no multi-stage transform. `ItemCgpVariant::to_from_variant_impls` forwards to the single codegen helper `derive_from_variant_from_enum`, which walks the enum's variants and emits one constructor impl each. The [`cgp_data` AST stack](../asts/cgp_data.md) documents `ItemCgpVariant` and the `Symbol` field-tag type. + +## Generated items + +The derive emits one [`FromVariant`](../../reference/traits/from_variant.md) impl per variant and nothing else — no companion type and no presence tracking, making it the simplest derive in the family. Each impl is keyed by the [`Symbol!`](../../reference/macros/symbol.md) of the variant's name, takes the variant's payload as the associated `Value`, and wraps it in the variant: + +```rust +impl FromVariant for Shape { + type Value = Circle; + fn from_variant(_tag: PhantomData, value: Self::Value) -> Self { Self::Circle(value) } +} +``` + +The `PhantomData` argument exists only to let a caller select which variant to build when several `FromVariant` impls are in scope. The `FromVariant` trait itself is defined in the field crate; the derive supplies only the per-variant impls. + +## Behavior and corner cases + +The enum's generic parameters are threaded onto every impl. This derive emits no `HasFields` representation impls and no extractor — those come from [`#[derive(HasFields)]`](derive_has_fields.md) and [`#[derive(ExtractField)]`](derive_extract_field.md); `FromVariant` is purely the construction slice, included wholesale by [`#[derive(CgpVariant)]`](derive_cgp_variant.md) and [`#[derive(CgpData)]`](derive_cgp_data.md). + +## Known issues + +Like the extractor derive, `#[derive(FromVariant)]` requires every variant to be a single-unnamed-field tuple variant. A fieldless, multi-field, or struct-style variant makes the macro fail with "Expected variant to contain exactly one unnamed field," with no per-variant opt-out. The requirement is described alongside the extractor's in [`derive_extract_field`](derive_extract_field.md#known-issues), and the reference document records its user-visible form. + +## Tests + +`#[derive(FromVariant)]` has no snapshot macro of its own; the constructor impls it emits are part of the variant expansion pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). The behavioral variant tests in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/) — notably [variant_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/variant_dispatch.rs) — construct enums through the generated `from_variant`. The single-unnamed-field requirement has no dedicated failure case in `cgp-macro-tests` and is a candidate for one. + +## Source + +The entry point is `derive_from_variant` in [cgp-macro-lib/src/derive_from_variant.rs](../../../crates/macros/cgp-macro-lib/src/derive_from_variant.rs). The codegen is `ItemCgpVariant::to_from_variant_impls` in [cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which delegates to `derive_from_variant_from_enum` in [cgp-macro-core/src/types/cgp_data/derive_from_variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs); the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The `FromVariant` trait is defined in [crates/core/cgp-field/src/traits/from_variant.rs](../../../crates/core/cgp-field/src/traits/from_variant.rs). diff --git a/docs/implementation/entrypoints/derive_has_field.md b/docs/implementation/entrypoints/derive_has_field.md new file mode 100644 index 00000000..a8998e33 --- /dev/null +++ b/docs/implementation/entrypoints/derive_has_field.md @@ -0,0 +1,69 @@ +# `#[derive(HasField)]` — implementation + +`#[derive(HasField)]` gives a struct tag-keyed field access by emitting one `HasField` impl and one `HasFieldMut` impl per field, each keyed by the field's type-level name. This document covers how that codegen works; for the accepted syntax and the full expansion a user sees, read the reference document [reference/derives/derive_has_field.md](../../reference/derives/derive_has_field.md). + +## Entry point + +The macro is driven by the thin `derive_has_field` function in [cgp-macro-lib/src/derive_has_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_field.rs). It parses the input into a `syn::ItemStruct`, wraps it in an `ItemCgpRecord`, and calls `to_has_field_impls`, which returns the getter impls to emit: + +```rust +let record = ItemCgpRecord { item_struct }; +let item_impls = record.to_has_field_impls()?; +``` + +Because it parses straight into `ItemStruct`, applying the derive to a non-struct item fails at `syn::parse2`. All codegen lives in `cgp-macro-core`; the entry function only concatenates the returned impls. + +## Pipeline + +There is no multi-stage transform. `ItemCgpRecord::to_has_field_impls` forwards to the single codegen helper `derive_has_field_impls_from_struct`, which walks the struct's fields and emits the getter impls. The [`cgp_data` AST stack](../asts/cgp_data.md) documents `ItemCgpRecord` and the `Symbol`/`Index` field-tag types the helper uses. + +## Generated items + +The derive emits two impls per field — a `HasField` read accessor and a `HasFieldMut` mutable accessor — and leaves the struct definition untouched. A named field is keyed by the [`Symbol!`](../../reference/macros/symbol.md) of its identifier; a tuple field is keyed by its positional [`Index`](../../reference/types/index.md). The field's declared type becomes the associated `Value`, and the body simply borrows the corresponding field: + +```rust +// named field +impl HasField for Person { + type Value = String; + fn get_field(&self, key: PhantomData) -> &Self::Value { &self.name } +} +// tuple field — same shape, Index tag, &self.0 body +impl HasField> for Rectangle { + type Value = f64; + fn get_field(&self, key: PhantomData>) -> &Self::Value { &self.0 } +} +``` + +The `HasFieldMut` impl for each field mirrors the read impl, returning `&mut Self::Value` from `&mut self.`. Whether a field's tag is a `Symbol` or an `Index` is decided by mapping the field's `syn::Member` to a [`FieldName`](../asts/cgp_data.md#symbol-index-and-fieldname), whose `ToTokens` picks the right type-level spelling. + +## Behavior and corner cases + +The struct's **generic parameters** are threaded onto every impl: the helper splits the generics into impl-generics, type-generics, and a `where` clause, so `struct Wrapper { value: T }` yields `impl HasField for Wrapper` with `Value = T`, and a lifetime field carries the struct's lifetime through (`impl<'a> HasField<…> for Context<'a>` with `Value = &'a str`). + +A **unit struct** has no fields, so the derive emits nothing rather than erroring. The helper only handles the named-field and tuple-field cases; there is no whole-struct output here — the aggregate `HasFields` view comes from [`#[derive(HasFields)]`](derive_has_fields.md) instead. + +Field access through **smart pointers** is not the derive's doing: `HasField`/`HasFieldMut` have blanket impls over `Deref`/`DerefMut` targets defined in the field crate, so a `Box` resolves through to the inner struct without the derive generating anything for the pointer type. + +## Snapshots + +Every `snapshot_derive_has_field!` invocation across the suite is indexed here, since these snapshots all belong to this entrypoint. They live in the `field_access` target, which owns the `#[derive(HasField)]` expansion: + +- [field_access/index.rs](../../../crates/tests/cgp-tests/tests/field_access/index.rs) — a tuple struct, each field keyed by `Index<0>`/`Index<1>` rather than a `Symbol!`. +- [field_access/lifetime_field.rs](../../../crates/tests/cgp-tests/tests/field_access/lifetime_field.rs) — a struct lifetime lifted onto the impls, with a borrowed field type (`&'a str`) kept as `Value`. +- [field_access/chain.rs](../../../crates/tests/cgp-tests/tests/field_access/chain.rs) — the canonical named-field expansion, over two owned structs. +- [field_access/chain_inner_life.rs](../../../crates/tests/cgp-tests/tests/field_access/chain_inner_life.rs) — the inner struct carries a lifetime, threaded onto its impls. +- [field_access/chain_outer_life.rs](../../../crates/tests/cgp-tests/tests/field_access/chain_outer_life.rs) — the outer struct borrows the inner one, with the outer lifetime on its impls. +- [field_access/chain_deeply_nested.rs](../../../crates/tests/cgp-tests/tests/field_access/chain_deeply_nested.rs) — five structs each deriving `HasField`, pinning the plain expansion repeated across a deep chain. + +## Tests + +The behavioral tests confirm the generated getters read the right fields: + +- [field_access/index.rs](../../../crates/tests/cgp-tests/tests/field_access/index.rs) reads a tuple struct's fields at run time through `get_field` with `Index<0>`/`Index<1>` tags. +- [field_access/lifetime_field.rs](../../../crates/tests/cgp-tests/tests/field_access/lifetime_field.rs) reads a lifetime-carrying field back out. +- [field_access/chain.rs](../../../crates/tests/cgp-tests/tests/field_access/chain.rs), [chain_inner_life.rs](../../../crates/tests/cgp-tests/tests/field_access/chain_inner_life.rs), [chain_outer_life.rs](../../../crates/tests/cgp-tests/tests/field_access/chain_outer_life.rs), and [chain_deeply_nested.rs](../../../crates/tests/cgp-tests/tests/field_access/chain_deeply_nested.rs) compose the generated getters through `ChainGetters` to read a nested field in one hop. +- [field_access/symbol.rs](../../../crates/tests/cgp-tests/tests/field_access/symbol.rs) and [field_access/index_display.rs](../../../crates/tests/cgp-tests/tests/field_access/index_display.rs) exercise the `Symbol!`/`Index` tag types the derive emits. + +## Source + +The entry point is `derive_has_field` in [cgp-macro-lib/src/derive_has_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_field.rs). It calls `ItemCgpRecord::to_has_field_impls` in [cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), whose codegen is `derive_has_field_impls_from_struct` in [cgp-macro-core/src/types/cgp_data/derive_has_field.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_field.rs); the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The `HasField`/`HasFieldMut` traits are defined in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). diff --git a/docs/implementation/entrypoints/derive_has_fields.md b/docs/implementation/entrypoints/derive_has_fields.md new file mode 100644 index 00000000..1c914ea0 --- /dev/null +++ b/docs/implementation/entrypoints/derive_has_fields.md @@ -0,0 +1,69 @@ +# `#[derive(HasFields)]` — implementation + +`#[derive(HasFields)]` gives a struct or enum a whole-shape view by emitting the representation impls — `HasFields`, `HasFieldsRef`, `FromFields`, `ToFields`, `ToFieldsRef` — that describe the type as a single type-level product (for a struct) or sum (for an enum). This document covers how that codegen works; for the accepted syntax and the full expansion, read the reference document [reference/derives/derive_has_fields.md](../../reference/derives/derive_has_fields.md). + +## Entry point + +The macro is driven by the `derive_has_fields` function in [cgp-macro-lib/src/derive_has_fields.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_fields.rs). Unlike the other data derives it dispatches on shape at the entry point: it parses the input as a `syn::Item` and branches on `struct` versus `enum`, rejecting anything else with a spanned "expect body to be either a struct or enum" error: + +```rust +let impls = match item { + Item::Struct(item_struct) => ItemCgpRecord { item_struct }.to_has_fields_impls()?, + Item::Enum(item_enum) => derive_has_fields_impls_from_enum(&item_enum)?, + _ => return Err(/* struct or enum */), +}; +``` + +The struct path goes through `ItemCgpRecord`; the enum path calls the enum codegen helper directly. + +## Pipeline + +There is no multi-stage transform. Both paths call a single codegen helper — `derive_has_fields_impls_from_struct` for a struct, `derive_has_fields_impls_from_enum` for an enum — that emits the five representation impls. The [`cgp_data` AST stack](../asts/cgp_data.md) documents `ItemCgpRecord` and the `Symbol`/`Index` field-tag types. + +## Generated items + +The derive emits five impls and leaves the type definition untouched. The load-bearing part is the `Fields` associated type: a struct's fields become a [`Product`](../../reference/macros/product.md) of [`Field`](../../reference/types/field.md) entries over the `Cons`/`Nil` spine, and an enum's variants become a [`Sum`](../../reference/macros/sum.md) of `Field` entries over the `Either`/`Void` spine. Named fields and variant names are keyed by [`Symbol!`](../../reference/macros/symbol.md); tuple fields by [`Index`](../../reference/types/index.md). + +```rust +// struct → product +impl HasFields for Person { + type Fields = Cons, Cons, Nil>>; +} +// enum → sum, terminated by Void +impl HasFields for Shape { + type Fields = Either, Either, Void>>; +} +``` + +Alongside the shape type, the derive emits `HasFieldsRef` (the same product/sum with each value borrowed under a fresh `'__a` lifetime) and the three conversions: `ToFields` builds the product/sum from a value, `FromFields` destructures it back, and `ToFieldsRef` builds the borrowed form. For a struct the conversions read `self..into()` into a `Cons(…)` chain and pattern-match `Cons(…)` back into `Self { … }`; for an enum they match each concrete variant to its `Either` arm and back. The product spine is built by `item_fields_to_product_type` in the `product.rs` submodule and the sum spine by `variants_to_sum_type` in `sum.rs`; the entries are chained right-associatively. + +## Behavior and corner cases + +A **single-field tuple struct** (a newtype) is special-cased: its `Fields` is the inner type directly, not a one-element `Cons, _>, Nil>`, and the conversions pass the single value straight through. A tuple struct with more than one field is not special-cased — its fields are keyed by `Index` and chained into the usual product. + +A **unit struct** produces `Nil` as its `Fields`, and its conversions round-trip through the empty product. + +The type's **generic parameters and `where` clause** are threaded onto all five impls. A borrowed field type appears verbatim in the product, and `HasFieldsRef` layers its own `'__a` borrow on top — so a field of type `&'a Name` becomes `&'__a &'a Name` in `FieldsRef<'__a>`. The `HasFieldsRef` associated type carries the `where Self: '__a` bound that every borrowed representation needs. + +An **enum** always maps each variant's payload into a `Field` entry regardless of the payload's own shape; the `HasFields` enum path does not impose the single-unnamed-field requirement that the extractor and `FromVariant` derives do, because it only names the payload type rather than deconstructing it. + +## Snapshots + +Every `snapshot_derive_has_fields!` invocation across the suite is indexed here, since these snapshots all belong to this entrypoint. The struct expansion is owned by the `extensible_records` target and the enum expansion by `extensible_variants`: + +- [extensible_records/struct_single_named_field.rs](../../../crates/tests/cgp-tests/tests/extensible_records/struct_single_named_field.rs) — the canonical struct expansion, one named field. +- [extensible_records/struct_two_named_fields.rs](../../../crates/tests/cgp-tests/tests/extensible_records/struct_two_named_fields.rs) — a two-field `Cons<_, Cons<_, Nil>>` product. +- [extensible_records/struct_single_unnamed_field.rs](../../../crates/tests/cgp-tests/tests/extensible_records/struct_single_unnamed_field.rs) — the newtype special case, `Fields` = the inner type. +- [extensible_records/struct_tuple_fields.rs](../../../crates/tests/cgp-tests/tests/extensible_records/struct_tuple_fields.rs) — a multi-field tuple struct keyed by `Index`. +- [extensible_records/struct_generic.rs](../../../crates/tests/cgp-tests/tests/extensible_records/struct_generic.rs) — a generic struct with a `where` clause threaded onto each impl. +- [extensible_records/struct_generic_lifetime.rs](../../../crates/tests/cgp-tests/tests/extensible_records/struct_generic_lifetime.rs) — a lifetime plus type parameter, with the layered `&'__a &'a` borrow in `FieldsRef`. +- [extensible_variants/has_fields_enum.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/has_fields_enum.rs) — the canonical enum expansion, a `Sum!` of `Field`. +- [extensible_variants/has_fields_enum_generic.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/has_fields_enum_generic.rs) — a generic enum with a lifetime and a reference-typed payload. + +## Tests + +The snapshot tests above double as the coverage: each pins one field-shape and, where paired with runtime assertions, round-trips a value through `to_fields`/`from_fields`. The `struct_single_unnamed_field` snapshot is the guard on the newtype special case, and `struct_generic`/`struct_generic_lifetime` and `has_fields_enum_generic` guard the generic-threading behavior. + +## Source + +The entry point is `derive_has_fields` in [cgp-macro-lib/src/derive_has_fields.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_fields.rs). The struct path calls `ItemCgpRecord::to_has_fields_impls` in [cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs); both paths land in the [derive_has_fields/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/) submodule, where `derive_struct.rs`/`derive_enum.rs` drive the five impls, `product.rs` (`item_fields_to_product_type`) builds the struct product, `sum.rs` (`variants_to_sum_type`) builds the enum sum, and the `from_fields_*`/`to_fields_*`/`to_fields_ref_*` files build the conversions. The AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The `HasFields`, `HasFieldsRef`, `FromFields`, `ToFields`, and `ToFieldsRef` traits and the `Field`/`Either`/`Void` building blocks live under [crates/core/cgp-field/src/](../../../crates/core/cgp-field/src/). diff --git a/docs/implementation/entrypoints/path.md b/docs/implementation/entrypoints/path.md new file mode 100644 index 00000000..6ae83594 --- /dev/null +++ b/docs/implementation/entrypoints/path.md @@ -0,0 +1,49 @@ +# `Path!` — implementation + +`Path!` is a function-like macro that expands an `@`-prefixed dotted name into a `PathCons` chain — the type-level route CGP's namespace and `RedirectLookup` machinery walks through nested delegation tables. This document covers how the macro parses the segments and emits the chain; for the accepted syntax and the full expansion a user sees, read the reference document [reference/macros/path.md](../../reference/macros/path.md). + +## Entry point + +The macro is driven by the thin `Path` function in [cgp-macro-lib/src/path.rs](../../../crates/macros/cgp-macro-lib/src/path.rs), which parses the body into a `UniPath` and emits its tokens directly: + +```rust +let unipath: UniPath = parse2(body)?; +Ok(unipath.to_token_stream()) +``` + +There is no `eval` step — the `UniPath` type both parses the `@`-path and, through its `ToTokens`, folds the parsed segments into the `PathCons` chain. The `UniPath` type and the segment types around it are documented in the [`path` AST stack](../asts/path.md). + +## Pipeline + +The macro is a single parse-then-emit step. `UniPath::parse` consumes the leading `@` and a dot-separated, non-empty run of segments, classifying each into a `PathElement` (a `Symbol` or a named `Type`); `UniPath::to_tokens` right-folds those segments into the `PathCons` chain. The classification is where the interesting decision lives, and it belongs to `PathElement` in the [`path` AST document](../asts/path.md). + +## Generated items + +`Path!` emits a single type: a right-nested chain of `PathCons` terminated by `Nil`, one `PathCons` per segment. Each lowercase, non-primitive segment is encoded as a `Symbol!` type-level string and every other segment is kept as the named type it spells: + +```rust +// Path!(@app.error.ErrorRaiserComponent) +PathCons< + Symbol!("app"), + PathCons>, +> +``` + +A lowercase segment expands further, since `Symbol!("app")` is itself a `Symbol<3, Chars<'a', …>>` chain. A single-segment path becomes `PathCons`. `PathCons` and `Nil` are emitted through the [export markers](../../../crates/macros/cgp-macro-core/src/exports.rs). + +## Behavior and corner cases + +The leading `@` is required — `UniPath::parse` consumes an `At` token before anything else, so a body without it fails at parse time — and at least one segment must follow, because the segments are read with `parse_separated_nonempty`. + +Each segment is first parsed as a full Rust `Type`, then reclassified: only a segment that reduces to a single identifier beginning with a lowercase ASCII letter, and is not a primitive type name, becomes a `Symbol`; everything else stays the named type. The primitive exception means a lowercase name like `u32`, `bool`, `usize`, or `str` is kept as the primitive type rather than turned into a symbol. This is the same convention `#[cgp_namespace]` entries and `#[prefix(...)]` attributes embed, and those constructs reuse the same segment and fold machinery rather than the `Path!` entry function. + +## Tests + +`Path!` has no snapshot macro of its own, and it is rarely written directly — the `@`-path syntax is almost always embedded inside `#[cgp_namespace]` entries and `#[prefix(...)]` attributes instead of the bare macro. Its expansion is therefore exercised indirectly through the namespace and prefix machinery that shares its parsing. + +- [namespaces/redirect_lookup.rs](../../../crates/tests/cgp-tests/tests/namespaces/redirect_lookup.rs) pins, through a `snapshot_cgp_component!` golden, how a `#[prefix(@bar.baz in DefaultNamespace)]` attribute lowers a component lookup into a `RedirectLookup` over the `PathCons` chain the same segment fold produces. +- [namespaces/namespace_symbol_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_symbol_path.rs) and [namespaces/namespace_type_path.rs](../../../crates/tests/cgp-tests/tests/namespaces/namespace_type_path.rs) exercise the lowercase-symbol and capitalized-type segment classifications through `#[cgp_namespace]` `@`-paths. + +## Source + +The entry point is `Path` in [cgp-macro-lib/src/path.rs](../../../crates/macros/cgp-macro-lib/src/path.rs); the `UniPath`, `PathElement`, and the wider path stack live in [cgp-macro-core/src/types/path/](../../../crates/macros/cgp-macro-core/src/types/path/) and are documented in [asts/path.md](../asts/path.md). The runtime spine `PathCons` is defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/path.rs), and the [`RedirectLookup`](../../reference/providers/redirect_lookup.md) provider that walks a path is in [cgp-component](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs). diff --git a/docs/implementation/entrypoints/product.md b/docs/implementation/entrypoints/product.md new file mode 100644 index 00000000..7ca9f270 --- /dev/null +++ b/docs/implementation/entrypoints/product.md @@ -0,0 +1,58 @@ +# `Product!` and `product!` — implementation + +`Product!` and `product!` are function-like macros that expand a comma-separated list into a `Cons`/`Nil` chain — a type at the type level for `Product!`, a matching value for `product!`. This document covers how each parses its list and emits the chain; for the accepted syntax and the full expansion a user sees, read the reference document [reference/macros/product.md](../../reference/macros/product.md). + +## Entry point + +The two macros are driven by the `Product` and `product` functions in [cgp-macro-lib/src/product.rs](../../../crates/macros/cgp-macro-lib/src/product.rs), which follow the same shape: parse the body into an AST type, call its `eval`, and emit the result. + +```rust +// Product! +let product_type: ProductType = parse2(body)?; +Ok(product_type.eval()?.to_token_stream()) + +// product! +let product_expr: ProductExpr = parse2(body)?; +Ok(product_expr.eval()?.to_token_stream()) +``` + +Both parse the body as a comma-separated list, so a malformed element fails at `parse2`. The two AST types are documented together in the [`product` AST stack](../asts/product.md). + +## Pipeline + +Each macro is a parse-then-`eval` step with no further stages. The `Parse` impl reads a `Punctuated`, and `eval` folds it into the chain and re-parses the result through [`parse_internal!`](../macros/parse_internal.md) so the emitted tokens are validated as a `syn::Type`. The [`product` AST document](../asts/product.md) covers both types. + +## Generated items + +`Product!` emits a single type: a right-nested chain of `Cons` terminated by `Nil`, one `Cons` per element. + +```rust +// Product![A, B, C] +Cons>> +``` + +`product!` emits a value of that type using the `Cons` tuple-struct constructor rather than the type form, so the value's type is exactly what `Product!` builds over the same elements: + +```rust +// product![a, b, c] +Cons(a, Cons(b, Cons(c, Nil))) +``` + +The chain is built by folding right-to-left onto `Nil`, so an empty `Product![]` (or `product![]`) is just `Nil`. `Cons` and `Nil` are emitted through the [export markers](../../../crates/macros/cgp-macro-core/src/exports.rs). + +## Behavior and corner cases + +The parser is deliberately permissive: `product!` parses its elements as `Type`s exactly as `Product!` does, not as `Expr`s, and only the emission differs (`Cons<…>` versus `Cons(…)`). A trailing comma is accepted on both because the list is parsed with `parse_terminated`, and an empty body is valid and yields `Nil`. + +Because `eval` re-parses its output through `parse_internal!`, a fold that produced malformed tokens would surface as a spanned `syn::Error` rather than raw token garbage — though with `Cons`/`Nil` and well-formed element types this path does not normally fail. + +## Tests + +`Product!`/`product!` have no snapshot macro of their own; the chain they build is exercised wherever a struct's field list is derived, since `#[derive(HasFields)]` emits a `Product!` of `Field` entries. + +- [extensible_records/person_record.rs](../../../crates/tests/cgp-tests/tests/extensible_records/person_record.rs) and [extensible_records/record_derive.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_derive.rs) pin, through `snapshot_derive_cgp_data!` goldens, the `Product!` field spine a record derives, so the `Cons`/`Nil` shape is checked as embedded output. +- [handlers/pipe_handlers.rs](../../../crates/tests/cgp-tests/tests/handlers/pipe_handlers.rs) uses `Product![…]` to write a handler pipeline, exercising the type-level form as a list of provider types rather than fields. + +## Source + +The entry points are `Product` and `product` in [cgp-macro-lib/src/product.rs](../../../crates/macros/cgp-macro-lib/src/product.rs); the `ProductType` and `ProductExpr` AST types live in [cgp-macro-core/src/types/product/](../../../crates/macros/cgp-macro-core/src/types/product/) and are documented in [asts/product.md](../asts/product.md). The fold re-parses through [parse_internal!](../macros/parse_internal.md). The runtime types `Cons` and `Nil` are defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/). diff --git a/docs/implementation/entrypoints/snapshot_macros.md b/docs/implementation/entrypoints/snapshot_macros.md new file mode 100644 index 00000000..ac6af5a2 --- /dev/null +++ b/docs/implementation/entrypoints/snapshot_macros.md @@ -0,0 +1,76 @@ +# The `snapshot_*!` macro family — implementation + +The `snapshot_*!` macros are the test-only proc macros that pin a CGP macro's expansion: each one invokes the real `cgp-macro-lib` entry function on an inline invocation, emits the generated code into the module *so it still compiles*, and generates a `#[test]` that asserts a pretty-printed `insta` snapshot of that same code. This document covers how the family is built; it has no reference document, because these macros are internal test utilities rather than user-facing CGP constructs. + +## Entry point + +The proc-macro shims live in [cgp-macro-test-util/src/lib.rs](../../../crates/macros/cgp-macro-test-util/src/lib.rs) — one `#[proc_macro]` per snapshot macro, each forwarding to a same-named function in [cgp-macro-test-util-lib](../../../crates/macros/cgp-macro-test-util-lib/) and converting a `syn::Error` into a compile error. The real logic is in `cgp-macro-test-util-lib`, split into the per-macro entrypoints under [src/entrypoints/](../../../crates/macros/cgp-macro-test-util-lib/src/entrypoints/) and the shared snapshot types and helpers. This crate is a peer of `cgp-macro-lib`, not part of `cgp-macro-core`; it depends on `cgp-macro-lib` so that a snapshot runs the *actual* macro rather than a reimplementation. + +The family members mirror the CGP macros they pin. The current set is `snapshot_cgp_component!`, `snapshot_cgp_impl!`, `snapshot_cgp_provider!`, `snapshot_cgp_new_provider!`, `snapshot_cgp_fn!`, `snapshot_cgp_getter!`, `snapshot_cgp_auto_getter!`, `snapshot_cgp_type!`, `snapshot_cgp_namespace!`, `snapshot_blanket_trait!`, `snapshot_delegate_components!`, `snapshot_check_components!`, `snapshot_delegate_and_check_components!`, `snapshot_derive_has_field!`, `snapshot_derive_has_fields!`, and `snapshot_derive_cgp_data!`. There is deliberately no snapshot macro for `#[cgp_computer]`, `#[cgp_producer]`, `#[cgp_auto_dispatch]`, or `#[async_trait]` — those extra-feature macros are pinned only behaviorally, through the handler, dispatch, and async tests indexed in their own implementation documents. + +## Pipeline + +Every family member follows the same three-step shape, differing only in which parser reads the invocation and which `cgp-macro-lib` function it calls: + +- **Parse** the macro body into a snapshot wrapper — a wrapper that captures the macro invocation to expand plus the trailing `#[test]` scaffold (the test name, the output binding, and the assertion expression). +- **Expand** by calling the corresponding `cgp-macro-lib` entry function (for example `cgp_macro_lib::cgp_component(attr, body)`) on the captured invocation, producing the same `TokenStream` a user would get. +- **Wrap** the expansion with `MacroSnapshot::wrap_output`, which pretty-prints it and stitches together the final output. + +Which parser is used depends on how the pinned macro is invoked, and the three shapes correspond to three wrapper types in [src/types/](../../../crates/macros/cgp-macro-test-util-lib/src/types/): + +- **`AttributeMacroSnapshot`** — for an attribute macro. It parses a `#[keyword(...)]` or `#[keyword { ... }]` attribute (its argument tokens become `attr`) followed by the annotated item (`ItemTrait`, `ItemImpl`, …). Used by `snapshot_cgp_component!`, `snapshot_cgp_impl!`, and the other attribute-macro members. +- **`StatementMacroSnapshot`** — for a function-like macro. It parses `keyword! { … }` and hands the brace body straight to the entry function. Used by `snapshot_delegate_components!` and its check-component siblings. +- **`DeriveMacroSnapshot`** — for a derive. It parses `#[derive(Keyword)]` followed by the item, and the entrypoint re-attaches the `#[derive(...)]` before calling the derive expander. Used by `snapshot_derive_has_field!` and the other derive members. + +The keyword each wrapper matches is a compile-time marker from [src/keywords.rs](../../../crates/macros/cgp-macro-test-util-lib/src/keywords.rs), built with `cgp-macro-core`'s `define_keyword!`, so the wrapper only accepts the attribute or macro name it is meant to pin. + +## Generated items + +A `snapshot_*!` invocation expands to the real generated code followed by a `#[test]` that binds the pretty-printed expansion to the declared name and runs the assertion. From this invocation — + +```rust +snapshot_cgp_component! { + #[cgp_component(FooProvider)] + pub trait CanDoFoo { + fn foo(&self, value: u32) -> String; + } + + expand_foo_component(output) { + insta::assert_snapshot!(output, @"…"); + } +} +``` + +— `MacroSnapshot::wrap_output` emits the component expansion verbatim (the consumer trait, provider trait, blanket impls, marker struct, and provider impls) and then: + +```rust +#[test] +fn expand_foo_component() { + let output = ""; + insta::assert_snapshot!(output, @"…"); +} +``` + +Because the expansion is emitted into the module, the snapshot participates in normal compilation exactly like a plain macro invocation would — adding or removing a snapshot changes only the golden assertion, never the compile or runtime coverage. The pretty-printed string is produced by `pretty_format` in [src/functions/pretty_format.rs](../../../crates/macros/cgp-macro-test-util-lib/src/functions/pretty_format.rs): it runs `cgp-macro-core`'s `strip_macro_prelude` over the tokens to drop the `::cgp::macro_prelude::` hygiene prefix, then formats with `prettyplease`, so the snapshot reads as the code a user would write rather than as fully-qualified hygienic output. + +## Behavior and corner cases + +The snapshot **runs the production macro**, not a copy: any change to a `cgp-macro-lib` entry function's output flows straight into the pinned snapshot string, which is the point — a diff in the golden output is the signal that the expansion changed. + +The **derive members re-emit the annotated item themselves**. Because a derive macro produces only the *added* code and not the struct or enum it decorates, an entrypoint like `snapshot_derive_has_field` prepends the original item to the output so the generated impls have a type to attach to. + +The **assertion is inline by convention**, following [crates/tests/CLAUDE.md](../../../crates/tests/CLAUDE.md): the snapshot string is written as an `insta` inline snapshot (`@"…"`) in the test file, so the golden output lives beside the invocation rather than in a separate `.snap` file. + +## Tests + +The snapshot macros are the test harness rather than the thing under test, so their coverage is the set of snapshot invocations across the suite. Per [crates/tests/CLAUDE.md](../../../crates/tests/CLAUDE.md), each CGP macro's expansion is snapshotted only in the concept target that owns its feature, and each owning target's snapshots are indexed by that macro's own implementation document. Representative usages: + +- [basic_delegation/component_macro.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs) — the canonical `snapshot_cgp_component!` invocation, using the `AttributeMacroSnapshot` shape. +- [async_and_send/cgp_fn_async.rs](../../../crates/tests/cgp-tests/tests/async_and_send/cgp_fn_async.rs) — a `snapshot_cgp_fn!` over a stacked `#[cgp_fn]` / `#[async_trait]`. +- [dispatching/use_delegate_getter.rs](../../../crates/tests/cgp-tests/tests/dispatching/use_delegate_getter.rs) — `snapshot_delegate_components!` and `snapshot_delegate_and_check_components!`, using the `StatementMacroSnapshot` shape. + +The per-macro Snapshots sections — for example [cgp_component.md](cgp_component.md) — are the canonical index of which expansion variants each family member pins and which are still missing. + +## Source + +The proc-macro shims are in [cgp-macro-test-util/src/lib.rs](../../../crates/macros/cgp-macro-test-util/src/lib.rs); the per-macro entrypoints are in [cgp-macro-test-util-lib/src/entrypoints/](../../../crates/macros/cgp-macro-test-util-lib/src/entrypoints/), the snapshot wrapper types in [src/types/](../../../crates/macros/cgp-macro-test-util-lib/src/types/), the pretty-printer in [src/functions/pretty_format.rs](../../../crates/macros/cgp-macro-test-util-lib/src/functions/pretty_format.rs), and the keyword markers in [src/keywords.rs](../../../crates/macros/cgp-macro-test-util-lib/src/keywords.rs). Each snapshot calls the matching production entry function in [cgp-macro-lib](../../../crates/macros/cgp-macro-lib/). diff --git a/docs/implementation/entrypoints/sum.md b/docs/implementation/entrypoints/sum.md new file mode 100644 index 00000000..7daa9309 --- /dev/null +++ b/docs/implementation/entrypoints/sum.md @@ -0,0 +1,44 @@ +# `Sum!` — implementation + +`Sum!` is a function-like macro that expands a comma-separated list of types into an `Either`/`Void` chain — the type-level coproduct CGP uses to represent an enum's variants. This document covers how the macro parses its list and emits the chain; for the accepted syntax and the full expansion a user sees, read the reference document [reference/macros/sum.md](../../reference/macros/sum.md). + +## Entry point + +The macro is driven by the thin `Sum` function in [cgp-macro-lib/src/sum.rs](../../../crates/macros/cgp-macro-lib/src/sum.rs), which parses the body into a `SumType`, calls its `eval`, and emits the result: + +```rust +let sum_type: SumType = parse2(body)?; +Ok(sum_type.eval()?.to_token_stream()) +``` + +The body is parsed as a comma-separated list of types, so a malformed element fails at `parse2`. The single AST type is documented in the [`sum` AST stack](../asts/sum.md). + +## Pipeline + +The macro is a parse-then-`eval` step with no further stages, mirroring `Product!` exactly but over a different spine. `SumType::parse` reads a `Punctuated`, and `eval` folds it into the chain and re-parses through [`parse_internal!`](../macros/parse_internal.md). The [`sum` AST document](../asts/sum.md) covers the type. + +## Generated items + +`Sum!` emits a single type: a right-nested chain of `Either` terminated by `Void`, one `Either` per element. + +```rust +// Sum![A, B, C] +Either>> +``` + +The chain is built by folding right-to-left onto `Void`, so an empty `Sum![]` is just `Void`. `Either` and `Void` are emitted through the [export markers](../../../crates/macros/cgp-macro-core/src/exports.rs). + +## Behavior and corner cases + +The only structural difference from `Product!` is the terminator: a sum folds onto `Void` rather than `Nil`. This is what makes an empty sum uninhabited — `Void` is an empty enum with no values, so an empty choice cannot be constructed, whereas an empty product (`Nil`) is a valid unit-like value. Otherwise the parsing is identical: a trailing comma is accepted through `parse_terminated`, and an empty body is valid. + +## Tests + +`Sum!` has no snapshot macro of its own; its expansion is exercised by a dedicated same-type assertion and by the enum field-derive that emits a `Sum!` of `Field` branches. + +- [extensible_variants/sum_macro.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/sum_macro.rs) writes `Sum![u32, String, bool]` and asserts it is the identical type to the hand-written `Either>>`, pinning the expansion directly, then builds values by nesting `Left`/`Right` to select each branch. +- [extensible_variants/has_fields_enum.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/has_fields_enum.rs) exercises the `Sum!` variant spine an enum derives through `#[derive(HasFields)]`, where each branch is a `Field`. + +## Source + +The entry point is `Sum` in [cgp-macro-lib/src/sum.rs](../../../crates/macros/cgp-macro-lib/src/sum.rs); the `SumType` AST type lives in [cgp-macro-core/src/types/sum.rs](../../../crates/macros/cgp-macro-core/src/types/sum.rs) and is documented in [asts/sum.md](../asts/sum.md). The fold re-parses through [parse_internal!](../macros/parse_internal.md). The runtime types `Either` and the uninhabited `Void` are defined in [cgp-field](../../../crates/core/cgp-field/src/types/sum.rs). diff --git a/docs/implementation/entrypoints/symbol.md b/docs/implementation/entrypoints/symbol.md new file mode 100644 index 00000000..749668d8 --- /dev/null +++ b/docs/implementation/entrypoints/symbol.md @@ -0,0 +1,52 @@ +# `Symbol!` — implementation + +`Symbol!` is a function-like macro that expands a string literal into a type-level string — the `Symbol>` type CGP uses to name a field at compile time. This document covers how the macro parses the literal and emits that type; for the accepted syntax and the full expansion a user sees, read the reference document [reference/macros/symbol.md](../../reference/macros/symbol.md). + +## Entry point + +The macro is driven by the thin `Symbol` function in [cgp-macro-lib/src/symbol.rs](../../../crates/macros/cgp-macro-lib/src/symbol.rs), which parses the body into a `Symbol` construct and returns its token stream directly: + +```rust +let symbol: Symbol = parse2(body)?; +Ok(symbol.to_token_stream()) +``` + +There is no multi-stage pipeline here — a single `Parse` reads the literal and a single `ToTokens` emits the type, so all the logic lives in the one [`Symbol` AST type](../asts/symbol.md). A body that is not a string literal fails while parsing `Symbol`, since its `Parse` impl expects a `LitStr`. + +## Pipeline + +The macro is a single parse-then-emit step with no intermediate stages. `Symbol::parse` captures the literal's value and span, and `Symbol::to_tokens` folds that value into the `Symbol>` type. The [`Symbol` AST document](../asts/symbol.md) covers the type. + +## Generated items + +`Symbol!` emits a single type: the `Symbol` wrapper around a right-nested `Chars` chain terminated by `Nil`, with the string's byte length baked in as the leading const argument. The chain has one `Chars` node per character: + +```rust +// Symbol!("abc") +Symbol<3, Chars<'a', Chars<'b', Chars<'c', Nil>>>> +``` + +The chain is built by folding the characters right-to-left onto `Nil`, so an empty `Symbol!("")` collapses to `Symbol<0, Nil>`. The `Symbol`, `Chars`, and `Nil` names are emitted through the [export markers](../../../crates/macros/cgp-macro-core/src/exports.rs) so the expansion is hygienic. + +## Behavior and corner cases + +The leading `LEN` argument is the string's **byte** length, taken from `str::len()`, not its character count. For an ASCII string the two coincide, but a multi-byte string diverges: `Symbol!("世界你好")` records `12`, while the `Chars` chain has one node per Unicode scalar value, so four `Chars` nodes. This split is deliberate — the char count lives in the chain's shape and the byte length lives in `LEN`. + +Every emitted token carries the literal's span (via `quote_spanned!`), so a downstream type error points back at the `Symbol!` invocation rather than at the macro internals. + +The `Symbol` type is also constructed from a bare identifier rather than a literal by the [`Path!` stack](../asts/path.md): a lowercase path segment becomes a `Symbol` through `Symbol::from_ident`, which reuses the same `ToTokens` emission. That path does not go through this macro's `Parse` impl, which only accepts a `LitStr`. + +## Known issues + +The `LEN` const argument exists to work around stable Rust's inability to compute the length of a `Chars` chain inside a const-generic context. Rather than deriving the length from the character list at the type level, the macro precomputes it and bakes it in as a separate parameter. This is why the length appears redundantly in every `Symbol` type and why it is a byte length rather than a character count; it is a limitation of the encoding, not a bug. + +## Tests + +The `Symbol!` expansion has no snapshot macro of its own; its behavior is exercised through runtime round-trip tests and, indirectly, through the field-derive snapshots that embed `Symbol` in their output. + +- [field_access/symbol.rs](../../../crates/tests/cgp-tests/tests/field_access/symbol.rs) checks that a `Symbol!` value `Display`s back to its string and that `StaticString::VALUE` recovers the original literal, covering the empty string, a single character, a multi-word string, and a multi-byte Unicode string — the last pinning that the char chain, not `LEN`, drives the reconstruction. +- [extensible_records/person_record.rs](../../../crates/tests/cgp-tests/tests/extensible_records/person_record.rs) pins, through a `snapshot_derive_cgp_data!` golden, how a multi-character field name such as `first_name` expands into its `Symbol>` spine with the leading length. + +## Source + +The entry point is `Symbol` in [cgp-macro-lib/src/symbol.rs](../../../crates/macros/cgp-macro-lib/src/symbol.rs); the `Symbol` AST type lives in [cgp-macro-core/src/types/field/symbol.rs](../../../crates/macros/cgp-macro-core/src/types/field/symbol.rs) and is documented in [asts/symbol.md](../asts/symbol.md). The runtime types `Symbol`, `Chars`, and `Nil` are defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/). diff --git a/docs/implementation/functions/derive/generics.md b/docs/implementation/functions/derive/generics.md new file mode 100644 index 00000000..9a40f7bc --- /dev/null +++ b/docs/implementation/functions/derive/generics.md @@ -0,0 +1,13 @@ +# `merge_generics` + +`merge_generics` combines two `syn::Generics` into one, concatenating their parameters and unioning their `where` clauses. The CGP codegen repeatedly needs to build an impl whose generics come from more than one source — a trait's own generics plus a provider's extra parameters, say — and this helper is how those are joined into a single parameter list and predicate set. + +The merge is a straightforward concatenation: the parameters of the first `Generics` come before those of the second, and the predicates of both `where` clauses are collected into one (dropped entirely when neither side has any). The angle-bracket tokens are taken from the first argument, so parameter *order* follows the caller's chosen sequence — the first argument's parameters lead. There is no de-duplication or reordering, so the caller is responsible for passing parameter lists that are already free of clashes and in a valid order (lifetimes before type parameters, as Rust requires). + +## Tests + +The helper has no dedicated test; it is covered indirectly through the expansion snapshots of the macros that assemble multi-source impls. + +## Source + +The function lives in [cgp-macro-core/src/functions/generics/merge_generics.rs](../../../../crates/macros/cgp-macro-core/src/functions/generics/merge_generics.rs). diff --git a/docs/implementation/functions/derive/idents.md b/docs/implementation/functions/derive/idents.md new file mode 100644 index 00000000..4a5ae36c --- /dev/null +++ b/docs/implementation/functions/derive/idents.md @@ -0,0 +1,15 @@ +# Identifier case conversion + +The case-conversion helpers turn identifiers between the naming conventions CGP's generated code uses — PascalCase for type and trait names, snake_case for values and method names. The macros derive one name from another all over the codebase (a provider trait name from a function name, a context value name from the context type name), and these functions are the shared way to do it. + +`to_camel_case_str` produces a PascalCase string by splitting on underscores, dropping empty segments, and upper-casing the first letter of each word. `to_snake_case_str` produces a snake_case string by inserting an underscore before each interior uppercase letter and lower-casing the result. + +The one non-obvious helper is `to_snake_case_ident`, which additionally wraps its result in the reserved `__…__` form: unless the identifier already starts with an underscore, `Context` becomes `__context__` rather than plain `context`. This is what produces the reserved value name that pairs with a reserved type name like `__Context__`, keeping generated bindings from clashing with a user's own identifiers — the same convention behind the reserved names described in [entrypoints/cgp_component.md](../../entrypoints/cgp_component.md). + +## Tests + +These helpers have no dedicated test; they are covered through the expansion snapshots, where the derived names appear in the generated code. + +## Source + +The functions live in [cgp-macro-core/src/functions/camel_case.rs](../../../../crates/macros/cgp-macro-core/src/functions/camel_case.rs) and [cgp-macro-core/src/functions/snake_case.rs](../../../../crates/macros/cgp-macro-core/src/functions/snake_case.rs). diff --git a/docs/implementation/macros/export_constructs.md b/docs/implementation/macros/export_constructs.md new file mode 100644 index 00000000..64bd33fc --- /dev/null +++ b/docs/implementation/macros/export_constructs.md @@ -0,0 +1,15 @@ +# `export_construct!` / `export_constructs!` + +`export_construct!` and `export_constructs!` declare the hygienic markers that let generated code refer to CGP library items by a short name that always expands to a fully-qualified path. Every CGP item the macros emit — `IsProviderFor`, `DelegateComponent`, `UseField`, `HasField`, and the rest — is represented in the codegen by a zero-sized marker struct whose `ToTokens` emits `::cgp::macro_prelude::`, so a user only needs `cgp` in scope for the expansion to resolve. + +`export_construct!(Name)` declares `pub struct Name;` and an impl of `quote::ToTokens` that emits `::cgp::macro_prelude::Name`. The two-argument form `export_construct!(From => To)` emits a different target path than the marker's own name, for the case where the codegen name and the exported item name differ. `export_constructs!` is the plural convenience wrapper: it takes a comma-separated list of `Name` or `From => To` entries and expands each through `export_construct!`, which is how [`exports.rs`](../../../crates/macros/cgp-macro-core/src/exports.rs) declares the whole set in one block. + +The point of the indirection is hygiene. Generated code interpolates the marker (`#is_provider_for`) rather than a literal `::cgp::...` path, so the emitted tokens carry the fully-qualified path without the macro author writing it out and without depending on what the user has imported. To emit a new CGP item from a macro, add it to the `export_constructs!` list in `exports.rs` and interpolate its marker; do not write `::cgp::...` path literals inline. + +## Tests + +These macros have no dedicated test; they are exercised by every expansion snapshot in the suite, since the fully-qualified paths in generated code all originate from these markers. + +## Source + +The macros are defined in [cgp-macro-core/src/macros/export.rs](../../../crates/macros/cgp-macro-core/src/macros/export.rs); the marker set they generate lives in [cgp-macro-core/src/exports.rs](../../../crates/macros/cgp-macro-core/src/exports.rs), and the `::cgp::macro_prelude` re-export surface is what makes the emitted paths resolve. The convention that all CGP items are referenced through these markers is recorded in [cgp-macro-core/CLAUDE.md](../../../crates/macros/cgp-macro-core/CLAUDE.md). diff --git a/docs/reference/attributes/derive_delegate.md b/docs/reference/attributes/derive_delegate.md index 34ddbb20..1b527e24 100644 --- a/docs/reference/attributes/derive_delegate.md +++ b/docs/reference/attributes/derive_delegate.md @@ -148,3 +148,5 @@ Now `MyApp` implements `CanCalculateArea` through `RectangleArea` and ## Source The attribute is parsed by `DeriveDelegateAttribute::parse` in [crates/macros/cgp-macro-core/src/types/attributes/derive_delegate/attribute.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/derive_delegate/attribute.rs), which reads the wrapper identifier and the angle-bracketed key (a single identifier or a parenthesized tuple). The dispatcher impl is built by the same file's `to_provider_impl`, which appends `__Components__` and `__Delegate__` generics, emits the `DelegateComponent<(params), Delegate = __Delegate__>` and `__Delegate__: ProviderTrait` bounds, and forwards each method through `trait_items_to_delegated_impl_items`. The attribute is collected in `types/attributes/cgp_component_attributes.rs` and emitted by `to_use_delegate_impls` in [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/item.rs). The `UseDelegate` provider and a worked single-key expansion are documented in [crates/core/cgp-component/src/providers/use_delegate.rs](../../../crates/core/cgp-component/src/providers/use_delegate.rs); the multi-attribute form with a custom `UseInputDelegate` is used in [crates/extra/cgp-handler/src/components/computer.rs](../../../crates/extra/cgp-handler/src/components/computer.rs). + +For the dispatcher impl it generates and the index of tests and snapshots, see the implementation document [implementation/asts/attributes.md](../../implementation/asts/attributes.md). diff --git a/docs/reference/attributes/extend.md b/docs/reference/attributes/extend.md index c4eca859..3b2e0d15 100644 --- a/docs/reference/attributes/extend.md +++ b/docs/reference/attributes/extend.md @@ -121,4 +121,6 @@ Because `HasScalarType` is a supertrait of `RectangleArea`, the abstract `Self:: ## Source -`#[extend(...)]` is parsed in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs) (the `extend` field of `FunctionAttributes`). For `#[cgp_fn]`, the bounds are added to the trait's supertraits and to the impl `where` clause in [crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs). For `#[cgp_component]`, the attribute is parsed by `CgpComponentAttributes::parse` and its bounds appended to the consumer trait's supertraits in [crates/macros/cgp-macro-core/src/types/attributes/cgp_component_attributes.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/cgp_component_attributes.rs). Expansion snapshots are in [crates/tests/cgp-tests/tests/impl_side_dependencies/fn_extend.rs](../../../crates/tests/cgp-tests/tests/impl_side_dependencies/fn_extend.rs) and the component abstract-type tests in [crates/tests/cgp-tests/tests/abstract_types/](../../../crates/tests/cgp-tests/tests/abstract_types/). +`#[extend(...)]` is parsed in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs) (the `extend` field of `FunctionAttributes`). For `#[cgp_fn]`, the bounds are added to the trait's supertraits and to the impl `where` clause in [crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs). For `#[cgp_component]`, the attribute is parsed by `CgpComponentAttributes::parse` and its bounds appended to the consumer trait's supertraits in [crates/macros/cgp-macro-core/src/types/attributes/cgp_component_attributes.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/cgp_component_attributes.rs). + +For what the attribute injects into each host and the index of tests and snapshots, see the implementation document [implementation/asts/attributes.md](../../implementation/asts/attributes.md). diff --git a/docs/reference/attributes/extend_where.md b/docs/reference/attributes/extend_where.md index 56ad44d3..468fac9e 100644 --- a/docs/reference/attributes/extend_where.md +++ b/docs/reference/attributes/extend_where.md @@ -62,4 +62,6 @@ The `Scalar: Mul` bound, written in the function body, stays as ## Source -`#[extend_where(...)]` is parsed in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs) (the `extend_where` field of `FunctionAttributes`), and its predicates are added to both the trait and impl `where` clauses in [crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs). An expansion snapshot that exercises `#[extend_where(...)]` alongside `#[use_type]` lives in [crates/tests/cgp-tests/tests/abstract_types/use_type_fn_nested_foreign.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_nested_foreign.rs), among the other `#[use_type]` `#[cgp_fn]` tests in [crates/tests/cgp-tests/tests/abstract_types/](../../../crates/tests/cgp-tests/tests/abstract_types/). +`#[extend_where(...)]` is parsed in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs) (the `extend_where` field of `FunctionAttributes`), and its predicates are added to both the trait and impl `where` clauses in [crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs). + +For what the attribute injects into its host and the index of tests and snapshots, see the implementation document [implementation/asts/attributes.md](../../implementation/asts/attributes.md). diff --git a/docs/reference/attributes/implicit.md b/docs/reference/attributes/implicit.md index f6ec59d0..f1b00f41 100644 --- a/docs/reference/attributes/implicit.md +++ b/docs/reference/attributes/implicit.md @@ -115,4 +115,6 @@ fn print_area(rect: &Rectangle) { ## Source -Implicit-argument parsing lives in [crates/macros/cgp-macro-core/src/functions/implicits/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/implicits/parse.rs), which extracts `#[implicit]`-marked arguments and validates the `self`/`mut` rules. The per-argument model is in [crates/macros/cgp-macro-core/src/types/implicits/](../../../crates/macros/cgp-macro-core/src/types/implicits/): `arg_field.rs` builds the `HasField` bound and the `let` binding, and `arg_fields.rs` adds the bounds to the impl generics and prepends the bindings to the body. The field-type-to-access-mode mapping (`.clone()`, `.as_str()`, and the reference/option/slice cases) is in [crates/macros/cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs) and [crates/macros/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs](../../../crates/macros/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs). Expansion snapshots are in [crates/tests/cgp-tests/tests/implicit_arguments/](../../../crates/tests/cgp-tests/tests/implicit_arguments/), covering both the `#[cgp_fn]` form (`cgp_fn_greet.rs`) and the `#[cgp_impl]` form (`cgp_impl_implicit.rs`). +Implicit-argument parsing lives in [crates/macros/cgp-macro-core/src/functions/implicits/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/implicits/parse.rs), which extracts `#[implicit]`-marked arguments and validates the `self`/`mut` rules. The per-argument model is in [crates/macros/cgp-macro-core/src/types/implicits/](../../../crates/macros/cgp-macro-core/src/types/implicits/): `arg_field.rs` builds the `HasField` bound and the `let` binding, and `arg_fields.rs` adds the bounds to the impl generics and prepends the bindings to the body. The field-type-to-access-mode mapping (`.clone()`, `.as_str()`, and the reference/option/slice cases) is in [crates/macros/cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs) and [crates/macros/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs](../../../crates/macros/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs). + +For how `#[implicit]` arguments are parsed and lowered into `HasField` bounds and `let` bindings, and the index of tests, see the implementation document [implementation/entrypoints/cgp_fn.md](../../implementation/entrypoints/cgp_fn.md). diff --git a/docs/reference/attributes/use_provider.md b/docs/reference/attributes/use_provider.md index 3bcd4b93..0452f7a6 100644 --- a/docs/reference/attributes/use_provider.md +++ b/docs/reference/attributes/use_provider.md @@ -127,4 +127,6 @@ A context can now wire `AreaCalculatorComponent` to `ScaledArea`, ## Source -The outer form is parsed by `UseProviderAttribute` in [crates/macros/cgp-macro-core/src/types/attributes/use_provider/attribute.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/use_provider/attribute.rs); its `to_type_param_bounds` inserts the context type at index 0 of the trait's generic arguments, and `to_provider_bounds` builds the `where` predicate. The bounds are appended to the impl by `add_type_param_bounds` in `attributes.rs`. The attribute is collected for `#[cgp_impl]` in `types/attributes/cgp_impl_attributes.rs` and for `#[cgp_fn]` in `types/attributes/function.rs`, and applied in `types/cgp_impl/item.rs` and `types/cgp_fn/preprocessed.rs`. The expansion snapshot for the `#[cgp_fn]` outer form is in [crates/tests/cgp-tests/tests/higher_order_providers/use_provider_fn.rs](../../../crates/tests/cgp-tests/tests/higher_order_providers/use_provider_fn.rs); `#[cgp_impl]` usage is exercised in [crates/tests/cgp-tests/tests/higher_order_providers/use_provider_impl.rs](../../../crates/tests/cgp-tests/tests/higher_order_providers/use_provider_impl.rs). +The outer form is parsed by `UseProviderAttribute` in [crates/macros/cgp-macro-core/src/types/attributes/use_provider/attribute.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/use_provider/attribute.rs); its `to_type_param_bounds` inserts the context type at index 0 of the trait's generic arguments, and `to_provider_bounds` builds the `where` predicate. The bounds are appended to the impl by `add_type_param_bounds` in `attributes.rs`. The attribute is collected for `#[cgp_impl]` in `types/attributes/cgp_impl_attributes.rs` and for `#[cgp_fn]` in `types/attributes/function.rs`, and applied in `types/cgp_impl/item.rs` and `types/cgp_fn/preprocessed.rs`. + +For the internal AST type, the bound completion, and the index of tests and snapshots, see the implementation document [implementation/asts/attributes.md](../../implementation/asts/attributes.md). diff --git a/docs/reference/attributes/use_type.md b/docs/reference/attributes/use_type.md index cd083f96..909ef853 100644 --- a/docs/reference/attributes/use_type.md +++ b/docs/reference/attributes/use_type.md @@ -178,4 +178,6 @@ The provider's `#[use_type]` adds `Self: HasScalarType` to its `where` clause an ## Source -The attribute is parsed by `UseTypeAttribute` in [crates/macros/cgp-macro-core/src/types/attributes/use_type/attribute.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/use_type/attribute.rs), with per-type entries (`as` alias and `=` equality) in `ident.rs`. The two-phase transform — substitute then add bounds — lives in `attributes.rs` as `transform_item_trait` (supertrait for `#[cgp_component]`) and `transform_item_impl` (`where` bound for impls), and the type-equality and foreign-context resolution are in `type_predicates.rs`. The identifier substitution itself is the `SubstituteAbstractType` `VisitMut` pass in [crates/macros/cgp-macro-core/src/visitors/substitute_abstract_type.rs](../../../crates/macros/cgp-macro-core/src/visitors/substitute_abstract_type.rs), which matches single-segment, argument-free type paths. The `= ...` rejection for component traits is enforced in `types/attributes/cgp_component_attributes.rs`. Expansion snapshots covering the single, foreign (`@`), alias, equality, and cross-spec equality forms are in [crates/tests/cgp-tests/tests/abstract_types/use_type_fn_equality.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_equality.rs) and [use_type_fn_foreign.rs](../../../crates/tests/cgp-tests/tests/abstract_types/use_type_fn_foreign.rs). +The attribute is parsed by `UseTypeAttribute` in [crates/macros/cgp-macro-core/src/types/attributes/use_type/attribute.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/use_type/attribute.rs), with per-type entries (`as` alias and `=` equality) in `ident.rs`. The two-phase transform — substitute then add bounds — lives in `attributes.rs` as `transform_item_trait` (supertrait for `#[cgp_component]`) and `transform_item_impl` (`where` bound for impls), and the type-equality and foreign-context resolution are in `type_predicates.rs`. The identifier substitution itself is the `SubstituteAbstractType` `VisitMut` pass in [crates/macros/cgp-macro-core/src/visitors/substitute_abstract_type.rs](../../../crates/macros/cgp-macro-core/src/visitors/substitute_abstract_type.rs), which matches single-segment, argument-free type paths. The `= ...` rejection for component traits is enforced in `types/attributes/cgp_component_attributes.rs`. + +For the internal AST types, the two-phase transform, and the index of tests and snapshots, see the implementation document [implementation/asts/attributes.md](../../implementation/asts/attributes.md). diff --git a/docs/reference/attributes/uses.md b/docs/reference/attributes/uses.md index 37d385d0..e9ca3074 100644 --- a/docs/reference/attributes/uses.md +++ b/docs/reference/attributes/uses.md @@ -105,4 +105,6 @@ The `#[uses(CanCalculateArea)]` attribute adds `Self: CanCalculateArea` to the g ## Source -`#[uses(...)]` parsing lives in [crates/macros/cgp-macro-core/src/types/attributes/uses.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/uses.rs) (the `UsesAttributes` type and its `to_type_param_bounds`), with the attribute dispatch in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs) for `#[cgp_fn]` and [crates/macros/cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs) for `#[cgp_impl]`. The bounds are added to the impl `where` clause in [crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs). Expansion snapshots are in [crates/tests/cgp-tests/tests/impl_side_dependencies/fn_uses.rs](../../../crates/tests/cgp-tests/tests/impl_side_dependencies/fn_uses.rs) and [crates/tests/cgp-tests/tests/impl_side_dependencies/impl_uses.rs](../../../crates/tests/cgp-tests/tests/impl_side_dependencies/impl_uses.rs). +`#[uses(...)]` parsing lives in [crates/macros/cgp-macro-core/src/types/attributes/uses.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/uses.rs) (the `UsesAttributes` type and its `to_type_param_bounds`), with the attribute dispatch in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs) for `#[cgp_fn]` and [crates/macros/cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs) for `#[cgp_impl]`. The bounds are added to the impl `where` clause in [crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs). + +For the internal AST type, what the attribute injects into each host, and the index of tests and snapshots, see the implementation document [implementation/asts/attributes.md](../../implementation/asts/attributes.md). diff --git a/docs/reference/components/can_raise_error.md b/docs/reference/components/can_raise_error.md index bcfaf0f1..f96417c2 100644 --- a/docs/reference/components/can_raise_error.md +++ b/docs/reference/components/can_raise_error.md @@ -79,4 +79,4 @@ The provider names neither the context nor its concrete error type. It requires ## Source -`CanRaiseError` is defined in [crates/core/cgp-error/src/traits/can_raise_error.rs](../../../crates/core/cgp-error/src/traits/can_raise_error.rs) and `CanWrapError` in [crates/core/cgp-error/src/traits/can_wrap_error.rs](../../../crates/core/cgp-error/src/traits/can_wrap_error.rs). Both build on `HasErrorType` from [crates/core/cgp-error/src/traits/has_error_type.rs](../../../crates/core/cgp-error/src/traits/has_error_type.rs). The pluggable providers that implement them live in [crates/standalone/error/](../../../crates/standalone/error/). Behavioral tests are in [crates/tests/cgp-tests](../../../crates/tests/cgp-tests). +`CanRaiseError` is defined in [crates/core/cgp-error/src/traits/can_raise_error.rs](../../../crates/core/cgp-error/src/traits/can_raise_error.rs) and `CanWrapError` in [crates/core/cgp-error/src/traits/can_wrap_error.rs](../../../crates/core/cgp-error/src/traits/can_wrap_error.rs). Both build on `HasErrorType` from [crates/core/cgp-error/src/traits/has_error_type.rs](../../../crates/core/cgp-error/src/traits/has_error_type.rs). The pluggable providers that implement them live in [crates/standalone/error/](../../../crates/standalone/error/). diff --git a/docs/reference/components/computer.md b/docs/reference/components/computer.md index 72aa3af7..621d6054 100644 --- a/docs/reference/components/computer.md +++ b/docs/reference/components/computer.md @@ -106,4 +106,4 @@ The computer components are the infallible corner of the [handler family](../../ ## Source -The synchronous computers `Computer`/`ComputerRef` are defined in [crates/extra/cgp-handler/src/components/computer.rs](../../../crates/extra/cgp-handler/src/components/computer.rs), and the async computers `AsyncComputer`/`AsyncComputerRef` in [crates/extra/cgp-handler/src/components/async_computer.rs](../../../crates/extra/cgp-handler/src/components/async_computer.rs). The `UseInputDelegate` dispatch type is in [crates/extra/cgp-handler/src/types.rs](../../../crates/extra/cgp-handler/src/types.rs). The components are re-exported through `cgp::extra::handler`. Behavioral tests exercising computers and their promotions are in [crates/tests/cgp-tests/tests/handlers/computer_macro.rs](../../../crates/tests/cgp-tests/tests/handlers/computer_macro.rs). +The synchronous computers `Computer`/`ComputerRef` are defined in [crates/extra/cgp-handler/src/components/computer.rs](../../../crates/extra/cgp-handler/src/components/computer.rs), and the async computers `AsyncComputer`/`AsyncComputerRef` in [crates/extra/cgp-handler/src/components/async_computer.rs](../../../crates/extra/cgp-handler/src/components/async_computer.rs). The `UseInputDelegate` dispatch type is in [crates/extra/cgp-handler/src/types.rs](../../../crates/extra/cgp-handler/src/types.rs). The components are re-exported through `cgp::extra::handler`. For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_computer](../../implementation/entrypoints/cgp_computer.md). diff --git a/docs/reference/components/handler.md b/docs/reference/components/handler.md index 8f9b1918..90fe2146 100644 --- a/docs/reference/components/handler.md +++ b/docs/reference/components/handler.md @@ -84,4 +84,4 @@ The function `run_with` works for any context that wires a handler for the given ## Source -`Handler` and `HandlerRef` are defined in [crates/extra/cgp-handler/src/components/handler.rs](../../../crates/extra/cgp-handler/src/components/handler.rs). The `ReturnInput` provider is in [crates/extra/cgp-handler/src/providers/return_input.rs](../../../crates/extra/cgp-handler/src/providers/return_input.rs), and the promotion combinators that lift simpler providers into `Handler` are in [crates/extra/cgp-handler/src/providers/](../../../crates/extra/cgp-handler/src/). The components are re-exported through `cgp::extra::handler`. Behavioral tests exercising handlers and their promotions are in [crates/tests/cgp-tests/tests/handlers/handler_macro.rs](../../../crates/tests/cgp-tests/tests/handlers/handler_macro.rs). +`Handler` and `HandlerRef` are defined in [crates/extra/cgp-handler/src/components/handler.rs](../../../crates/extra/cgp-handler/src/components/handler.rs). The `ReturnInput` provider is in [crates/extra/cgp-handler/src/providers/return_input.rs](../../../crates/extra/cgp-handler/src/providers/return_input.rs), and the promotion combinators that lift simpler providers into `Handler` are in [crates/extra/cgp-handler/src/providers/](../../../crates/extra/cgp-handler/src/). The components are re-exported through `cgp::extra::handler`. diff --git a/docs/reference/components/has_error_type.md b/docs/reference/components/has_error_type.md index 043404c1..549560da 100644 --- a/docs/reference/components/has_error_type.md +++ b/docs/reference/components/has_error_type.md @@ -70,4 +70,4 @@ This direct form makes plain that `HasErrorType` is an ordinary trait with a `De ## Source -The trait and the `ErrorOf` alias are defined in [crates/core/cgp-error/src/traits/has_error_type.rs](../../../crates/core/cgp-error/src/traits/has_error_type.rs). The `#[cgp_type]` machinery it relies on lives in [crates/macros/cgp-macro-core/src/types/cgp_type/](../../../crates/macros/cgp-macro-core/src/types/cgp_type/), and the underlying `HasType`/`TypeProvider`/`UseType` definitions are in [crates/core/cgp-type/src/](../../../crates/core/cgp-type/src/). The pluggable concrete error backends are in [crates/standalone/error/](../../../crates/standalone/error/). Behavioral tests are in [crates/tests/cgp-tests](../../../crates/tests/cgp-tests). +The trait and the `ErrorOf` alias are defined in [crates/core/cgp-error/src/traits/has_error_type.rs](../../../crates/core/cgp-error/src/traits/has_error_type.rs). The `#[cgp_type]` machinery it relies on lives in [crates/macros/cgp-macro-core/src/types/cgp_type/](../../../crates/macros/cgp-macro-core/src/types/cgp_type/), and the underlying `HasType`/`TypeProvider`/`UseType` definitions are in [crates/core/cgp-type/src/](../../../crates/core/cgp-type/src/). The pluggable concrete error backends are in [crates/standalone/error/](../../../crates/standalone/error/). diff --git a/docs/reference/components/has_type.md b/docs/reference/components/has_type.md index 5a00d4f8..4e98d75c 100644 --- a/docs/reference/components/has_type.md +++ b/docs/reference/components/has_type.md @@ -72,4 +72,4 @@ where ## Source -The trait, the `TypeProvider` provider trait, and the `TypeOf` alias are defined in [crates/core/cgp-type/src/traits/has_type.rs](../../../crates/core/cgp-type/src/traits/has_type.rs). The `UseType` provider and its `TypeProvider` impl are in [crates/core/cgp-type/src/impls/use_type.rs](../../../crates/core/cgp-type/src/impls/use_type.rs). The `#[cgp_type]` macro that builds named components on this substrate lives in [crates/macros/cgp-macro-core/src/types/cgp_type/](../../../crates/macros/cgp-macro-core/src/types/cgp_type/). Behavioral and expansion-snapshot tests are in [crates/tests/cgp-tests/tests/abstract_types/](../../../crates/tests/cgp-tests/tests/abstract_types/). +The trait, the `TypeProvider` provider trait, and the `TypeOf` alias are defined in [crates/core/cgp-type/src/traits/has_type.rs](../../../crates/core/cgp-type/src/traits/has_type.rs). The `UseType` provider and its `TypeProvider` impl are in [crates/core/cgp-type/src/impls/use_type.rs](../../../crates/core/cgp-type/src/impls/use_type.rs). The `#[cgp_type]` macro that builds named components on this substrate lives in [crates/macros/cgp-macro-core/src/types/cgp_type/](../../../crates/macros/cgp-macro-core/src/types/cgp_type/). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_type](../../implementation/entrypoints/cgp_type.md). diff --git a/docs/reference/components/producer.md b/docs/reference/components/producer.md index 4144b4fb..26f23112 100644 --- a/docs/reference/components/producer.md +++ b/docs/reference/components/producer.md @@ -80,4 +80,4 @@ Here `MagicNumber` produces `42` from the `Code` tag alone, and `App` delegates ## Source -`Producer` is defined in [crates/extra/cgp-handler/src/components/produce.rs](../../../crates/extra/cgp-handler/src/components/produce.rs). The `Promote` combinator that lifts it into a `Computer` is in [crates/extra/cgp-handler/src/providers/promote.rs](../../../crates/extra/cgp-handler/src/providers/promote.rs), and the `PromoteProducer` table in [crates/extra/cgp-handler/src/providers/promote_all.rs](../../../crates/extra/cgp-handler/src/providers/promote_all.rs). The component is re-exported through `cgp::extra::handler`. Behavioral tests exercising a producer and its promotions are in [crates/tests/cgp-tests/tests/handlers/producer_macro.rs](../../../crates/tests/cgp-tests/tests/handlers/producer_macro.rs). +`Producer` is defined in [crates/extra/cgp-handler/src/components/produce.rs](../../../crates/extra/cgp-handler/src/components/produce.rs). The `Promote` combinator that lifts it into a `Computer` is in [crates/extra/cgp-handler/src/providers/promote.rs](../../../crates/extra/cgp-handler/src/providers/promote.rs), and the `PromoteProducer` table in [crates/extra/cgp-handler/src/providers/promote_all.rs](../../../crates/extra/cgp-handler/src/providers/promote_all.rs). The component is re-exported through `cgp::extra::handler`. For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_producer](../../implementation/entrypoints/cgp_producer.md). diff --git a/docs/reference/components/runner.md b/docs/reference/components/runner.md index f121a184..962f8d68 100644 --- a/docs/reference/components/runner.md +++ b/docs/reference/components/runner.md @@ -103,4 +103,4 @@ The `Runner` family is most often paired with [`HasRuntime`](has_runtime.md): a ## Source -`CanRun` / `Runner` and `CanSendRun` / `SendRunner` are defined together in [crates/extra/cgp-run/src/lib.rs](../../../crates/extra/cgp-run/src/lib.rs), reached from the facade as `cgp::extra::run`. The `#[cgp_component]` and `#[derive_delegate]` expansions they rely on live under [crates/macros/cgp-macro-core/src/](../../../crates/macros/cgp-macro-core/src/). The end-to-end usage — a `UseDelegate` runner table, a `SpawnAndRun` provider, and a concrete `SendRunner` proxy that spawns a `Send` future — is exercised in [crates/tests/cgp-tests/tests/async_and_send/spawn.rs](../../../crates/tests/cgp-tests/tests/async_and_send/spawn.rs). +`CanRun` / `Runner` and `CanSendRun` / `SendRunner` are defined together in [crates/extra/cgp-run/src/lib.rs](../../../crates/extra/cgp-run/src/lib.rs), reached from the facade as `cgp::extra::run`. The `#[cgp_component]` and `#[derive_delegate]` expansions they rely on live under [crates/macros/cgp-macro-core/src/](../../../crates/macros/cgp-macro-core/src/). diff --git a/docs/reference/components/try_computer.md b/docs/reference/components/try_computer.md index 61e89933..ede928a1 100644 --- a/docs/reference/components/try_computer.md +++ b/docs/reference/components/try_computer.md @@ -94,4 +94,4 @@ The provider `ParseU64` returns its `u64` output or the context's abstract error ## Source -`TryComputer` and `TryComputerRef` are defined in [crates/extra/cgp-handler/src/components/try_compute.rs](../../../crates/extra/cgp-handler/src/components/try_compute.rs). The `ReturnInput` provider is in [crates/extra/cgp-handler/src/providers/return_input.rs](../../../crates/extra/cgp-handler/src/providers/return_input.rs), and the promotion combinators in [crates/extra/cgp-handler/src/providers/](../../../crates/extra/cgp-handler/src/). The components are re-exported through `cgp::extra::handler`. Behavioral tests exercising the fallible computers and their promotions are in [crates/tests/cgp-tests/tests/handlers/computer_macro.rs](../../../crates/tests/cgp-tests/tests/handlers/computer_macro.rs). +`TryComputer` and `TryComputerRef` are defined in [crates/extra/cgp-handler/src/components/try_compute.rs](../../../crates/extra/cgp-handler/src/components/try_compute.rs). The `ReturnInput` provider is in [crates/extra/cgp-handler/src/providers/return_input.rs](../../../crates/extra/cgp-handler/src/providers/return_input.rs), and the promotion combinators in [crates/extra/cgp-handler/src/providers/](../../../crates/extra/cgp-handler/src/). The components are re-exported through `cgp::extra::handler`. For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_computer](../../implementation/entrypoints/cgp_computer.md). diff --git a/docs/reference/derives/derive_build_field.md b/docs/reference/derives/derive_build_field.md index c80f673f..50f2602c 100644 --- a/docs/reference/derives/derive_build_field.md +++ b/docs/reference/derives/derive_build_field.md @@ -129,4 +129,6 @@ Each step changes the partial type, and only after the last field is set does th ## Source -The derive entry point is `derive_build_field` in [crates/macros/cgp-macro-lib/src/derive_build_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_build_field.rs), which builds an `ItemCgpRecord` and calls `to_build_field_items()`. That method, in [crates/macros/cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), composes the helpers in the [`derive_builder/`](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/) submodule (`builder_struct.rs`, `has_builder_impl.rs`, `into_builder_impl.rs`, `partial_data.rs`, `finalize_build_impl.rs`, `update_field_impls.rs`, `has_field_impls.rs`). The `BuildField` and `FinalizeBuild` traits are in [crates/core/cgp-field/src/traits/build_field.rs](../../../crates/core/cgp-field/src/traits/build_field.rs), `UpdateField` in `update_field.rs`, `HasBuilder`/`IntoBuilder` in `has_builder.rs`, `PartialData` in `partial_data.rs`, and the `MapType` markers in `crates/core/cgp-field/src/impls/map_type.rs`. Tests are in [crates/tests/cgp-tests/tests/extensible_records/](../../../crates/tests/cgp-tests/tests/extensible_records/). +The derive entry point is `derive_build_field` in [crates/macros/cgp-macro-lib/src/derive_build_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_build_field.rs), which builds an `ItemCgpRecord` and calls `to_build_field_items()`. That method, in [crates/macros/cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), composes the helpers in the [`derive_builder/`](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/) submodule (`builder_struct.rs`, `has_builder_impl.rs`, `into_builder_impl.rs`, `partial_data.rs`, `finalize_build_impl.rs`, `update_field_impls.rs`, `has_field_impls.rs`). The `BuildField` and `FinalizeBuild` traits are in [crates/core/cgp-field/src/traits/build_field.rs](../../../crates/core/cgp-field/src/traits/build_field.rs), `UpdateField` in `update_field.rs`, `HasBuilder`/`IntoBuilder` in `has_builder.rs`, `PartialData` in `partial_data.rs`, and the `MapType` markers in `crates/core/cgp-field/src/impls/map_type.rs`. + +For the full internal walkthrough — the builder helpers, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_build_field.md](../../implementation/entrypoints/derive_build_field.md). diff --git a/docs/reference/derives/derive_cgp_data.md b/docs/reference/derives/derive_cgp_data.md index 10c67d27..094b26a5 100644 --- a/docs/reference/derives/derive_cgp_data.md +++ b/docs/reference/derives/derive_cgp_data.md @@ -197,4 +197,6 @@ These two views are what higher-level constructs build on: builders and field-di ## Source -The derive entry point is `derive_cgp_data` in [crates/macros/cgp-macro-lib/src/cgp_data.rs](../../../crates/macros/cgp-macro-lib/src/cgp_data.rs), which parses the input into `ItemCgpData` and calls `to_items()`. The dispatch on struct vs. enum is in [crates/macros/cgp-macro-core/src/types/cgp_data/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/item.rs); the record path is in `record.rs` and the variant path in `variant.rs` in the same directory, which delegate to the `derive_has_fields/`, `derive_builder/`, `derive_extractor/`, and `derive_from_variant.rs` submodules. The runtime traits are in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/) and the `MapType` markers in `crates/core/cgp-field/src/impls/map_type.rs`. Expansion snapshots and behavioral tests live in [crates/tests/cgp-tests/tests/extensible_records/](../../../crates/tests/cgp-tests/tests/extensible_records/) and [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/). +The derive entry point is `derive_cgp_data` in [crates/macros/cgp-macro-lib/src/cgp_data.rs](../../../crates/macros/cgp-macro-lib/src/cgp_data.rs), which parses the input into `ItemCgpData` and calls `to_items()`. The dispatch on struct vs. enum is in [crates/macros/cgp-macro-core/src/types/cgp_data/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/item.rs); the record path is in `record.rs` and the variant path in `variant.rs` in the same directory, which delegate to the `derive_has_fields/`, `derive_builder/`, `derive_extractor/`, and `derive_from_variant.rs` submodules. The runtime traits are in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/) and the `MapType` markers in `crates/core/cgp-field/src/impls/map_type.rs`. + +For the full internal walkthrough — the shape dispatch, the record and variant codegen it composes, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_cgp_data.md](../../implementation/entrypoints/derive_cgp_data.md). diff --git a/docs/reference/derives/derive_cgp_record.md b/docs/reference/derives/derive_cgp_record.md index ab8e826c..8319865c 100644 --- a/docs/reference/derives/derive_cgp_record.md +++ b/docs/reference/derives/derive_cgp_record.md @@ -134,4 +134,6 @@ If a field were left unset before `finalize_build`, the call would not compile ## Source -The derive entry point is `derive_cgp_record` in [crates/macros/cgp-macro-lib/src/cgp_record.rs](../../../crates/macros/cgp-macro-lib/src/cgp_record.rs), which parses an `ItemCgpRecord` and calls `to_items()`. The record codegen is in [crates/macros/cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), which composes `derive_has_field_impls_from_struct`, `derive_has_fields_impls_from_struct`, and the builder helpers in the `derive_builder/` submodule. The runtime traits (`HasBuilder`, `IntoBuilder`, `PartialData`, `FinalizeBuild`, `UpdateField`, `BuildField`, `HasFields`, `FromFields`, `ToFields`) live in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). Expansion snapshots and behavioral tests are in [crates/tests/cgp-tests/tests/extensible_records/](../../../crates/tests/cgp-tests/tests/extensible_records/). +The derive entry point is `derive_cgp_record` in [crates/macros/cgp-macro-lib/src/cgp_record.rs](../../../crates/macros/cgp-macro-lib/src/cgp_record.rs), which parses an `ItemCgpRecord` and calls `to_items()`. The record codegen is in [crates/macros/cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), which composes `derive_has_field_impls_from_struct`, `derive_has_fields_impls_from_struct`, and the builder helpers in the `derive_builder/` submodule. The runtime traits (`HasBuilder`, `IntoBuilder`, `PartialData`, `FinalizeBuild`, `UpdateField`, `BuildField`, `HasFields`, `FromFields`, `ToFields`) live in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). + +For the full internal walkthrough — the codegen it composes, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_cgp_record.md](../../implementation/entrypoints/derive_cgp_record.md). diff --git a/docs/reference/derives/derive_cgp_variant.md b/docs/reference/derives/derive_cgp_variant.md index cf1626ed..4be59141 100644 --- a/docs/reference/derives/derive_cgp_variant.md +++ b/docs/reference/derives/derive_cgp_variant.md @@ -120,4 +120,6 @@ Because each `extract_field` narrows the remainder type, the compiler knows afte ## Source -The derive entry point is `derive_cgp_variant` in [crates/macros/cgp-macro-lib/src/cgp_variant.rs](../../../crates/macros/cgp-macro-lib/src/cgp_variant.rs), which parses an `ItemCgpVariant` and calls `to_items()`. The variant codegen is in [crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which composes `derive_has_fields_impls_from_enum`, `derive_from_variant_from_enum`, and the extractor helpers in the `derive_extractor/` submodule. The runtime traits (`HasExtractor`, `HasExtractorRef`, `HasExtractorMut`, `ExtractField`, `FinalizeExtract`, `FromVariant`, `HasFields`, `FromFields`, `ToFields`) live in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). Expansion snapshots and behavioral tests are in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/). +The derive entry point is `derive_cgp_variant` in [crates/macros/cgp-macro-lib/src/cgp_variant.rs](../../../crates/macros/cgp-macro-lib/src/cgp_variant.rs), which parses an `ItemCgpVariant` and calls `to_items()`. The variant codegen is in [crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which composes `derive_has_fields_impls_from_enum`, `derive_from_variant_from_enum`, and the extractor helpers in the `derive_extractor/` submodule. The runtime traits (`HasExtractor`, `HasExtractorRef`, `HasExtractorMut`, `ExtractField`, `FinalizeExtract`, `FromVariant`, `HasFields`, `FromFields`, `ToFields`) live in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). + +For the full internal walkthrough — the codegen it composes, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_cgp_variant.md](../../implementation/entrypoints/derive_cgp_variant.md). diff --git a/docs/reference/derives/derive_extract_field.md b/docs/reference/derives/derive_extract_field.md index 490db8c8..3782b199 100644 --- a/docs/reference/derives/derive_extract_field.md +++ b/docs/reference/derives/derive_extract_field.md @@ -146,4 +146,6 @@ The derive only accepts enums whose every variant is a single-field tuple varian ## Source -The derive entry point is `derive_extract_field` in [crates/macros/cgp-macro-lib/src/derive_extract_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_extract_field.rs), which builds an `ItemCgpVariant` and calls `to_extract_field_items()`. That method, in [crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), composes the helpers in the [`derive_extractor/`](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/) submodule (`extractor_enum.rs`, `has_extractor_impl.rs`, `partial_data.rs`, `finalize_extract_impl.rs`, `extract_field_impls.rs`). The `ExtractField`, `HasExtractor`/`HasExtractorRef`/`HasExtractorMut`, `FinalizeExtract`, and `FinalizeExtractResult` traits are in [crates/core/cgp-field/src/traits/extract_field.rs](../../../crates/core/cgp-field/src/traits/extract_field.rs), `PartialData` in `partial_data.rs`, and the `MapType`/`MapTypeRef` markers in `crates/core/cgp-field/src/impls/`. Tests are in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/). +The derive entry point is `derive_extract_field` in [crates/macros/cgp-macro-lib/src/derive_extract_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_extract_field.rs), which builds an `ItemCgpVariant` and calls `to_extract_field_items()`. That method, in [crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), composes the helpers in the [`derive_extractor/`](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/) submodule (`extractor_enum.rs`, `has_extractor_impl.rs`, `partial_data.rs`, `finalize_extract_impl.rs`, `extract_field_impls.rs`). The `ExtractField`, `HasExtractor`/`HasExtractorRef`/`HasExtractorMut`, `FinalizeExtract`, and `FinalizeExtractResult` traits are in [crates/core/cgp-field/src/traits/extract_field.rs](../../../crates/core/cgp-field/src/traits/extract_field.rs), `PartialData` in `partial_data.rs`, and the `MapType`/`MapTypeRef` markers in `crates/core/cgp-field/src/impls/`. + +For the full internal walkthrough — the extractor helpers, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_extract_field.md](../../implementation/entrypoints/derive_extract_field.md). diff --git a/docs/reference/derives/derive_from_variant.md b/docs/reference/derives/derive_from_variant.md index 2fe52c6c..7902d564 100644 --- a/docs/reference/derives/derive_from_variant.md +++ b/docs/reference/derives/derive_from_variant.md @@ -86,4 +86,6 @@ The derive only accepts enums whose every variant is a single-field tuple varian ## Source -The derive entry point is `derive_from_variant` in [crates/macros/cgp-macro-lib/src/derive_from_variant.rs](../../../crates/macros/cgp-macro-lib/src/derive_from_variant.rs), which builds an `ItemCgpVariant` and calls `to_from_variant_impls()`. That method, in [crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), delegates to `derive_from_variant_from_enum` in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs). The `FromVariant` trait is in [crates/core/cgp-field/src/traits/from_variant.rs](../../../crates/core/cgp-field/src/traits/from_variant.rs). Tests are in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/). +The derive entry point is `derive_from_variant` in [crates/macros/cgp-macro-lib/src/derive_from_variant.rs](../../../crates/macros/cgp-macro-lib/src/derive_from_variant.rs), which builds an `ItemCgpVariant` and calls `to_from_variant_impls()`. That method, in [crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), delegates to `derive_from_variant_from_enum` in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs). The `FromVariant` trait is in [crates/core/cgp-field/src/traits/from_variant.rs](../../../crates/core/cgp-field/src/traits/from_variant.rs). + +For the full internal walkthrough — the per-variant codegen, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_from_variant.md](../../implementation/entrypoints/derive_from_variant.md). diff --git a/docs/reference/derives/derive_has_field.md b/docs/reference/derives/derive_has_field.md index 80302756..404a0df3 100644 --- a/docs/reference/derives/derive_has_field.md +++ b/docs/reference/derives/derive_has_field.md @@ -173,4 +173,6 @@ In practice the explicit `HasField` bound is rarely written by hand. The same `n ## Source -The derive entry point is `derive_has_field` in [crates/macros/cgp-macro-lib/src/derive_has_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_field.rs), registered as the `HasField` proc-macro derive in [crates/macros/cgp-macro/src/lib.rs](../../../crates/macros/cgp-macro/src/lib.rs). It parses the input as a `syn::ItemStruct`, wraps it in an `ItemCgpRecord` ([crates/macros/cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs)), and calls `to_has_field_impls`, whose codegen lives in `derive_has_field_impls_from_struct` in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_field.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_field.rs) — this is where named fields are mapped to `Symbol` tags and unnamed fields to `Index` tags, and where both the `HasField` and `HasFieldMut` impls are emitted. The traits themselves are defined in [crates/core/cgp-field/src/traits/has_field.rs](../../../crates/core/cgp-field/src/traits/has_field.rs) and [crates/core/cgp-field/src/traits/has_field_mut.rs](../../../crates/core/cgp-field/src/traits/has_field_mut.rs). Expansion snapshots are in [crates/tests/cgp-macro-tests](../../../crates/tests/cgp-macro-tests). +The derive entry point is `derive_has_field` in [crates/macros/cgp-macro-lib/src/derive_has_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_field.rs), registered as the `HasField` proc-macro derive in [crates/macros/cgp-macro/src/lib.rs](../../../crates/macros/cgp-macro/src/lib.rs). It parses the input as a `syn::ItemStruct`, wraps it in an `ItemCgpRecord` ([crates/macros/cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs)), and calls `to_has_field_impls`, whose codegen lives in `derive_has_field_impls_from_struct` in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_field.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_field.rs) — this is where named fields are mapped to `Symbol` tags and unnamed fields to `Index` tags, and where both the `HasField` and `HasFieldMut` impls are emitted. The traits themselves are defined in [crates/core/cgp-field/src/traits/has_field.rs](../../../crates/core/cgp-field/src/traits/has_field.rs) and [crates/core/cgp-field/src/traits/has_field_mut.rs](../../../crates/core/cgp-field/src/traits/has_field_mut.rs). + +For the full internal walkthrough — the codegen helper that synthesizes each impl, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_has_field.md](../../implementation/entrypoints/derive_has_field.md). diff --git a/docs/reference/derives/derive_has_fields.md b/docs/reference/derives/derive_has_fields.md index 606f699e..fb189579 100644 --- a/docs/reference/derives/derive_has_fields.md +++ b/docs/reference/derives/derive_has_fields.md @@ -149,4 +149,6 @@ Generic algorithms key off the `Fields` type rather than the concrete struct. Th ## Source -The derive entry point is `derive_has_fields` in [crates/macros/cgp-macro-lib/src/derive_has_fields.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_fields.rs), registered as the `HasFields` proc-macro derive in [crates/macros/cgp-macro/src/lib.rs](../../../crates/macros/cgp-macro/src/lib.rs). It dispatches on the parsed item: structs go through `ItemCgpRecord::to_has_fields_impls` → `derive_has_fields_impls_from_struct`, and enums through `derive_has_fields_impls_from_enum`, both in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/). Within that module, `product.rs` (`item_fields_to_product_type`) builds the struct `Fields` product, `sum.rs` (`variants_to_sum_type`) builds the enum `Fields` sum, and `from_fields_*`, `to_fields_*`, and `to_fields_ref_*` build the conversion impls. The traits are defined in [crates/core/cgp-field/src/traits/has_fields.rs](../../../crates/core/cgp-field/src/traits/has_fields.rs), [crates/core/cgp-field/src/traits/to_fields.rs](../../../crates/core/cgp-field/src/traits/to_fields.rs), and [crates/core/cgp-field/src/traits/from_fields.rs](../../../crates/core/cgp-field/src/traits/from_fields.rs); the `Field`, `Either`, and `Void` building blocks live under [crates/core/cgp-field/src/types/](../../../crates/core/cgp-field/src/types/). Expansion snapshots are in [crates/tests/cgp-macro-tests](../../../crates/tests/cgp-macro-tests). +The derive entry point is `derive_has_fields` in [crates/macros/cgp-macro-lib/src/derive_has_fields.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_fields.rs), registered as the `HasFields` proc-macro derive in [crates/macros/cgp-macro/src/lib.rs](../../../crates/macros/cgp-macro/src/lib.rs). It dispatches on the parsed item: structs go through `ItemCgpRecord::to_has_fields_impls` → `derive_has_fields_impls_from_struct`, and enums through `derive_has_fields_impls_from_enum`, both in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/). Within that module, `product.rs` (`item_fields_to_product_type`) builds the struct `Fields` product, `sum.rs` (`variants_to_sum_type`) builds the enum `Fields` sum, and `from_fields_*`, `to_fields_*`, and `to_fields_ref_*` build the conversion impls. The traits are defined in [crates/core/cgp-field/src/traits/has_fields.rs](../../../crates/core/cgp-field/src/traits/has_fields.rs), [crates/core/cgp-field/src/traits/to_fields.rs](../../../crates/core/cgp-field/src/traits/to_fields.rs), and [crates/core/cgp-field/src/traits/from_fields.rs](../../../crates/core/cgp-field/src/traits/from_fields.rs); the `Field`, `Either`, and `Void` building blocks live under [crates/core/cgp-field/src/types/](../../../crates/core/cgp-field/src/types/). + +For the full internal walkthrough — the codegen helpers that build the product and sum spines, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_has_fields.md](../../implementation/entrypoints/derive_has_fields.md). diff --git a/docs/reference/macros/async_trait.md b/docs/reference/macros/async_trait.md index 7cbac40a..a9b12b5a 100644 --- a/docs/reference/macros/async_trait.md +++ b/docs/reference/macros/async_trait.md @@ -135,5 +135,6 @@ The generated future carries no `Send` bound. Because the rewrite produces a bar ## Source -The macro entry point is `async_trait` in [crates/macros/cgp-async-macro/src/lib.rs](../../../crates/macros/cgp-async-macro/src/lib.rs), a `#[proc_macro_attribute]` that discards its attribute arguments and forwards the annotated item to `impl_async`. The rewrite lives in [crates/macros/cgp-async-macro/src/impl_async.rs](../../../crates/macros/cgp-async-macro/src/impl_async.rs): it parses the item as a `syn::ItemTrait`, and on success walks the trait's methods, replacing each `async` signature's output with `-> impl ::core::future::Future` and clearing the `async` keyword; if the item does not parse as a trait, it is returned unchanged. The macro is re-exported into the prelude from [crates/main/cgp-core/src/prelude.rs](../../../crates/main/cgp-core/src/prelude.rs), so `use cgp::prelude::*;` brings it into scope. Its interaction with `#[cgp_fn]` is exercised by the expansion snapshot in [crates/tests/cgp-tests/tests/async_and_send/cgp_fn_async.rs](../../../crates/tests/cgp-tests/tests/async_and_send/cgp_fn_async.rs), and async providers spawned onto a runtime appear in [crates/tests/cgp-tests/tests/async_and_send/spawn.rs](../../../crates/tests/cgp-tests/tests/async_and_send/spawn.rs). - +The macro entry point is `async_trait` in [crates/macros/cgp-async-macro/src/lib.rs](../../../crates/macros/cgp-async-macro/src/lib.rs), a `#[proc_macro_attribute]` that discards its attribute arguments and forwards the annotated item to `impl_async`. The rewrite lives in [crates/macros/cgp-async-macro/src/impl_async.rs](../../../crates/macros/cgp-async-macro/src/impl_async.rs): it parses the item as a `syn::ItemTrait`, and on success walks the trait's methods, replacing each `async` signature's output with `-> impl ::core::future::Future` and clearing the `async` keyword; if the item does not parse as a trait, it is returned unchanged. The macro is re-exported into the prelude from [crates/main/cgp-core/src/prelude.rs](../../../crates/main/cgp-core/src/prelude.rs), so `use cgp::prelude::*;` brings it into scope. + +For the internal walkthrough — the parse-or-passthrough structure, the signature rewrite, the default-body limitation, and the index of tests — see the implementation document [implementation/entrypoints/async_trait.md](../../implementation/entrypoints/async_trait.md). diff --git a/docs/reference/macros/blanket_trait.md b/docs/reference/macros/blanket_trait.md index e4c464c9..aedd6961 100644 --- a/docs/reference/macros/blanket_trait.md +++ b/docs/reference/macros/blanket_trait.md @@ -167,4 +167,6 @@ fn run(ctx: &Context) { ## Source -The macro entry point is `blanket_trait` in [crates/macros/cgp-macro-lib/src/blanket_trait.rs](../../../crates/macros/cgp-macro-lib/src/blanket_trait.rs), which parses the optional context identifier (defaulting to `__Context__` when the attribute argument is empty) and the trait, then runs `item.to_items()?`. The logic lives in [crates/macros/cgp-macro-core/src/types/blanket_trait.rs](../../../crates/macros/cgp-macro-core/src/types/blanket_trait.rs): `to_item_impl` walks the trait items, forwards each default method/const body and associated-type assignment into the impl, lifts associated types into impl generics, moves associated-type bounds into the `where` clause, and appends the trait's supertraits as the `__Context__: ...` predicate. The `Self`-to-parameter rewriting for associated types is done by `RemoveSelfPathVisitor` in [crates/macros/cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). Behavioral and expansion-snapshot tests are in [crates/tests/cgp-tests/tests/blanket_traits/](../../../crates/tests/cgp-tests/tests/blanket_traits/), covering the empty, method, and associated-type-with-and-without-bounds cases. +The macro entry point is `blanket_trait` in [crates/macros/cgp-macro-lib/src/blanket_trait.rs](../../../crates/macros/cgp-macro-lib/src/blanket_trait.rs), which parses the optional context identifier (defaulting to `__Context__` when the attribute argument is empty) and the trait, then runs `item.to_items()?`. The logic lives in [crates/macros/cgp-macro-core/src/types/blanket_trait.rs](../../../crates/macros/cgp-macro-core/src/types/blanket_trait.rs): `to_item_impl` walks the trait items, forwards each default method/const body and associated-type assignment into the impl, lifts associated types into impl generics, moves associated-type bounds into the `where` clause, and appends the trait's supertraits as the `__Context__: ...` predicate. The `Self`-to-parameter rewriting for associated types is done by `RemoveSelfPathVisitor` in [crates/macros/cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). + +For the full internal walkthrough — the codegen walk, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/blanket_trait.md](../../implementation/entrypoints/blanket_trait.md). diff --git a/docs/reference/macros/cgp_auto_dispatch.md b/docs/reference/macros/cgp_auto_dispatch.md index 5beaef74..88a00651 100644 --- a/docs/reference/macros/cgp_auto_dispatch.md +++ b/docs/reference/macros/cgp_auto_dispatch.md @@ -135,4 +135,6 @@ The macro rejects trait methods with non-lifetime generic parameters, so a dispa ## Source -The macro is the `cgp_auto_dispatch` entry point in [crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs), forwarded from the proc-macro shim in [crates/macros/cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs) and re-exported through [crates/main/cgp-extra/src/prelude.rs](../../../crates/main/cgp-extra/src/prelude.rs). The matchers it generates live in [crates/extra/cgp-dispatch/src/providers/matchers/](../../../crates/extra/cgp-dispatch/src/providers/matchers/). Tests are in [crates/tests/cgp-tests/tests/dispatching/](../../../crates/tests/cgp-tests/tests/dispatching/), including the `auto_dispatch_shape.rs` cases covering by-reference, by-mutable-reference, by-value, multi-argument, and async methods. +The macro is the `cgp_auto_dispatch` entry point in [crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs), forwarded from the proc-macro shim in [crates/macros/cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs) and re-exported through [crates/main/cgp-extra/src/prelude.rs](../../../crates/main/cgp-extra/src/prelude.rs). The matchers it generates live in [crates/extra/cgp-dispatch/src/providers/matchers/](../../../crates/extra/cgp-dispatch/src/providers/matchers/). + +For the internal walkthrough — the blanket-impl and per-variant-computer helpers, the matcher selection, the lifetime elaboration, and the index of behavioral tests — see the implementation document [implementation/entrypoints/cgp_auto_dispatch.md](../../implementation/entrypoints/cgp_auto_dispatch.md). diff --git a/docs/reference/macros/cgp_auto_getter.md b/docs/reference/macros/cgp_auto_getter.md index 9bcf895a..b1cf1329 100644 --- a/docs/reference/macros/cgp_auto_getter.md +++ b/docs/reference/macros/cgp_auto_getter.md @@ -158,4 +158,6 @@ The explicit form is more verbose but requires no understanding of `HasField` or ## Source -The macro entry point is `cgp_auto_getter` in [crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs), which rejects any attribute argument and runs `ItemCgpAutoGetter::preprocess(...).to_items()`. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_auto_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_auto_getter/): `item.rs` sets the `__Context__` context identifier and drives field parsing, and `blanket.rs` builds the single blanket impl. Getter parsing — including the `&str`/`Option<&T>`/`&[T]`/owned shorthands and the associated-type rules — is shared with `#[cgp_getter]` in [crates/macros/cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs), [crates/macros/cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), and [crates/macros/cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/). Behavioral and expansion-snapshot tests are in [crates/tests/cgp-tests/tests/getters/](../../../crates/tests/cgp-tests/tests/getters/) (notably `assoc_type_auto_getter.rs` for the associated-type form and `string_auto.rs` for the `&str` shorthand). +The macro entry point is `cgp_auto_getter` in [crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs), which rejects any attribute argument and runs `ItemCgpAutoGetter::preprocess(...).to_items()`. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_auto_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_auto_getter/): `item.rs` sets the `__Context__` context identifier and drives field parsing, and `blanket.rs` builds the single blanket impl. Getter parsing — including the `&str`/`Option<&T>`/`&[T]`/owned shorthands and the associated-type rules — is shared with `#[cgp_getter]` in [crates/macros/cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs), [crates/macros/cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), and [crates/macros/cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/). + +For the full internal walkthrough — the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/cgp_auto_getter.md](../../implementation/entrypoints/cgp_auto_getter.md). diff --git a/docs/reference/macros/cgp_computer.md b/docs/reference/macros/cgp_computer.md index 780c3b6b..dbc3cade 100644 --- a/docs/reference/macros/cgp_computer.md +++ b/docs/reference/macros/cgp_computer.md @@ -145,4 +145,6 @@ Because the function returns a plain `u64`, the `try_compute` and `handle` forms ## Source -The macro entrypoint is [crates/macros/cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs), forwarding to the implementation in [crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs); the `Result`-versus-value detection is the `MaybeResultType` parser in [crates/macros/cgp-extra-macro-lib/src/parse/maybe_result.rs](../../../crates/macros/cgp-extra-macro-lib/src/parse/maybe_result.rs). The base `Computer`/`AsyncComputer` traits are defined in [crates/extra/cgp-handler/src/components/](../../../crates/extra/cgp-handler/src/components/), and the promotion bundles in [crates/extra/cgp-handler/src/providers/promote_all.rs](../../../crates/extra/cgp-handler/src/providers/promote_all.rs). Behavioral and snapshot tests live in [crates/tests/cgp-tests/tests/handlers/computer_macro.rs](../../../crates/tests/cgp-tests/tests/handlers/computer_macro.rs). +The macro entrypoint is [crates/macros/cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs), forwarding to the implementation in [crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs); the `Result`-versus-value detection is the `MaybeResultType` parser in [crates/macros/cgp-extra-macro-lib/src/parse/maybe_result.rs](../../../crates/macros/cgp-extra-macro-lib/src/parse/maybe_result.rs). The base `Computer`/`AsyncComputer` traits are defined in [crates/extra/cgp-handler/src/components/](../../../crates/extra/cgp-handler/src/components/), and the promotion bundles in [crates/extra/cgp-handler/src/providers/promote_all.rs](../../../crates/extra/cgp-handler/src/providers/promote_all.rs). + +For the internal walkthrough — the sync/async and value/`Result` branching, the generated items, and the index of behavioral tests — see the implementation document [implementation/entrypoints/cgp_computer.md](../../implementation/entrypoints/cgp_computer.md). diff --git a/docs/reference/macros/cgp_fn.md b/docs/reference/macros/cgp_fn.md index a8bd0753..a2d12c71 100644 --- a/docs/reference/macros/cgp_fn.md +++ b/docs/reference/macros/cgp_fn.md @@ -170,4 +170,6 @@ Because `Rectangle` derives `HasField` and carries `width`, `height`, and `scale ## Source -The macro entry point is `cgp_fn` in [crates/macros/cgp-macro-lib/src/cgp_fn.rs](../../../crates/macros/cgp-macro-lib/src/cgp_fn.rs), which parses the optional trait-name identifier and the function, then runs `item.preprocess()?.to_items()?`. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_fn/](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/): `item.rs` performs the PascalCase default-name derivation (`to_camel_case_str`), implicit-argument extraction, and attribute parsing; `preprocessed.rs` builds the trait in `to_item_trait` and the blanket impl in `to_item_impl`, including the generics/`where`-clause split and the insertion of the leading `__Context__` parameter. Implicit-argument handling is in [crates/macros/cgp-macro-core/src/types/implicits/](../../../crates/macros/cgp-macro-core/src/types/implicits/), and the companion-attribute parsing is in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs). Behavioral and expansion-snapshot tests are spread across the concept directories: the basic form and implicit arguments in [crates/tests/cgp-tests/tests/implicit_arguments/](../../../crates/tests/cgp-tests/tests/implicit_arguments/), generics in [crates/tests/cgp-tests/tests/generic_components/](../../../crates/tests/cgp-tests/tests/generic_components/), the `#[uses]` and `#[extend]` companion attributes in [crates/tests/cgp-tests/tests/impl_side_dependencies/](../../../crates/tests/cgp-tests/tests/impl_side_dependencies/), `#[use_type]` in [crates/tests/cgp-tests/tests/abstract_types/](../../../crates/tests/cgp-tests/tests/abstract_types/), and `#[use_provider]` in [crates/tests/cgp-tests/tests/higher_order_providers/](../../../crates/tests/cgp-tests/tests/higher_order_providers/). +The macro entry point is `cgp_fn` in [crates/macros/cgp-macro-lib/src/cgp_fn.rs](../../../crates/macros/cgp-macro-lib/src/cgp_fn.rs), which parses the optional trait-name identifier and the function, then runs `item.preprocess()?.to_items()?`. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_fn/](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/): `item.rs` performs the PascalCase default-name derivation (`to_camel_case_str`), implicit-argument extraction, and attribute parsing; `preprocessed.rs` builds the trait in `to_item_trait` and the blanket impl in `to_item_impl`, including the generics/`where`-clause split and the insertion of the leading `__Context__` parameter. Implicit-argument handling is in [crates/macros/cgp-macro-core/src/types/implicits/](../../../crates/macros/cgp-macro-core/src/types/implicits/), and the companion-attribute parsing is in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs). + +For the full internal walkthrough — the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/cgp_fn.md](../../implementation/entrypoints/cgp_fn.md). diff --git a/docs/reference/macros/cgp_getter.md b/docs/reference/macros/cgp_getter.md index c2637f90..30b49112 100644 --- a/docs/reference/macros/cgp_getter.md +++ b/docs/reference/macros/cgp_getter.md @@ -150,4 +150,6 @@ The direct implementation is the most transparent option and shows that a `#[cgp ## Source -The macro entry point is `cgp_getter` in [crates/macros/cgp-macro-lib/src/cgp_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_getter.rs), which derives the default provider name (strip `Has`, append `Getter`), runs the `#[cgp_component]` `preprocess → eval` pipeline, then converts the result into `ItemCgpGetter` and emits the extra provider impls. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/): `item.rs` assembles the items, `use_field.rs` builds the `UseField` impl with the free `__Tag__` parameter, `to_use_fields_impl.rs` builds the `UseFields` impl keyed by method name, and `with_provider.rs` builds the `WithProvider` impl. Getter-method parsing and the return-type shorthands are shared with `#[cgp_auto_getter]` in [crates/macros/cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs) and [crates/macros/cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/). Behavioral and expansion-snapshot tests are in [crates/tests/cgp-tests/tests/getters/](../../../crates/tests/cgp-tests/tests/getters/) (notably `string.rs` for the full `UseField`/`UseFields`/`WithProvider` expansion). +The macro entry point is `cgp_getter` in [crates/macros/cgp-macro-lib/src/cgp_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_getter.rs), which derives the default provider name (strip `Has`, append `Getter`), runs the `#[cgp_component]` `preprocess → eval` pipeline, then converts the result into `ItemCgpGetter` and emits the extra provider impls. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/): `item.rs` assembles the items, `use_field.rs` builds the `UseField` impl with the free `__Tag__` parameter, `to_use_fields_impl.rs` builds the `UseFields` impl keyed by method name, and `with_provider.rs` builds the `WithProvider` impl. Getter-method parsing and the return-type shorthands are shared with `#[cgp_auto_getter]` in [crates/macros/cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs) and [crates/macros/cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/). + +For the full internal walkthrough — the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/cgp_getter.md](../../implementation/entrypoints/cgp_getter.md). diff --git a/docs/reference/macros/cgp_impl.md b/docs/reference/macros/cgp_impl.md index 3123667b..9b0dd3a0 100644 --- a/docs/reference/macros/cgp_impl.md +++ b/docs/reference/macros/cgp_impl.md @@ -177,4 +177,6 @@ The call `rect.area()` resolves through the consumer blanket impl to `Rectangle` ## Source -The macro entry point is `cgp_impl` in [crates/macros/cgp-macro-lib/src/cgp_impl.rs](../../../crates/macros/cgp-macro-lib/src/cgp_impl.rs), which lowers the impl and emits the lowered provider impl alongside any default impls. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_impl/](../../../crates/macros/cgp-macro-core/src/types/cgp_impl/): attribute argument parsing (the `new` keyword, provider type, optional component type) in `args.rs`; the lowering that extracts implicit arguments, applies companion attributes, and inserts the `__Context__` parameter when `for` is omitted in `item.rs`; the rewrite of `self`/`Self` and the handoff to `#[cgp_provider]` in `lowered.rs`; and the bare-impl passthrough for `#[cgp_impl(Self)]` in `provider_or_bare.rs`. The `self`/`Self` rewriting is performed by the `ReplaceSelfType`, `ReplaceSelfReceiver`, and `ReplaceSelfValue` visitors in [crates/macros/cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). Expansion snapshots are in [crates/tests/cgp-tests](../../../crates/tests/cgp-tests), notably `tests/basic_delegation/provider_macro.rs` for the canonical provider form and `tests/implicit_arguments/` for the `#[implicit]`-argument and implicit-context variants. +The macro entry point is `cgp_impl` in [crates/macros/cgp-macro-lib/src/cgp_impl.rs](../../../crates/macros/cgp-macro-lib/src/cgp_impl.rs), which lowers the impl and emits the lowered provider impl alongside any default impls. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_impl/](../../../crates/macros/cgp-macro-core/src/types/cgp_impl/): attribute argument parsing (the `new` keyword, provider type, optional component type) in `args.rs`; the lowering that extracts implicit arguments, applies companion attributes, and inserts the `__Context__` parameter when `for` is omitted in `item.rs`; the rewrite of `self`/`Self` and the handoff to `#[cgp_provider]` in `lowered.rs`; and the bare-impl passthrough for `#[cgp_impl(Self)]` in `provider_or_bare.rs`. The `self`/`Self` rewriting is performed by the `ReplaceSelfType`, `ReplaceSelfReceiver`, and `ReplaceSelfValue` visitors in [crates/macros/cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). + +For the internal walkthrough — pipeline, generated items, corner cases, and the index of tests and snapshots — see [implementation/entrypoints/cgp_impl.md](../../implementation/entrypoints/cgp_impl.md). diff --git a/docs/reference/macros/cgp_namespace.md b/docs/reference/macros/cgp_namespace.md index 23a9fe88..65a747a6 100644 --- a/docs/reference/macros/cgp_namespace.md +++ b/docs/reference/macros/cgp_namespace.md @@ -210,4 +210,6 @@ Inheritance composes the same way at the namespace level: `ExtendedNamespace: De ## Source -The macro entry point is `cgp_namespace` in [crates/macros/cgp-macro-lib/src/cgp_namespace.rs](../../../crates/macros/cgp-macro-lib/src/cgp_namespace.rs), which parses a `NamespaceTable` and calls `.eval()`. The logic lives in [crates/macros/cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/): `table.rs` parses the header (`new`, namespace name, optional `: parent`) and builds the trait, struct, per-entry impls, and the parent-inheritance impl; `inherit.rs` builds the path-rewriting inheritance entry; `eval.rs` holds the emitted `EvaluatedNamespaceTable`. The `#[prefix(...)]` attribute that attaches a component to a namespace is parsed in [crates/macros/cgp-macro-core/src/types/attributes/prefix.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/prefix.rs), and the matching `RedirectLookup` provider impl is emitted by [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs). The runtime traits `DefaultNamespace`/`DefaultImpls1`/`DefaultImpls2` are in [crates/core/cgp-component/src/namespaces.rs](../../../crates/core/cgp-component/src/namespaces.rs) and `RedirectLookup` in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs). Expansion snapshots covering the basic, symbol-path, multi-namespace, extended, and default-impls cases are in [crates/tests/cgp-tests/tests/namespaces/](../../../crates/tests/cgp-tests/tests/namespaces/). +The macro entry point is `cgp_namespace` in [crates/macros/cgp-macro-lib/src/cgp_namespace.rs](../../../crates/macros/cgp-macro-lib/src/cgp_namespace.rs), which parses a `NamespaceTable` and calls `.eval()`. The logic lives in [crates/macros/cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/): `table.rs` parses the header (`new`, namespace name, optional `: parent`) and builds the trait, struct, per-entry impls, and the parent-inheritance impl; `inherit.rs` builds the path-rewriting inheritance entry; `eval.rs` holds the emitted `EvaluatedNamespaceTable`. The `#[prefix(...)]` attribute that attaches a component to a namespace is parsed in [crates/macros/cgp-macro-core/src/types/attributes/prefix.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/prefix.rs), and the matching `RedirectLookup` provider impl is emitted by [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs). The runtime traits `DefaultNamespace`/`DefaultImpls1`/`DefaultImpls2` are in [crates/core/cgp-component/src/namespaces.rs](../../../crates/core/cgp-component/src/namespaces.rs) and `RedirectLookup` in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs). + +For the full internal walkthrough — the pipeline, the item each entry form generates, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/cgp_namespace.md](../../implementation/entrypoints/cgp_namespace.md). diff --git a/docs/reference/macros/cgp_new_provider.md b/docs/reference/macros/cgp_new_provider.md index 627b446d..6dfa96e9 100644 --- a/docs/reference/macros/cgp_new_provider.md +++ b/docs/reference/macros/cgp_new_provider.md @@ -115,4 +115,6 @@ This is equivalent to writing `pub struct RectangleArea;` followed by the same i ## Source -The macro entry point is `cgp_new_provider` in [crates/macros/cgp-macro-lib/src/cgp_new_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_new_provider.rs); it parses the same `ProviderArgs`, sets `new` to enabled, and then runs the identical lowering as [`#[cgp_provider]`](cgp_provider.md). All of the generation logic — including the struct declaration emitted when `new` is set — lives in [crates/macros/cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/); the struct shape is built in `item.rs` (`to_provider_struct`). The `#[cgp_impl(new …)]` sugar that desugars to `#[cgp_new_provider]` (declaring the provider struct alongside the impl) is snapshotted in [crates/tests/cgp-tests/tests/basic_delegation/provider_macro.rs](../../../crates/tests/cgp-tests/tests/basic_delegation/provider_macro.rs), and `#[cgp_new_provider]` is exercised directly in [crates/tests/cgp-tests/tests/dispatching/compose.rs](../../../crates/tests/cgp-tests/tests/dispatching/compose.rs) and [crates/tests/cgp-tests/tests/async_and_send/spawn.rs](../../../crates/tests/cgp-tests/tests/async_and_send/spawn.rs). +The macro entry point is `cgp_new_provider` in [crates/macros/cgp-macro-lib/src/cgp_new_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_new_provider.rs); it parses the same `ProviderArgs`, sets `new` to enabled, and then runs the identical lowering as [`#[cgp_provider]`](cgp_provider.md). All of the generation logic — including the struct declaration emitted when `new` is set — lives in [crates/macros/cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/); the struct shape is built in `item.rs` (`to_provider_struct`). + +For the internal walkthrough — pipeline, generated items, corner cases, and the index of tests and snapshots — see [implementation/entrypoints/cgp_new_provider.md](../../implementation/entrypoints/cgp_new_provider.md). diff --git a/docs/reference/macros/cgp_producer.md b/docs/reference/macros/cgp_producer.md index d33a9997..90e6af30 100644 --- a/docs/reference/macros/cgp_producer.md +++ b/docs/reference/macros/cgp_producer.md @@ -118,4 +118,6 @@ The computer and handler forms accept an input argument and ignore it, since the ## Source -The macro entrypoint is [crates/macros/cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs), forwarding to the implementation in [crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs). The `Producer` trait is defined in [crates/extra/cgp-handler/src/components/produce.rs](../../../crates/extra/cgp-handler/src/components/produce.rs), and the `PromoteProducer` bundle in [crates/extra/cgp-handler/src/providers/promote_all.rs](../../../crates/extra/cgp-handler/src/providers/promote_all.rs). Behavioral and snapshot tests live in [crates/tests/cgp-tests/tests/handlers/producer_macro.rs](../../../crates/tests/cgp-tests/tests/handlers/producer_macro.rs). +The macro entrypoint is [crates/macros/cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs), forwarding to the implementation in [crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs). The `Producer` trait is defined in [crates/extra/cgp-handler/src/components/produce.rs](../../../crates/extra/cgp-handler/src/components/produce.rs), and the `PromoteProducer` bundle in [crates/extra/cgp-handler/src/providers/promote_all.rs](../../../crates/extra/cgp-handler/src/providers/promote_all.rs). + +For the internal walkthrough — the signature validation, the generated items, and the index of behavioral tests — see the implementation document [implementation/entrypoints/cgp_producer.md](../../implementation/entrypoints/cgp_producer.md). diff --git a/docs/reference/macros/cgp_provider.md b/docs/reference/macros/cgp_provider.md index a944739e..e6430666 100644 --- a/docs/reference/macros/cgp_provider.md +++ b/docs/reference/macros/cgp_provider.md @@ -138,4 +138,6 @@ In most code, the same provider would be written more concisely with [`#[cgp_imp ## Source -The macro entry point is `cgp_provider` in [crates/macros/cgp-macro-lib/src/cgp_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_provider.rs), which parses the optional component argument, lowers the impl, and emits the result. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/): attribute argument parsing (the optional `new` keyword and component type) in `args.rs`; the lowering that derives the component default, the provider struct, and the `IsProviderFor` impl in `item.rs`; the emitted-token assembly in `lower.rs`; and the splitting of provider-trait arguments into context and `Params` tuple in `provider_impl_args.rs`. The `IsProviderFor` derivation itself is in [crates/macros/cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs). Expansion snapshots of the generated provider impl are in [crates/tests/cgp-tests/tests/generic_components/](../../../crates/tests/cgp-tests/tests/generic_components/) (the const-generic and lifetime provider cases), and `#[cgp_provider]` is exercised directly in [crates/tests/cgp-tests/tests/dispatching/compose.rs](../../../crates/tests/cgp-tests/tests/dispatching/compose.rs) and [crates/tests/cgp-tests/tests/async_and_send/spawn.rs](../../../crates/tests/cgp-tests/tests/async_and_send/spawn.rs). +The macro entry point is `cgp_provider` in [crates/macros/cgp-macro-lib/src/cgp_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_provider.rs), which parses the optional component argument, lowers the impl, and emits the result. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/): attribute argument parsing (the optional `new` keyword and component type) in `args.rs`; the lowering that derives the component default, the provider struct, and the `IsProviderFor` impl in `item.rs`; the emitted-token assembly in `lower.rs`; and the splitting of provider-trait arguments into context and `Params` tuple in `provider_impl_args.rs`. The `IsProviderFor` derivation itself is in [crates/macros/cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs). + +For the internal walkthrough — pipeline, generated items, corner cases, and the index of tests and snapshots — see [implementation/entrypoints/cgp_provider.md](../../implementation/entrypoints/cgp_provider.md). diff --git a/docs/reference/macros/cgp_type.md b/docs/reference/macros/cgp_type.md index a7857808..b023e124 100644 --- a/docs/reference/macros/cgp_type.md +++ b/docs/reference/macros/cgp_type.md @@ -128,4 +128,6 @@ This direct form is only marginally longer than the wired form and is the most a ## Source -The macro entry point is `cgp_type` in [crates/macros/cgp-macro-lib/src/cgp_type.rs](../../../crates/macros/cgp-macro-lib/src/cgp_type.rs), which extracts the single associated type, derives the default `{Type}TypeProvider` provider name from the associated type's identifier, runs the `#[cgp_component]` `preprocess → eval` pipeline, and converts the result into `ItemCgpType`. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs), which validates the trait shape (`extract_item_type_from_trait`) and builds the `UseType` and `WithProvider` provider impls. The runtime `HasType`, `TypeProvider`, and `UseType` definitions are in [crates/core/cgp-type/src/](../../../crates/core/cgp-type/src/) (`traits/has_type.rs` and `impls/use_type.rs`). Behavioral and expansion-snapshot tests are in [crates/tests/cgp-tests/tests/abstract_types/](../../../crates/tests/cgp-tests/tests/abstract_types/) (notably `cgp_type_macro.rs`). +The macro entry point is `cgp_type` in [crates/macros/cgp-macro-lib/src/cgp_type.rs](../../../crates/macros/cgp-macro-lib/src/cgp_type.rs), which extracts the single associated type, derives the default `{Type}TypeProvider` provider name from the associated type's identifier, runs the `#[cgp_component]` `preprocess → eval` pipeline, and converts the result into `ItemCgpType`. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs), which validates the trait shape (`extract_item_type_from_trait`) and builds the `UseType` and `WithProvider` provider impls. The runtime `HasType`, `TypeProvider`, and `UseType` definitions are in [crates/core/cgp-type/src/](../../../crates/core/cgp-type/src/) (`traits/has_type.rs` and `impls/use_type.rs`). + +For the full internal walkthrough — the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/cgp_type.md](../../implementation/entrypoints/cgp_type.md). diff --git a/docs/reference/macros/check_components.md b/docs/reference/macros/check_components.md index a38327b1..4f270114 100644 --- a/docs/reference/macros/check_components.md +++ b/docs/reference/macros/check_components.md @@ -213,4 +213,6 @@ This verifies `MyApp: CanCalculateAreaOfShape` and `MyApp: CanCalcula ## Source -The macro entry point is `check_components` in [crates/macros/cgp-macro-lib/src/check_components.rs](../../../crates/macros/cgp-macro-lib/src/check_components.rs), which parses `CheckComponentsTables` and emits their items. The logic lives in [crates/macros/cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/): table parsing, the `#[check_trait]`/`#[check_providers]` attributes, the `__Check{Context}` name derivation, and the choice between `CanUseComponent` and `IsProviderFor` supertraits are all in `table.rs`; key and value parsing (including array syntax) in `key.rs` and `value.rs`; and the cartesian-product expansion of entries in `entry.rs`. Expansion snapshots are in [crates/tests/cgp-tests/tests/checking/](../../../crates/tests/cgp-tests/tests/checking/). +The macro entry point is `check_components` in [crates/macros/cgp-macro-lib/src/check_components.rs](../../../crates/macros/cgp-macro-lib/src/check_components.rs), which parses `CheckComponentsTables` and emits their items. The logic lives in [crates/macros/cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/): table parsing, the `#[check_trait]`/`#[check_providers]` attributes, the `__Check{Context}` name derivation, and the choice between `CanUseComponent` and `IsProviderFor` supertraits are all in `table.rs`; key and value parsing (including array syntax) in `key.rs` and `value.rs`; and the cartesian-product expansion of entries in `entry.rs`. + +For the full internal walkthrough — the pipeline, the AST types behind each grammar form, the corner-case handling, and the index of expansion snapshots — see the implementation document [implementation/entrypoints/check_components.md](../../implementation/entrypoints/check_components.md). diff --git a/docs/reference/macros/delegate_and_check_components.md b/docs/reference/macros/delegate_and_check_components.md index a37b7c54..09b22c9d 100644 --- a/docs/reference/macros/delegate_and_check_components.md +++ b/docs/reference/macros/delegate_and_check_components.md @@ -182,4 +182,6 @@ delegate_and_check_components! { ## Source -The macro entry point is `delegate_and_check_components` in [crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs), which parses the table, evaluates the delegation half via the shared `DelegateTable`, derives a `CheckComponentsTable` from the keys, and emits both. The logic lives in [crates/macros/cgp-macro-core/src/types/delegate_and_check_components/](../../../crates/macros/cgp-macro-core/src/types/delegate_and_check_components/): the `__CanUse{Context}` default name and `#[check_trait]` handling in `item.rs`, the `#[check_params]`/`#[skip_check]` parsing and their mutual exclusion in `check_params.rs`, the per-key conversion to check entries in `key_with_check_params.rs`, and the walk over delegation entries in `to_keys_with_check_params.rs`. It reuses the `DelegateTable` from [delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/) and the `CheckComponentsTable` from [check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/). Expansion snapshots are in [crates/tests/cgp-tests/tests/checking/](../../../crates/tests/cgp-tests/tests/checking/). +The macro entry point is `delegate_and_check_components` in [crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs), which parses the table, evaluates the delegation half via the shared `DelegateTable`, derives a `CheckComponentsTable` from the keys, and emits both. The logic lives in [crates/macros/cgp-macro-core/src/types/delegate_and_check_components/](../../../crates/macros/cgp-macro-core/src/types/delegate_and_check_components/): the `__CanUse{Context}` default name and `#[check_trait]` handling in `item.rs`, the `#[check_params]`/`#[skip_check]` parsing and their mutual exclusion in `check_params.rs`, the per-key conversion to check entries in `key_with_check_params.rs`, and the walk over delegation entries in `to_keys_with_check_params.rs`. It reuses the `DelegateTable` from [delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/) and the `CheckComponentsTable` from [check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/). + +For the full internal walkthrough — the two reused pipelines, the key-to-check derivation, the corner-case handling, and the index of expansion snapshots — see the implementation document [implementation/entrypoints/delegate_and_check_components.md](../../implementation/entrypoints/delegate_and_check_components.md). diff --git a/docs/reference/macros/delegate_components.md b/docs/reference/macros/delegate_components.md index 44fbe584..30a6d331 100644 --- a/docs/reference/macros/delegate_components.md +++ b/docs/reference/macros/delegate_components.md @@ -253,4 +253,6 @@ delegate_components! { ## Source -The macro entry point is `delegate_components` in [crates/macros/cgp-macro-lib/src/delegate_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_components.rs), which parses a `DelegateTable`, validates that no attributes are present, evaluates it, and emits the tokens. The logic lives in [crates/macros/cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/): the top-level table and the `new` keyword in `table/main.rs`, key parsing (single, array/`Multi`, path) in `key/`, value parsing including the nested-table form in `value/`, the statement forms (`open`, `namespace`, `for`) in `statement/` — with the `open` statement and its `RedirectLookup` expansion in `statement/open.rs` — and the `DelegateComponent`/`IsProviderFor` impl construction in `mapping/eval.rs`. Attribute rejection is in `validate_attributes.rs`. Expansion snapshots covering the single-entry, array, and generic-table forms are in [crates/tests/cgp-tests/tests/basic_delegation/](../../../crates/tests/cgp-tests/tests/basic_delegation/), and the namespace-header form (`namespace …;`, `@`-path keys) is exercised by the namespace snapshots in [crates/tests/cgp-tests/tests/namespaces/](../../../crates/tests/cgp-tests/tests/namespaces/). +The macro entry point is `delegate_components` in [crates/macros/cgp-macro-lib/src/delegate_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_components.rs), which parses a `DelegateTable`, validates that no attributes are present, evaluates it, and emits the tokens. The logic lives in [crates/macros/cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/): the top-level table and the `new` keyword in `table/main.rs`, key parsing (single, array/`Multi`, path) in `key/`, value parsing including the nested-table form in `value/`, the statement forms (`open`, `namespace`, `for`) in `statement/` — with the `open` statement and its `RedirectLookup` expansion in `statement/open.rs` — and the `DelegateComponent`/`IsProviderFor` impl construction in `mapping/eval.rs`. Attribute rejection is in `validate_attributes.rs`. + +For the full internal walkthrough — the pipeline, the AST types behind each grammar form, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/delegate_components.md](../../implementation/entrypoints/delegate_components.md). diff --git a/docs/reference/macros/path.md b/docs/reference/macros/path.md index 0f81ad90..e07de081 100644 --- a/docs/reference/macros/path.md +++ b/docs/reference/macros/path.md @@ -93,4 +93,6 @@ Either way the path is the same `PathCons` list; the macro and the namespace sim ## Source -The macro entry point is `Path` in [crates/macros/cgp-macro-lib/src/path.rs](../../../crates/macros/cgp-macro-lib/src/path.rs), which parses the body into a `UniPath` and emits its tokens. The parsing and codegen live in [crates/macros/cgp-macro-core/src/types/path/](../../../crates/macros/cgp-macro-core/src/types/path/): `unipath.rs` requires the leading `@`, parses the dot-separated segments, and right-folds them with `PathCons` onto `Nil`; `path_element.rs` decides per segment whether a lowercase, non-primitive identifier becomes a `Symbol` or the segment stays a named type. The runtime spine `PathCons` is defined in [crates/core/cgp-base-types/src/types/path.rs](../../../crates/core/cgp-base-types/src/types/path.rs), and the `RedirectLookup` provider that walks a path is in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs). The `@`-path forms are exercised by the namespace snapshot tests in [crates/tests/cgp-tests/tests/namespaces/](../../../crates/tests/cgp-tests/tests/namespaces/). +The macro entry point is `Path` in [crates/macros/cgp-macro-lib/src/path.rs](../../../crates/macros/cgp-macro-lib/src/path.rs), which parses the body into a `UniPath` and emits its tokens. The parsing and codegen live in [crates/macros/cgp-macro-core/src/types/path/](../../../crates/macros/cgp-macro-core/src/types/path/): `unipath.rs` requires the leading `@`, parses the dot-separated segments, and right-folds them with `PathCons` onto `Nil`; `path_element.rs` decides per segment whether a lowercase, non-primitive identifier becomes a `Symbol` or the segment stays a named type. The runtime spine `PathCons` is defined in [crates/core/cgp-base-types/src/types/path.rs](../../../crates/core/cgp-base-types/src/types/path.rs), and the `RedirectLookup` provider that walks a path is in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs). + +For the full internal walkthrough — the parse-and-emit pipeline, the per-segment symbol/type classification, the `PathCons` fold, and the index of tests — see the implementation document [implementation/entrypoints/path.md](../../implementation/entrypoints/path.md). diff --git a/docs/reference/macros/product.md b/docs/reference/macros/product.md index bb74a6f3..2bb5d847 100644 --- a/docs/reference/macros/product.md +++ b/docs/reference/macros/product.md @@ -102,3 +102,5 @@ let row: Row = product![1, "hi".to_string(), true]; ## Source The macro entry points are `Product` and `product` in [crates/macros/cgp-macro-lib/src/product.rs](../../../crates/macros/cgp-macro-lib/src/product.rs). The type form is the `ProductType` construct in [crates/macros/cgp-macro-core/src/types/product/product_type.rs](../../../crates/macros/cgp-macro-core/src/types/product/product_type.rs), whose `eval` right-folds the elements with `Cons` onto `Nil`; the value form is `ProductExpr` in [crates/macros/cgp-macro-core/src/types/product/product_expr.rs](../../../crates/macros/cgp-macro-core/src/types/product/product_expr.rs), which does the same fold using the `Cons(..)` constructor. The runtime types are defined in [crates/core/cgp-base-types/src/types/cons.rs](../../../crates/core/cgp-base-types/src/types/cons.rs) (`Cons`) and [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs) (`Nil`). + +For the full internal walkthrough — the parse-and-`eval` pipeline shared by both forms, the right-fold onto `Nil`, and the index of tests — see the implementation document [implementation/entrypoints/product.md](../../implementation/entrypoints/product.md). diff --git a/docs/reference/macros/sum.md b/docs/reference/macros/sum.md index 2a87f6a3..a814e871 100644 --- a/docs/reference/macros/sum.md +++ b/docs/reference/macros/sum.md @@ -89,3 +89,5 @@ type Token = Sum![u32, String, bool]; ## Source The macro entry point is `Sum` in [crates/macros/cgp-macro-lib/src/sum.rs](../../../crates/macros/cgp-macro-lib/src/sum.rs), forwarding to the `SumType` construct in [crates/macros/cgp-macro-core/src/types/sum.rs](../../../crates/macros/cgp-macro-core/src/types/sum.rs), whose `eval` right-folds the element types with `Either` onto `Void`. The runtime types `Either` and the uninhabited `Void` are both defined in [crates/core/cgp-field/src/types/sum.rs](../../../crates/core/cgp-field/src/types/sum.rs). The enum `HasFields` derive that emits a `Sum!` of `Field` branches lives in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs). + +For the full internal walkthrough — the parse-and-`eval` pipeline, the right-fold onto `Void`, and the index of tests — see the implementation document [implementation/entrypoints/sum.md](../../implementation/entrypoints/sum.md). diff --git a/docs/reference/macros/symbol.md b/docs/reference/macros/symbol.md index 9882da59..d7ebc087 100644 --- a/docs/reference/macros/symbol.md +++ b/docs/reference/macros/symbol.md @@ -85,4 +85,6 @@ When a struct derives [`HasField`](../derives/derive_has_field.md), each named f ## Source -The macro entry point is `Symbol` in [crates/macros/cgp-macro-lib/src/symbol.rs](../../../crates/macros/cgp-macro-lib/src/symbol.rs), which forwards to the `Symbol` construct in [crates/macros/cgp-macro-core/src/types/field/symbol.rs](../../../crates/macros/cgp-macro-core/src/types/field/symbol.rs) — its `ToTokens` impl performs the right-fold over the characters, computes `LEN` from `str::len()`, and wraps the result in `Symbol`. The runtime types are defined in [crates/core/cgp-base-types/src/types/symbol.rs](../../../crates/core/cgp-base-types/src/types/symbol.rs) (`Symbol`) and [crates/core/cgp-base-types/src/types/chars.rs](../../../crates/core/cgp-base-types/src/types/chars.rs) (`Chars`), with `Nil` in [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs). Tests covering display round-tripping and multi-byte strings are in [crates/tests/cgp-tests/tests/field_access/symbol.rs](../../../crates/tests/cgp-tests/tests/field_access/symbol.rs). +The macro entry point is `Symbol` in [crates/macros/cgp-macro-lib/src/symbol.rs](../../../crates/macros/cgp-macro-lib/src/symbol.rs), which forwards to the `Symbol` construct in [crates/macros/cgp-macro-core/src/types/field/symbol.rs](../../../crates/macros/cgp-macro-core/src/types/field/symbol.rs) — its `ToTokens` impl performs the right-fold over the characters, computes `LEN` from `str::len()`, and wraps the result in `Symbol`. The runtime types are defined in [crates/core/cgp-base-types/src/types/symbol.rs](../../../crates/core/cgp-base-types/src/types/symbol.rs) (`Symbol`) and [crates/core/cgp-base-types/src/types/chars.rs](../../../crates/core/cgp-base-types/src/types/chars.rs) (`Chars`), with `Nil` in [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs). + +For the full internal walkthrough — the parse-and-emit pipeline, the character fold and the `LEN` const workaround, and the index of tests — see the implementation document [implementation/entrypoints/symbol.md](../../implementation/entrypoints/symbol.md). diff --git a/docs/reference/providers/dispatch_combinators.md b/docs/reference/providers/dispatch_combinators.md index 59f40422..dd165ecc 100644 --- a/docs/reference/providers/dispatch_combinators.md +++ b/docs/reference/providers/dispatch_combinators.md @@ -266,4 +266,4 @@ The matchers stand on the enum-deconstruction traits in [`extract_field`](../tra ## Source -The provider structs live under [crates/extra/cgp-dispatch/src/providers/](../../../crates/extra/cgp-dispatch/src/providers/): the matchers in `with_handlers/` (`match_with_handlers.rs`, `match_with_handlers_ref.rs`, `match_with_handlers_mut.rs`, `match_first_with_handlers*.rs`, `build_with_handlers.rs`), the matcher loop alias in `dispatchers/dispatch_matchers.rs`, the field/variant adapters in `field_matchers/` (`extract_field.rs`, `extract_first_field.rs`, `extract_handle.rs`, `field_value.rs`, `first_field_value.rs`), the convenience matchers and the `ToFieldHandlers`/`HasFieldHandlers`/`MapFieldHandler` machinery in `matchers/` (`match_with_field_handlers.rs`, `match_first_with_field_handlers.rs`, `to_field_handlers.rs`), and the builders in `field_builders/` (`build_and_set_field.rs`, `build_and_merge.rs`) and `builders/build_and_merge_outputs.rs`. The prelude re-exports the value-handler matchers from [crates/main/cgp-extra/src/prelude.rs](../../../crates/main/cgp-extra/src/prelude.rs); the remaining structs are reached through `cgp::extra::dispatch`. Tests exercising them are in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/) (matchers) and [extensible_records/](../../../crates/tests/cgp-tests/tests/extensible_records/) (builders). +The provider structs live under [crates/extra/cgp-dispatch/src/providers/](../../../crates/extra/cgp-dispatch/src/providers/): the matchers in `with_handlers/` (`match_with_handlers.rs`, `match_with_handlers_ref.rs`, `match_with_handlers_mut.rs`, `match_first_with_handlers*.rs`, `build_with_handlers.rs`), the matcher loop alias in `dispatchers/dispatch_matchers.rs`, the field/variant adapters in `field_matchers/` (`extract_field.rs`, `extract_first_field.rs`, `extract_handle.rs`, `field_value.rs`, `first_field_value.rs`), the convenience matchers and the `ToFieldHandlers`/`HasFieldHandlers`/`MapFieldHandler` machinery in `matchers/` (`match_with_field_handlers.rs`, `match_first_with_field_handlers.rs`, `to_field_handlers.rs`), and the builders in `field_builders/` (`build_and_set_field.rs`, `build_and_merge.rs`) and `builders/build_and_merge_outputs.rs`. The prelude re-exports the value-handler matchers from [crates/main/cgp-extra/src/prelude.rs](../../../crates/main/cgp-extra/src/prelude.rs); the remaining structs are reached through `cgp::extra::dispatch`. diff --git a/docs/reference/providers/error_providers.md b/docs/reference/providers/error_providers.md index bda3b924..7202d856 100644 --- a/docs/reference/providers/error_providers.md +++ b/docs/reference/providers/error_providers.md @@ -189,4 +189,4 @@ These providers implement the [`CanRaiseError`](../components/can_raise_error.md ## Source -The providers are defined in `cgp-error-extra`: `RaiseFrom` in [crates/extra/cgp-error-extra/src/impls/raise_from.rs](../../../crates/extra/cgp-error-extra/src/impls/raise_from.rs), `ReturnError` in [return_error.rs](../../../crates/extra/cgp-error-extra/src/impls/return_error.rs), `RaiseInfallible` in [infallible.rs](../../../crates/extra/cgp-error-extra/src/impls/infallible.rs), `DiscardDetail` in [discard_detail.rs](../../../crates/extra/cgp-error-extra/src/impls/discard_detail.rs), `PanicOnError` in [panic_error.rs](../../../crates/extra/cgp-error-extra/src/impls/panic_error.rs), and `DebugError`/`DisplayError` (behind the `alloc` feature) in [impls/alloc/debug_error.rs](../../../crates/extra/cgp-error-extra/src/impls/alloc/debug_error.rs) and [display_error.rs](../../../crates/extra/cgp-error-extra/src/impls/alloc/display_error.rs). The `ErrorRaiser`/`ErrorWrapper` provider traits and the `CanRaiseError`/`CanWrapError`/`HasErrorType` consumer traits they build on are in [crates/core/cgp-error/src/](../../../crates/core/cgp-error/src/). The standalone backend counterparts are in [crates/standalone/error/](../../../crates/standalone/error/). These providers are exercised in the error wiring throughout [crates/tests/cgp-tests/](../../../crates/tests/cgp-tests/). +The providers are defined in `cgp-error-extra`: `RaiseFrom` in [crates/extra/cgp-error-extra/src/impls/raise_from.rs](../../../crates/extra/cgp-error-extra/src/impls/raise_from.rs), `ReturnError` in [return_error.rs](../../../crates/extra/cgp-error-extra/src/impls/return_error.rs), `RaiseInfallible` in [infallible.rs](../../../crates/extra/cgp-error-extra/src/impls/infallible.rs), `DiscardDetail` in [discard_detail.rs](../../../crates/extra/cgp-error-extra/src/impls/discard_detail.rs), `PanicOnError` in [panic_error.rs](../../../crates/extra/cgp-error-extra/src/impls/panic_error.rs), and `DebugError`/`DisplayError` (behind the `alloc` feature) in [impls/alloc/debug_error.rs](../../../crates/extra/cgp-error-extra/src/impls/alloc/debug_error.rs) and [display_error.rs](../../../crates/extra/cgp-error-extra/src/impls/alloc/display_error.rs). The `ErrorRaiser`/`ErrorWrapper` provider traits and the `CanRaiseError`/`CanWrapError`/`HasErrorType` consumer traits they build on are in [crates/core/cgp-error/src/](../../../crates/core/cgp-error/src/). The standalone backend counterparts are in [crates/standalone/error/](../../../crates/standalone/error/). diff --git a/docs/reference/providers/handler_combinators.md b/docs/reference/providers/handler_combinators.md index 4ea2b21e..86cb7783 100644 --- a/docs/reference/providers/handler_combinators.md +++ b/docs/reference/providers/handler_combinators.md @@ -217,4 +217,4 @@ The combinators are providers of the handler component traits: [`Computer`](../c ## Source -The combinators are defined in `cgp-handler` under [crates/extra/cgp-handler/src/providers/](../../../crates/extra/cgp-handler/src/providers/): `compose.rs` (`ComposeHandlers`), `pipe.rs` (`PipeHandlers` and the internal `ComposeProviders` fold), `return_input.rs` (`ReturnInput`), `promote.rs` (`Promote`), `promote_async.rs` (`PromoteAsync`), `promote_ref.rs` (`PromoteRef`), `try_promote.rs` (`TryPromote`), and `promote_all.rs` (the `PromoteComputer`, `PromoteTryComputer`, `PromoteProducer`, `PromoteAsyncComputer`, and `PromoteHandler` bundles). `UseInputDelegate` is defined in [crates/extra/cgp-handler/src/types.rs](../../../crates/extra/cgp-handler/src/types.rs), and its provider impls are generated from the `#[derive_delegate(UseInputDelegate)]` directive on the handler component traits in [crates/extra/cgp-handler/src/components/](../../../crates/extra/cgp-handler/src/components/). Behavioral tests exercising the combinators live in [crates/tests/cgp-tests/tests/handlers/](../../../crates/tests/cgp-tests/tests/handlers/), notably `pipe.rs`. +The combinators are defined in `cgp-handler` under [crates/extra/cgp-handler/src/providers/](../../../crates/extra/cgp-handler/src/providers/): `compose.rs` (`ComposeHandlers`), `pipe.rs` (`PipeHandlers` and the internal `ComposeProviders` fold), `return_input.rs` (`ReturnInput`), `promote.rs` (`Promote`), `promote_async.rs` (`PromoteAsync`), `promote_ref.rs` (`PromoteRef`), `try_promote.rs` (`TryPromote`), and `promote_all.rs` (the `PromoteComputer`, `PromoteTryComputer`, `PromoteProducer`, `PromoteAsyncComputer`, and `PromoteHandler` bundles). `UseInputDelegate` is defined in [crates/extra/cgp-handler/src/types.rs](../../../crates/extra/cgp-handler/src/types.rs), and its provider impls are generated from the `#[derive_delegate(UseInputDelegate)]` directive on the handler component traits in [crates/extra/cgp-handler/src/components/](../../../crates/extra/cgp-handler/src/components/). diff --git a/docs/reference/providers/monad_providers.md b/docs/reference/providers/monad_providers.md index 54007f08..b484250b 100644 --- a/docs/reference/providers/monad_providers.md +++ b/docs/reference/providers/monad_providers.md @@ -101,4 +101,4 @@ PipeMonadic::::try_co ## Source -The pipeline provider, `TryPromoteProviders`, and the internal `BindProviders` fold are in [crates/extra/cgp-monad/src/providers/pipe_monadic.rs](../../../crates/extra/cgp-monad/src/providers/pipe_monadic.rs). The monad markers and bind providers are in [crates/extra/cgp-monad/src/monadic/](../../../crates/extra/cgp-monad/src/monadic/) — `ident.rs` for `IdentMonadic`, `ok.rs` for `OkMonadic` / `OkMonadicTrans` / `BindOk`, and `err.rs` for `ErrMonadic` / `ErrMonadicTrans` / `BindErr`. Usage is exercised in [crates/tests/cgp-tests/tests/monadic_handlers/](../../../crates/tests/cgp-tests/tests/monadic_handlers/) (`ok.rs`, `err.rs`, `ok_err_trans.rs`). +The pipeline provider, `TryPromoteProviders`, and the internal `BindProviders` fold are in [crates/extra/cgp-monad/src/providers/pipe_monadic.rs](../../../crates/extra/cgp-monad/src/providers/pipe_monadic.rs). The monad markers and bind providers are in [crates/extra/cgp-monad/src/monadic/](../../../crates/extra/cgp-monad/src/monadic/) — `ident.rs` for `IdentMonadic`, `ok.rs` for `OkMonadic` / `OkMonadicTrans` / `BindOk`, and `err.rs` for `ErrMonadic` / `ErrMonadicTrans` / `BindErr`. diff --git a/docs/reference/providers/redirect_lookup.md b/docs/reference/providers/redirect_lookup.md index 930e3e24..05eda12a 100644 --- a/docs/reference/providers/redirect_lookup.md +++ b/docs/reference/providers/redirect_lookup.md @@ -78,4 +78,4 @@ This registers `TestProvider` under the path `bar`/`baz` in `App`'s default name ## Source -The struct is defined in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs), and the related `DefaultNamespace` trait in [crates/core/cgp-component/src/namespaces.rs](../../../crates/core/cgp-component/src/namespaces.rs). The `RedirectLookup` provider impl is generated by `to_redirect_lookup_impl` in [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs), which appends generic parameters through `ConcatPath`. The namespace delegates that target `RedirectLookup` are produced by the `#[prefix]` attribute in [crates/macros/cgp-macro-core/src/types/attributes/prefix.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/prefix.rs) and the redirect mapping in [crates/macros/cgp-macro-core/src/types/delegate_component/mapping/redirect.rs](../../../crates/macros/cgp-macro-core/src/types/delegate_component/mapping/redirect.rs). Expansion snapshots showing the generated impl and the namespace wiring are in [crates/tests/cgp-tests/tests/namespaces/](../../../crates/tests/cgp-tests/tests/namespaces/). +The struct is defined in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs), and the related `DefaultNamespace` trait in [crates/core/cgp-component/src/namespaces.rs](../../../crates/core/cgp-component/src/namespaces.rs). The `RedirectLookup` provider impl is generated by `to_redirect_lookup_impl` in [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs), which appends generic parameters through `ConcatPath`. The namespace delegates that target `RedirectLookup` are produced by the `#[prefix]` attribute in [crates/macros/cgp-macro-core/src/types/attributes/prefix.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/prefix.rs) and the redirect mapping in [crates/macros/cgp-macro-core/src/types/delegate_component/mapping/redirect.rs](../../../crates/macros/cgp-macro-core/src/types/delegate_component/mapping/redirect.rs). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_component](../../implementation/entrypoints/cgp_component.md). diff --git a/docs/reference/providers/use_context.md b/docs/reference/providers/use_context.md index 5d4b9a69..dedf0d6c 100644 --- a/docs/reference/providers/use_context.md +++ b/docs/reference/providers/use_context.md @@ -85,4 +85,4 @@ Note that `UseContext` only acts as a default when a higher-order provider's str ## Source -The struct is defined in [crates/core/cgp-component/src/providers/use_context.rs](../../../crates/core/cgp-component/src/providers/use_context.rs), which also declares the `WithContext` alias. The `UseContext` provider impl is generated by `to_use_context_impl` in [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_use_context_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_use_context_impl.rs), which forwards each provider-trait method to the consumer trait via `trait_items_to_delegated_impl_items`. Expansion snapshots showing the generated `UseContext` impl appear in [crates/tests/cgp-tests/tests/getters/](../../../crates/tests/cgp-tests/tests/getters/) and [crates/tests/cgp-tests/tests/basic_delegation/](../../../crates/tests/cgp-tests/tests/basic_delegation/). +The struct is defined in [crates/core/cgp-component/src/providers/use_context.rs](../../../crates/core/cgp-component/src/providers/use_context.rs), which also declares the `WithContext` alias. The `UseContext` provider impl is generated by `to_use_context_impl` in [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_use_context_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_use_context_impl.rs), which forwards each provider-trait method to the consumer trait via `trait_items_to_delegated_impl_items`. For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_component](../../implementation/entrypoints/cgp_component.md). diff --git a/docs/reference/providers/use_default.md b/docs/reference/providers/use_default.md index bf25b45d..b20d7349 100644 --- a/docs/reference/providers/use_default.md +++ b/docs/reference/providers/use_default.md @@ -107,4 +107,4 @@ delegate_components! { ## Source -The struct is defined in [crates/core/cgp-component/src/providers/use_default.rs](../../../crates/core/cgp-component/src/providers/use_default.rs) and re-exported in [crates/core/cgp-component/src/providers/mod.rs](../../../crates/core/cgp-component/src/providers/mod.rs); the file contains only the bare struct, with no macro-generated impls. The empty-body `#[cgp_impl]` pattern that wires components to a default-only marker is exercised in [crates/tests/cgp-tests/tests/basic_delegation/](../../../crates/tests/cgp-tests/tests/basic_delegation/). +The struct is defined in [crates/core/cgp-component/src/providers/use_default.rs](../../../crates/core/cgp-component/src/providers/use_default.rs) and re-exported in [crates/core/cgp-component/src/providers/mod.rs](../../../crates/core/cgp-component/src/providers/mod.rs); the file contains only the bare struct, with no macro-generated impls. For how it is generated and the index of tests, see the implementation document [implementation/asts/attributes](../../implementation/asts/attributes.md). diff --git a/docs/reference/providers/use_delegate.md b/docs/reference/providers/use_delegate.md index 0634810c..f7fd5f04 100644 --- a/docs/reference/providers/use_delegate.md +++ b/docs/reference/providers/use_delegate.md @@ -95,4 +95,4 @@ The wiring reads in two layers. `MyApp` delegates `AreaCalculatorComponent` to ` ## Source -The struct is defined in [crates/core/cgp-component/src/providers/use_delegate.rs](../../../crates/core/cgp-component/src/providers/use_delegate.rs). The `UseDelegate` provider impl is generated from the `#[derive_delegate]` directive parsed in [crates/macros/cgp-macro-core/src/types/attributes/](../../../crates/macros/cgp-macro-core/src/types/attributes/) and emitted by the `#[cgp_component]` pipeline in [crates/macros/cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/). The nested-table wiring is handled by `delegate_components!` in [crates/macros/cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/). Behavioral tests exercising `UseDelegate` dispatch live in [crates/tests/cgp-tests/tests/dispatching/](../../../crates/tests/cgp-tests/tests/dispatching/). +The struct is defined in [crates/core/cgp-component/src/providers/use_delegate.rs](../../../crates/core/cgp-component/src/providers/use_delegate.rs). The `UseDelegate` provider impl is generated from the `#[derive_delegate]` directive parsed in [crates/macros/cgp-macro-core/src/types/attributes/](../../../crates/macros/cgp-macro-core/src/types/attributes/) and emitted by the `#[cgp_component]` pipeline in [crates/macros/cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/). The nested-table wiring is handled by `delegate_components!` in [crates/macros/cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/). For how it is generated and the index of tests, see the implementation document [implementation/asts/attributes](../../implementation/asts/attributes.md). diff --git a/docs/reference/providers/use_field.md b/docs/reference/providers/use_field.md index 1e568560..f6777167 100644 --- a/docs/reference/providers/use_field.md +++ b/docs/reference/providers/use_field.md @@ -91,4 +91,4 @@ Both forms read `first_name`; `UseField` is the idiomatic choice for binding a g ## Source -The `UseField` struct, its `WithField` alias, and the `FieldGetter`, `MutFieldGetter`, and `TypeProvider` impls are in [crates/core/cgp-field/src/impls/use_field.rs](../../../crates/core/cgp-field/src/impls/use_field.rs). The `HasField`, `FieldGetter`, and (in `has_field_mut.rs`) `HasFieldMut`, `MutFieldGetter` traits are in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). The `#[cgp_getter]`-generated `UseField` impl is built in [crates/macros/cgp-macro-core/src/types/cgp_getter/use_field.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/use_field.rs). Behavioral and expansion tests are in [crates/tests/cgp-tests/tests/getters/](../../../crates/tests/cgp-tests/tests/getters/). +The `UseField` struct, its `WithField` alias, and the `FieldGetter`, `MutFieldGetter`, and `TypeProvider` impls are in [crates/core/cgp-field/src/impls/use_field.rs](../../../crates/core/cgp-field/src/impls/use_field.rs). The `HasField`, `FieldGetter`, and (in `has_field_mut.rs`) `HasFieldMut`, `MutFieldGetter` traits are in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). The `#[cgp_getter]`-generated `UseField` impl is built in [crates/macros/cgp-macro-core/src/types/cgp_getter/use_field.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/use_field.rs). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_getter](../../implementation/entrypoints/cgp_getter.md). diff --git a/docs/reference/providers/use_fields.md b/docs/reference/providers/use_fields.md index 2efd93f7..f96877cf 100644 --- a/docs/reference/providers/use_fields.md +++ b/docs/reference/providers/use_fields.md @@ -86,4 +86,4 @@ Because `App` wires `FooGetterComponent` to `UseFields`, the generated impl read ## Source -The struct is defined in [crates/core/cgp-component/src/providers/use_fields.rs](../../../crates/core/cgp-component/src/providers/use_fields.rs). The `UseFields` impl is built by `to_use_fields_impl` in [crates/macros/cgp-macro-core/src/types/cgp_getter/to_use_fields_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/to_use_fields_impl.rs), which keys each method on its name via `Symbol::from_ident` and emits a matching `HasField` bound. Expansion snapshots showing the generated `UseFields` impl alongside the `UseField` and `WithProvider` impls are in [crates/tests/cgp-tests/tests/getters/](../../../crates/tests/cgp-tests/tests/getters/). +The struct is defined in [crates/core/cgp-component/src/providers/use_fields.rs](../../../crates/core/cgp-component/src/providers/use_fields.rs). The `UseFields` impl is built by `to_use_fields_impl` in [crates/macros/cgp-macro-core/src/types/cgp_getter/to_use_fields_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/to_use_fields_impl.rs), which keys each method on its name via `Symbol::from_ident` and emits a matching `HasField` bound. For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_getter](../../implementation/entrypoints/cgp_getter.md). diff --git a/docs/reference/providers/use_type.md b/docs/reference/providers/use_type.md index ee190243..ade70ee1 100644 --- a/docs/reference/providers/use_type.md +++ b/docs/reference/providers/use_type.md @@ -96,4 +96,4 @@ Both forms produce the same result — `App::Scalar` is `f64` — which is why ` ## Source -The `UseType` struct, its `WithType` alias, and the built-in `TypeProvider` impl are in [crates/core/cgp-type/src/impls/use_type.rs](../../../crates/core/cgp-type/src/impls/use_type.rs). The `HasType` consumer trait, the `TypeProvider` provider trait, and the `TypeOf` alias are in [crates/core/cgp-type/src/traits/has_type.rs](../../../crates/core/cgp-type/src/traits/has_type.rs). The `#[cgp_type]`-generated `UseType` impl is built in [crates/macros/cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs). Behavioral and expansion tests live in [crates/tests/cgp-tests/tests/abstract_types/](../../../crates/tests/cgp-tests/tests/abstract_types/). +The `UseType` struct, its `WithType` alias, and the built-in `TypeProvider` impl are in [crates/core/cgp-type/src/impls/use_type.rs](../../../crates/core/cgp-type/src/impls/use_type.rs). The `HasType` consumer trait, the `TypeProvider` provider trait, and the `TypeOf` alias are in [crates/core/cgp-type/src/traits/has_type.rs](../../../crates/core/cgp-type/src/traits/has_type.rs). The `#[cgp_type]`-generated `UseType` impl is built in [crates/macros/cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_type](../../implementation/entrypoints/cgp_type.md). diff --git a/docs/reference/providers/with_provider.md b/docs/reference/providers/with_provider.md index 25c405b6..e462c4d7 100644 --- a/docs/reference/providers/with_provider.md +++ b/docs/reference/providers/with_provider.md @@ -93,4 +93,4 @@ delegate_components! { ## Source -The struct is defined in [crates/core/cgp-component/src/providers/with_provider.rs](../../../crates/core/cgp-component/src/providers/with_provider.rs), and the `WithContext` alias in [crates/core/cgp-component/src/providers/use_context.rs](../../../crates/core/cgp-component/src/providers/use_context.rs). The remaining aliases are defined beside their inner providers: `WithType` and `WithDelegatedType` in [crates/core/cgp-type/src/impls/use_type.rs](../../../crates/core/cgp-type/src/impls/use_type.rs) and [use_delegated_type.rs](../../../crates/core/cgp-type/src/impls/use_delegated_type.rs), and `WithField` and `WithFieldRef` in [crates/core/cgp-field/src/impls/use_field.rs](../../../crates/core/cgp-field/src/impls/use_field.rs) and [use_ref.rs](../../../crates/core/cgp-field/src/impls/use_ref.rs). The component `WithProvider` impls are generated by `#[cgp_type]` in [crates/macros/cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs) and by `#[cgp_getter]` in [crates/macros/cgp-macro-core/src/types/cgp_getter/with_provider.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/with_provider.rs). The generated getter `WithProvider` impl is shown in the expansion snapshot in [crates/tests/cgp-tests/tests/getters/](../../../crates/tests/cgp-tests/tests/getters/). +The struct is defined in [crates/core/cgp-component/src/providers/with_provider.rs](../../../crates/core/cgp-component/src/providers/with_provider.rs), and the `WithContext` alias in [crates/core/cgp-component/src/providers/use_context.rs](../../../crates/core/cgp-component/src/providers/use_context.rs). The remaining aliases are defined beside their inner providers: `WithType` and `WithDelegatedType` in [crates/core/cgp-type/src/impls/use_type.rs](../../../crates/core/cgp-type/src/impls/use_type.rs) and [use_delegated_type.rs](../../../crates/core/cgp-type/src/impls/use_delegated_type.rs), and `WithField` and `WithFieldRef` in [crates/core/cgp-field/src/impls/use_field.rs](../../../crates/core/cgp-field/src/impls/use_field.rs) and [use_ref.rs](../../../crates/core/cgp-field/src/impls/use_ref.rs). The component `WithProvider` impls are generated by `#[cgp_type]` in [crates/macros/cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs) and by `#[cgp_getter]` in [crates/macros/cgp-macro-core/src/types/cgp_getter/with_provider.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/with_provider.rs). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_getter](../../implementation/entrypoints/cgp_getter.md). diff --git a/docs/reference/traits/can_use_component.md b/docs/reference/traits/can_use_component.md index 79f0096d..8511e250 100644 --- a/docs/reference/traits/can_use_component.md +++ b/docs/reference/traits/can_use_component.md @@ -95,4 +95,4 @@ where ## Source -The trait and its sole blanket impl are defined in [crates/core/cgp-component/src/traits/can_use_component.rs](../../../crates/core/cgp-component/src/traits/can_use_component.rs) and re-exported through [crates/core/cgp-component/src/macro_prelude.rs](../../../crates/core/cgp-component/src/macro_prelude.rs). The checks that assert it are generated by `check_components!`, whose codegen lives in [crates/macros/cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/) — `table.rs` chooses `CanUseComponent` versus `IsProviderFor` as the check trait's supertrait. Expansion snapshots are in [crates/tests/cgp-tests/tests/checking/](../../../crates/tests/cgp-tests/tests/checking/) and [crates/tests/cgp-tests/tests/namespaces/](../../../crates/tests/cgp-tests/tests/namespaces/). +The trait and its sole blanket impl are defined in [crates/core/cgp-component/src/traits/can_use_component.rs](../../../crates/core/cgp-component/src/traits/can_use_component.rs) and re-exported through [crates/core/cgp-component/src/macro_prelude.rs](../../../crates/core/cgp-component/src/macro_prelude.rs). The checks that assert it are generated by `check_components!`, whose codegen lives in [crates/macros/cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/) — `table.rs` chooses `CanUseComponent` versus `IsProviderFor` as the check trait's supertrait. For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/check_components.md](../../implementation/entrypoints/check_components.md). diff --git a/docs/reference/traits/cast.md b/docs/reference/traits/cast.md index 9898543e..818deac4 100644 --- a/docs/reference/traits/cast.md +++ b/docs/reference/traits/cast.md @@ -105,4 +105,4 @@ The casting traits sit on top of the extensible-data primitives: variant casts r ## Source -`CanUpcast`, `CanDowncast`, and `CanDowncastFields`, together with the internal `FieldsExtractor` recursion that drives them, are defined in [crates/core/cgp-field/src/impls/cast.rs](../../../crates/core/cgp-field/src/impls/cast.rs). `CanBuildFrom` and its internal `FieldsBuilder` recursion are in [crates/core/cgp-field/src/impls/build_from.rs](../../../crates/core/cgp-field/src/impls/build_from.rs). The underlying extractor and builder traits are under [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/) (`extract_field.rs`, `from_variant.rs`, `has_builder.rs`). End-to-end tests of upcasting, downcasting, and building-from live in the extensible-data suites under [crates/tests/cgp-tests/tests/extensible_records/](../../../crates/tests/cgp-tests/tests/extensible_records/) and [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/). +`CanUpcast`, `CanDowncast`, and `CanDowncastFields`, together with the internal `FieldsExtractor` recursion that drives them, are defined in [crates/core/cgp-field/src/impls/cast.rs](../../../crates/core/cgp-field/src/impls/cast.rs). `CanBuildFrom` and its internal `FieldsBuilder` recursion are in [crates/core/cgp-field/src/impls/build_from.rs](../../../crates/core/cgp-field/src/impls/build_from.rs). The underlying extractor and builder traits are under [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/) (`extract_field.rs`, `from_variant.rs`, `has_builder.rs`). diff --git a/docs/reference/traits/default_namespace.md b/docs/reference/traits/default_namespace.md index 2a9b0d6f..a294bdec 100644 --- a/docs/reference/traits/default_namespace.md +++ b/docs/reference/traits/default_namespace.md @@ -98,4 +98,4 @@ Pointing a `for in DefaultShowComponents { … }` loop at this nam ## Source -The three traits are defined in [crates/core/cgp-component/src/namespaces.rs](../../../crates/core/cgp-component/src/namespaces.rs), with `DefaultNamespace` re-exported through [crates/core/cgp-component/src/macro_prelude.rs](../../../crates/core/cgp-component/src/macro_prelude.rs). The namespace macro that builds the namespace trait and its inheritance impl lives in [crates/macros/cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/); the `#[default_impl(... in DefaultImpls1<...>)]` attribute that registers a per-type default is parsed and lowered in [crates/macros/cgp-macro-core/src/types/attributes/default_impl/](../../../crates/macros/cgp-macro-core/src/types/attributes/default_impl/). The `namespace` header and `for … in` loop are handled by the `delegate_components!` codegen in [crates/macros/cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/). Expansion snapshots covering `DefaultNamespace`, `DefaultImpls1`, the `for … in` loop, and namespace inheritance are in [crates/tests/cgp-tests/tests/namespaces/](../../../crates/tests/cgp-tests/tests/namespaces/). +The three traits are defined in [crates/core/cgp-component/src/namespaces.rs](../../../crates/core/cgp-component/src/namespaces.rs), with `DefaultNamespace` re-exported through [crates/core/cgp-component/src/macro_prelude.rs](../../../crates/core/cgp-component/src/macro_prelude.rs). The namespace macro that builds the namespace trait and its inheritance impl lives in [crates/macros/cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/); the `#[default_impl(... in DefaultImpls1<...>)]` attribute that registers a per-type default is parsed and lowered in [crates/macros/cgp-macro-core/src/types/attributes/default_impl/](../../../crates/macros/cgp-macro-core/src/types/attributes/default_impl/). The `namespace` header and `for … in` loop are handled by the `delegate_components!` codegen in [crates/macros/cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_namespace.md](../../implementation/entrypoints/cgp_namespace.md). diff --git a/docs/reference/traits/delegate_component.md b/docs/reference/traits/delegate_component.md index 1be42df1..fd80712c 100644 --- a/docs/reference/traits/delegate_component.md +++ b/docs/reference/traits/delegate_component.md @@ -108,4 +108,4 @@ The bound `AreaComponents: DelegateComponent` is the "get", and `>::Output; ## Source -`StaticFormat` and its `Chars`/`Nil` impls are defined in [crates/core/cgp-base-types/src/traits/static_format.rs](../../../crates/core/cgp-base-types/src/traits/static_format.rs); the `Display` impls that delegate to it are on the [`Chars`](../types/chars.md) and [`Symbol`](../macros/symbol.md) types in [crates/core/cgp-base-types/src/types/](../../../crates/core/cgp-base-types/src/types/). `StaticString`, with its const-evaluated UTF-8 decoding, is in [crates/core/cgp-field/src/traits/static_string.rs](../../../crates/core/cgp-field/src/traits/static_string.rs). `ConcatPath` is in [crates/core/cgp-base-types/src/traits/concat_path.rs](../../../crates/core/cgp-base-types/src/traits/concat_path.rs), and `PathCons` in [crates/core/cgp-base-types/src/types/path.rs](../../../crates/core/cgp-base-types/src/types/path.rs). Tests covering display round-tripping and const decoding of multi-byte strings are in [crates/tests/cgp-tests/tests/field_access/](../../../crates/tests/cgp-tests/tests/field_access/). +`StaticFormat` and its `Chars`/`Nil` impls are defined in [crates/core/cgp-base-types/src/traits/static_format.rs](../../../crates/core/cgp-base-types/src/traits/static_format.rs); the `Display` impls that delegate to it are on the [`Chars`](../types/chars.md) and [`Symbol`](../macros/symbol.md) types in [crates/core/cgp-base-types/src/types/](../../../crates/core/cgp-base-types/src/types/). `StaticString`, with its const-evaluated UTF-8 decoding, is in [crates/core/cgp-field/src/traits/static_string.rs](../../../crates/core/cgp-field/src/traits/static_string.rs). `ConcatPath` is in [crates/core/cgp-base-types/src/traits/concat_path.rs](../../../crates/core/cgp-base-types/src/traits/concat_path.rs), and `PathCons` in [crates/core/cgp-base-types/src/types/path.rs](../../../crates/core/cgp-base-types/src/types/path.rs). diff --git a/docs/reference/types/chars.md b/docs/reference/types/chars.md index 2406b2a5..25b82559 100644 --- a/docs/reference/types/chars.md +++ b/docs/reference/types/chars.md @@ -71,4 +71,4 @@ Because the encoding is a list, an empty string is `Symbol<0, Nil>` — a `Symbo ## Source -The runtime types are defined in [crates/core/cgp-base-types/src/types/chars.rs](../../../crates/core/cgp-base-types/src/types/chars.rs) (`Chars`) and [crates/core/cgp-base-types/src/types/symbol.rs](../../../crates/core/cgp-base-types/src/types/symbol.rs) (`Symbol`), with `Nil` in [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs). The `StaticFormat` impls that drive `Display` are in [crates/core/cgp-base-types/src/traits/static_format.rs](../../../crates/core/cgp-base-types/src/traits/static_format.rs), and the const-decoding `StaticString` impl that consumes `LEN` is in [crates/core/cgp-field/src/traits/static_string.rs](../../../crates/core/cgp-field/src/traits/static_string.rs). The constructing macro is [`Symbol!`](../macros/symbol.md). Tests covering display round-tripping and multi-byte strings are in [crates/tests/cgp-tests/tests/field_access/](../../../crates/tests/cgp-tests/tests/field_access/). +The runtime types are defined in [crates/core/cgp-base-types/src/types/chars.rs](../../../crates/core/cgp-base-types/src/types/chars.rs) (`Chars`) and [crates/core/cgp-base-types/src/types/symbol.rs](../../../crates/core/cgp-base-types/src/types/symbol.rs) (`Symbol`), with `Nil` in [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs). The `StaticFormat` impls that drive `Display` are in [crates/core/cgp-base-types/src/traits/static_format.rs](../../../crates/core/cgp-base-types/src/traits/static_format.rs), and the const-decoding `StaticString` impl that consumes `LEN` is in [crates/core/cgp-field/src/traits/static_string.rs](../../../crates/core/cgp-field/src/traits/static_string.rs). The constructing macro is [`Symbol!`](../macros/symbol.md). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/symbol.md](../../implementation/entrypoints/symbol.md). diff --git a/docs/reference/types/life.md b/docs/reference/types/life.md index 2d644066..c23156a1 100644 --- a/docs/reference/types/life.md +++ b/docs/reference/types/life.md @@ -54,4 +54,4 @@ Every impl that wires this component — whether through `UseContext`, a `UseFie ## Source -The type is defined in [crates/core/cgp-field/src/types/life.rs](../../../crates/core/cgp-field/src/types/life.rs). The macro logic that wraps a trait's lifetime parameters in `Life` when building the `IsProviderFor` argument tuple is in [crates/macros/cgp-macro-core/src/functions/is_provider_params.rs](../../../crates/macros/cgp-macro-core/src/functions/is_provider_params.rs), with related placement in [crates/macros/cgp-macro-core/src/types/empty_struct.rs](../../../crates/macros/cgp-macro-core/src/types/empty_struct.rs) and [crates/macros/cgp-macro-core/src/types/cgp_provider/provider_impl_args.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/provider_impl_args.rs). The generated wiring for a lifetime-carrying component is exercised by the snapshot tests in [crates/tests/cgp-tests/tests/generic_components/](../../../crates/tests/cgp-tests/tests/generic_components/). +The type is defined in [crates/core/cgp-field/src/types/life.rs](../../../crates/core/cgp-field/src/types/life.rs). The macro logic that wraps a trait's lifetime parameters in `Life` when building the `IsProviderFor` argument tuple is in [crates/macros/cgp-macro-core/src/functions/is_provider_params.rs](../../../crates/macros/cgp-macro-core/src/functions/is_provider_params.rs), with related placement in [crates/macros/cgp-macro-core/src/types/empty_struct.rs](../../../crates/macros/cgp-macro-core/src/types/empty_struct.rs) and [crates/macros/cgp-macro-core/src/types/cgp_provider/provider_impl_args.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/provider_impl_args.rs). For how it is generated and the index of tests, see the implementation document [implementation/functions/parse/is_provider_params.md](../../implementation/functions/parse/is_provider_params.md). From 167b3a74f788b4d31ae76415508e27ab75c4d85c Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 2 Jul 2026 01:32:21 +0200 Subject: [PATCH 3/3] Use bullet points for source and tests sections --- docs/CLAUDE.md | 2 +- docs/implementation/CLAUDE.md | 2 ++ docs/implementation/asts/attributes.md | 5 ++++- docs/implementation/asts/blanket_trait.md | 3 ++- docs/implementation/asts/cgp_component.md | 3 ++- docs/implementation/asts/cgp_data.md | 8 ++++++-- docs/implementation/asts/cgp_fn.md | 7 +++++-- docs/implementation/asts/cgp_getter.md | 7 +++++-- docs/implementation/asts/cgp_impl.md | 4 +++- docs/implementation/asts/cgp_provider.md | 4 +++- docs/implementation/asts/cgp_type.md | 4 +++- docs/implementation/asts/check_components.md | 7 +++++-- docs/implementation/asts/delegate_component.md | 6 ++++-- docs/implementation/asts/namespace.md | 4 +++- docs/implementation/asts/path.md | 3 ++- docs/implementation/asts/product.md | 3 ++- docs/implementation/asts/sum.md | 3 ++- docs/implementation/asts/symbol.md | 3 ++- docs/implementation/entrypoints/async_trait.md | 5 ++++- docs/implementation/entrypoints/blanket_trait.md | 10 ++++++++-- .../implementation/entrypoints/cgp_auto_dispatch.md | 4 +++- docs/implementation/entrypoints/cgp_auto_getter.md | 5 ++++- docs/implementation/entrypoints/cgp_component.md | 6 +++++- docs/implementation/entrypoints/cgp_computer.md | 5 ++++- docs/implementation/entrypoints/cgp_fn.md | 7 ++++++- docs/implementation/entrypoints/cgp_getter.md | 6 +++++- docs/implementation/entrypoints/cgp_impl.md | 5 ++++- docs/implementation/entrypoints/cgp_namespace.md | 6 +++++- docs/implementation/entrypoints/cgp_new_provider.md | 4 +++- docs/implementation/entrypoints/cgp_producer.md | 4 +++- docs/implementation/entrypoints/cgp_provider.md | 6 +++++- docs/implementation/entrypoints/cgp_type.md | 7 ++++++- docs/implementation/entrypoints/check_components.md | 11 +++++++++-- .../entrypoints/delegate_and_check_components.md | 8 ++++++-- .../entrypoints/delegate_components.md | 6 +++++- .../entrypoints/derive_build_field.md | 10 ++++++++-- docs/implementation/entrypoints/derive_cgp_data.md | 13 +++++++++++-- .../implementation/entrypoints/derive_cgp_record.md | 8 ++++++-- .../entrypoints/derive_cgp_variant.md | 8 ++++++-- .../entrypoints/derive_extract_field.md | 11 +++++++++-- .../entrypoints/derive_from_variant.md | 9 +++++++-- docs/implementation/entrypoints/derive_has_field.md | 4 +++- .../implementation/entrypoints/derive_has_fields.md | 10 ++++++++-- docs/implementation/entrypoints/path.md | 5 ++++- docs/implementation/entrypoints/product.md | 5 ++++- docs/implementation/entrypoints/snapshot_macros.md | 7 ++++++- docs/implementation/entrypoints/sum.md | 5 ++++- docs/implementation/entrypoints/symbol.md | 4 +++- .../functions/derive/delegated_impls.md | 9 +++++++-- docs/implementation/functions/derive/generics.md | 4 ++-- docs/implementation/functions/derive/idents.md | 4 ++-- .../functions/parse/is_provider_params.md | 9 +++++++-- docs/implementation/macros/define_keyword.md | 5 +++-- docs/implementation/macros/export_constructs.md | 5 +++-- docs/implementation/macros/parse_internal.md | 6 ++++-- docs/reference/attributes/derive_delegate.md | 8 +++++--- docs/reference/attributes/extend.md | 7 ++++--- docs/reference/attributes/extend_where.md | 6 +++--- docs/reference/attributes/implicit.md | 7 ++++--- docs/reference/attributes/use_provider.md | 7 ++++--- docs/reference/attributes/use_type.md | 8 +++++--- docs/reference/attributes/uses.md | 7 ++++--- docs/reference/components/can_raise_error.md | 4 +++- docs/reference/components/computer.md | 5 ++++- docs/reference/components/handler.md | 4 +++- docs/reference/components/has_error_type.md | 4 +++- docs/reference/components/has_runtime.md | 4 +++- docs/reference/components/has_type.md | 5 ++++- docs/reference/components/producer.md | 5 ++++- docs/reference/components/runner.md | 3 ++- docs/reference/components/try_computer.md | 5 ++++- docs/reference/derives/derive_build_field.md | 7 ++++--- docs/reference/derives/derive_cgp_data.md | 7 ++++--- docs/reference/derives/derive_cgp_record.md | 7 ++++--- docs/reference/derives/derive_cgp_variant.md | 7 ++++--- docs/reference/derives/derive_extract_field.md | 7 ++++--- docs/reference/derives/derive_from_variant.md | 7 ++++--- docs/reference/derives/derive_has_field.md | 7 ++++--- docs/reference/derives/derive_has_fields.md | 7 ++++--- docs/reference/macros/async_trait.md | 7 ++++--- docs/reference/macros/blanket_trait.md | 7 ++++--- docs/reference/macros/cgp_auto_dispatch.md | 6 +++--- docs/reference/macros/cgp_auto_getter.md | 7 ++++--- docs/reference/macros/cgp_component.md | 7 ++++--- docs/reference/macros/cgp_computer.md | 7 ++++--- docs/reference/macros/cgp_fn.md | 7 ++++--- docs/reference/macros/cgp_getter.md | 7 ++++--- docs/reference/macros/cgp_impl.md | 7 ++++--- docs/reference/macros/cgp_namespace.md | 8 +++++--- docs/reference/macros/cgp_new_provider.md | 6 +++--- docs/reference/macros/cgp_producer.md | 6 +++--- docs/reference/macros/cgp_provider.md | 7 ++++--- docs/reference/macros/cgp_type.md | 7 ++++--- docs/reference/macros/check_components.md | 6 +++--- .../macros/delegate_and_check_components.md | 7 ++++--- docs/reference/macros/delegate_components.md | 7 ++++--- docs/reference/macros/path.md | 7 ++++--- docs/reference/macros/product.md | 8 +++++--- docs/reference/macros/sum.md | 7 ++++--- docs/reference/macros/symbol.md | 6 +++--- docs/reference/providers/chain_getters.md | 4 +++- docs/reference/providers/dispatch_combinators.md | 3 ++- docs/reference/providers/error_providers.md | 4 +++- docs/reference/providers/handler_combinators.md | 3 ++- docs/reference/providers/monad_providers.md | 3 ++- docs/reference/providers/redirect_lookup.md | 5 ++++- docs/reference/providers/use_context.md | 4 +++- docs/reference/providers/use_default.md | 3 ++- docs/reference/providers/use_delegate.md | 5 ++++- docs/reference/providers/use_delegated_type.md | 3 ++- docs/reference/providers/use_field.md | 5 ++++- docs/reference/providers/use_field_ref.md | 3 ++- docs/reference/providers/use_fields.md | 4 +++- docs/reference/providers/use_type.md | 5 ++++- docs/reference/providers/with_provider.md | 5 ++++- docs/reference/traits/can_use_component.md | 4 +++- docs/reference/traits/cast.md | 4 +++- docs/reference/traits/default_namespace.md | 5 ++++- docs/reference/traits/delegate_component.md | 5 ++++- docs/reference/traits/extract_field.md | 4 +++- docs/reference/traits/from_variant.md | 4 +++- docs/reference/traits/has_builder.md | 4 +++- docs/reference/traits/has_field.md | 5 ++++- docs/reference/traits/has_fields.md | 5 ++++- docs/reference/traits/is_provider_for.md | 4 +++- docs/reference/traits/map_type.md | 5 ++++- docs/reference/traits/monad.md | 3 ++- docs/reference/traits/optional_fields.md | 3 ++- docs/reference/traits/product_ops.md | 3 ++- docs/reference/traits/static_format.md | 4 +++- docs/reference/types/chars.md | 5 ++++- docs/reference/types/cons.md | 3 ++- docs/reference/types/either.md | 4 +++- docs/reference/types/field.md | 4 +++- docs/reference/types/index.md | 3 ++- docs/reference/types/life.md | 4 +++- docs/reference/types/mref.md | 3 ++- docs/reference/types/path_cons.md | 5 ++++- 138 files changed, 534 insertions(+), 231 deletions(-) diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md index fc72349a..a70936e9 100644 --- a/docs/CLAUDE.md +++ b/docs/CLAUDE.md @@ -63,7 +63,7 @@ Each reference document follows the same shape so readers can navigate any of th - **Examples** — at least one realistic, self-contained example showing the construct in use. - **Related constructs** — links to the reference documents for constructs commonly used with this one, with a phrase explaining each relationship. - **Known issues** — optional; present only when the construct has corner cases, surprising behavior, or open bugs worth warning a reader about. Omit the heading entirely when there is nothing to record. See the review workflow below for what belongs here. -- **Source** — pointers to the implementing modules in `cgp-macro-core` and `cgp-macro-lib`, and a link to the construct's implementation document under [implementation/](implementation/README.md), so a reader can drop from prose into the code and its internal walkthrough. A reference document never points at a test file; all test pointers live in the implementation document instead. +- **Source** — pointers to the implementing modules in `cgp-macro-core` and `cgp-macro-lib`, and a link to the construct's implementation document under [implementation/](implementation/README.md), so a reader can drop from prose into the code and its internal walkthrough. A reference document never points at a test file; all test pointers live in the implementation document instead. Write this section as a bullet list — one pointer per bullet — rather than a flowing paragraph; a short lead-in sentence is optional, but each source pointer is its own bullet. Place each document in the subdirectory that matches what the construct is. The reference is organized into `macros/` (procedural macros a programmer invokes, including the type-level construction macros), `derives/` (the `#[derive(...)]` family), `attributes/` (modifier attributes consumed by a host macro), `components/` (the built-in CGP components — consumer/provider trait pairs defined with `#[cgp_component]`/`#[cgp_type]`/`#[cgp_getter]`), `providers/` (the zero-sized provider structs a context delegates to), `traits/` (capability and mechanism traits that are *not* themselves components), and `types/` (the type-level building-block types). A trait belongs in `components/` rather than `traits/` precisely when it is a CGP component with a generated provider trait and `…Component` marker. The high-level conceptual overviews that tie several constructs together are not per-construct reference documents; they live in the sibling top-level [concepts/](concepts/) directory and are cataloged in the [concepts index](concepts/README.md). The [reference index](reference/README.md) describes the reference layout in full and is the catalog you register a new reference document in. Because documents live in different subdirectories, a cross-link between two of them is a relative path — a sibling in the same directory is `name.md`, and a document in another directory is `../that-dir/name.md`. diff --git a/docs/implementation/CLAUDE.md b/docs/implementation/CLAUDE.md index 4beae161..a9ecfaa1 100644 --- a/docs/implementation/CLAUDE.md +++ b/docs/implementation/CLAUDE.md @@ -50,6 +50,8 @@ Use code snippets to make specific behavior concrete. When you describe how inpu When a section lists many items one at a time — the tests, the snapshots, a set of accepted keys — use a bullet list rather than framed prose. The dual-reader topic-sentence style governs the explanatory prose, not these enumerations: introduce the list with a short sentence and let the bullets carry the items. +The **Tests** and **Source** sections are always bullet lists, never flowing paragraphs — one test (or snapshot) per bullet, and one source pointer per bullet. A short lead-in sentence before the bullets is allowed (and is the norm for Tests), but the items themselves must be bullets so a reader can scan a construct's coverage and its code locations at a glance. + ## The Tests and Snapshots sections Every document links its related tests in a **Tests** section, stating the behavior each test pins in the document's own words. List the behavioral tests in [crates/tests/cgp-tests](../../crates/tests/cgp-tests) and the failure cases in [crates/tests/cgp-macro-tests](../../crates/tests/cgp-macro-tests) that exercise the construct, each as a link to the file with a one-line description of what it verifies. Because the reference documents no longer point at tests, this section is the canonical index of a construct's coverage — write it so an agent can see at a glance what behavior is guarded and, by omission, what is not. diff --git a/docs/implementation/asts/attributes.md b/docs/implementation/asts/attributes.md index 28697be1..94c9cc33 100644 --- a/docs/implementation/asts/attributes.md +++ b/docs/implementation/asts/attributes.md @@ -82,4 +82,7 @@ The behavioral and snapshot tests that exercise each modifier are listed per att ## Source -The modifiers live in [cgp-macro-core/src/types/attributes/](../../../crates/macros/cgp-macro-core/src/types/attributes/): `uses.rs` (`UsesAttributes`), the `use_type/` submodule (`UseTypeAttribute`, per-type entries in `ident.rs`, the two-phase transform in `attributes.rs`, and predicate derivation in `type_predicates.rs`), the `use_provider/` submodule (`UseProviderAttribute` and its bound completion), the `derive_delegate/` submodule (`DeriveDelegateAttribute::to_provider_impl`), and the `default_impl/` submodule (`DefaultImplAttribute::to_item_impl`). `#[extend]`/`#[extend_where]` are fields of `FunctionAttributes` in `function.rs`. The host collectors are `CgpComponentAttributes` in `cgp_component_attributes.rs`, `CgpImplAttributes` in `cgp_impl_attributes.rs`, and `FunctionAttributes` in `function.rs`. The abstract-type substitution is the `SubstituteAbstractType` visitor in [cgp-macro-core/src/visitors/substitute_abstract_type.rs](../../../crates/macros/cgp-macro-core/src/visitors/substitute_abstract_type.rs), and the `#[derive_delegate]` forwarding bodies come from the [delegated-impl helpers](../functions/derive/delegated_impls.md). +- The modifiers live in [cgp-macro-core/src/types/attributes/](../../../crates/macros/cgp-macro-core/src/types/attributes/): `uses.rs` (`UsesAttributes`), the `use_type/` submodule (`UseTypeAttribute`, per-type entries in `ident.rs`, the two-phase transform in `attributes.rs`, and predicate derivation in `type_predicates.rs`), the `use_provider/` submodule (`UseProviderAttribute` and its bound completion), the `derive_delegate/` submodule (`DeriveDelegateAttribute::to_provider_impl`), and the `default_impl/` submodule (`DefaultImplAttribute::to_item_impl`). +- `#[extend]`/`#[extend_where]` are fields of `FunctionAttributes` in `function.rs`. +- The host collectors are `CgpComponentAttributes` in `cgp_component_attributes.rs`, `CgpImplAttributes` in `cgp_impl_attributes.rs`, and `FunctionAttributes` in `function.rs`. +- The abstract-type substitution is the `SubstituteAbstractType` visitor in [cgp-macro-core/src/visitors/substitute_abstract_type.rs](../../../crates/macros/cgp-macro-core/src/visitors/substitute_abstract_type.rs), and the `#[derive_delegate]` forwarding bodies come from the [delegated-impl helpers](../functions/derive/delegated_impls.md). diff --git a/docs/implementation/asts/blanket_trait.md b/docs/implementation/asts/blanket_trait.md index dcd5c09f..3c108473 100644 --- a/docs/implementation/asts/blanket_trait.md +++ b/docs/implementation/asts/blanket_trait.md @@ -21,4 +21,5 @@ It then assembles the impl generics — the trait's own generics, plus the conte ## Source -`ItemBlanketTrait` lives in [cgp-macro-core/src/types/blanket_trait.rs](../../../crates/macros/cgp-macro-core/src/types/blanket_trait.rs). The `Self::`-to-parameter rewriting is done by `RemoveSelfPathVisitor` in [cgp-macro-core/src/visitors/remove_self_path.rs](../../../crates/macros/cgp-macro-core/src/visitors/remove_self_path.rs). +- `ItemBlanketTrait` lives in [cgp-macro-core/src/types/blanket_trait.rs](../../../crates/macros/cgp-macro-core/src/types/blanket_trait.rs). +- The `Self::`-to-parameter rewriting is done by `RemoveSelfPathVisitor` in [cgp-macro-core/src/visitors/remove_self_path.rs](../../../crates/macros/cgp-macro-core/src/visitors/remove_self_path.rs). diff --git a/docs/implementation/asts/cgp_component.md b/docs/implementation/asts/cgp_component.md index 19cdd393..545aeb29 100644 --- a/docs/implementation/asts/cgp_component.md +++ b/docs/implementation/asts/cgp_component.md @@ -34,4 +34,5 @@ The attribute argument is parsed in two steps so that parsing and defaulting sta ## Source -The stack lives in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/): the argument types in `args/`, `ItemCgpComponent` in `item.rs`, `PreprocessedCgpComponent` in `preprocessed/`, and `EvaluatedCgpComponent` in `evaluated/`. The `self`/`Self` rewriting is done by the visitors in [cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). +- The stack lives in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/): the argument types in `args/`, `ItemCgpComponent` in `item.rs`, `PreprocessedCgpComponent` in `preprocessed/`, and `EvaluatedCgpComponent` in `evaluated/`. +- The `self`/`Self` rewriting is done by the visitors in [cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). diff --git a/docs/implementation/asts/cgp_data.md b/docs/implementation/asts/cgp_data.md index eeb1d7d4..f313f84c 100644 --- a/docs/implementation/asts/cgp_data.md +++ b/docs/implementation/asts/cgp_data.md @@ -45,8 +45,12 @@ Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>> Index<0> ## Tests -The stack has no parser-rejection tests of its own in `cgp-macro-tests`; the shape errors it raises (a non-struct/non-enum for `CgpData`, a non-struct for the record derives, a non-enum for the variant derives, and a non-single-field variant for the extractor and `FromVariant`) surface at `syn::parse2` or in the codegen helpers and are exercised only implicitly. The stage transforms are exercised end-to-end by the expansion snapshots indexed in the entrypoint documents' Snapshots sections — the [`snapshot_derive_has_field`](../entrypoints/derive_has_field.md#snapshots), [`snapshot_derive_has_fields`](../entrypoints/derive_has_fields.md#snapshots), and [`snapshot_derive_cgp_data`](../entrypoints/derive_cgp_data.md#snapshots) families. +- The stack has no parser-rejection tests of its own in `cgp-macro-tests`; the shape errors it raises (a non-struct/non-enum for `CgpData`, a non-struct for the record derives, a non-enum for the variant derives, and a non-single-field variant for the extractor and `FromVariant`) surface at `syn::parse2` or in the codegen helpers and are exercised only implicitly. +- The stage transforms are exercised end-to-end by the expansion snapshots indexed in the entrypoint documents' Snapshots sections — the [`snapshot_derive_has_field`](../entrypoints/derive_has_field.md#snapshots), [`snapshot_derive_has_fields`](../entrypoints/derive_has_fields.md#snapshots), and [`snapshot_derive_cgp_data`](../entrypoints/derive_cgp_data.md#snapshots) families. ## Source -The stack lives in [crates/macros/cgp-macro-core/src/types/cgp_data/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/): `ItemCgpData` in `item.rs`, `ItemCgpRecord` in `record.rs`, and `ItemCgpVariant` in `variant.rs`. The record codegen helpers are under `derive_has_field.rs`, `derive_has_fields/`, and `derive_builder/`; the variant codegen helpers under `derive_has_fields/`, `derive_from_variant.rs`, and `derive_extractor/`. The field-tag types are in [crates/macros/cgp-macro-core/src/types/field/](../../../crates/macros/cgp-macro-core/src/types/field/): `Symbol` in `symbol.rs`, `Index` in `index.rs`, `FieldName` in `field_name.rs`, and `HasFieldBound` in `has_field_bound.rs`. The runtime traits these impls satisfy are defined in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). +- The stack lives in [crates/macros/cgp-macro-core/src/types/cgp_data/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/): `ItemCgpData` in `item.rs`, `ItemCgpRecord` in `record.rs`, and `ItemCgpVariant` in `variant.rs`. +- The record codegen helpers are under `derive_has_field.rs`, `derive_has_fields/`, and `derive_builder/`; the variant codegen helpers under `derive_has_fields/`, `derive_from_variant.rs`, and `derive_extractor/`. +- The field-tag types are in [crates/macros/cgp-macro-core/src/types/field/](../../../crates/macros/cgp-macro-core/src/types/field/): `Symbol` in `symbol.rs`, `Index` in `index.rs`, `FieldName` in `field_name.rs`, and `HasFieldBound` in `has_field_bound.rs`. +- The runtime traits these impls satisfy are defined in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). diff --git a/docs/implementation/asts/cgp_fn.md b/docs/implementation/asts/cgp_fn.md index 578e189b..c9078dd5 100644 --- a/docs/implementation/asts/cgp_fn.md +++ b/docs/implementation/asts/cgp_fn.md @@ -31,8 +31,11 @@ let name: &str = self.get_field(PhantomData::).as_str(); ## Tests -The stage transforms are exercised end-to-end by the expansion snapshots indexed in the [entrypoint document's Snapshots section](../entrypoints/cgp_fn.md); there is no separate parser-rejection test file for `#[cgp_fn]` in `cgp-macro-tests`. The `&mut self`-with-multiple-implicits rejection and the mutable-pattern rejection enforced during extraction are currently unpinned by any test. +- The stage transforms are exercised end-to-end by the expansion snapshots indexed in the [entrypoint document's Snapshots section](../entrypoints/cgp_fn.md); there is no separate parser-rejection test file for `#[cgp_fn]` in `cgp-macro-tests`. +- The `&mut self`-with-multiple-implicits rejection and the mutable-pattern rejection enforced during extraction are currently unpinned by any test. ## Source -The stack lives in [cgp-macro-core/src/types/cgp_fn/](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/): `ItemCgpFn` and its `preprocess` in `item.rs`, `PreprocessedItemCgpFn` and its `to_item_trait`/`to_item_impl` in `preprocessed.rs`. The implicit-argument types are in [cgp-macro-core/src/types/implicits/](../../../crates/macros/cgp-macro-core/src/types/implicits/) and their extraction in [cgp-macro-core/src/functions/implicits/](../../../crates/macros/cgp-macro-core/src/functions/implicits/); the field-mode conversion (`parse_field_type`) is in [cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), shared with the getter stack in [asts/cgp_getter.md](cgp_getter.md). Companion-attribute parsing is in [cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs). +- The stack lives in [cgp-macro-core/src/types/cgp_fn/](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/): `ItemCgpFn` and its `preprocess` in `item.rs`, `PreprocessedItemCgpFn` and its `to_item_trait`/`to_item_impl` in `preprocessed.rs`. +- The implicit-argument types are in [cgp-macro-core/src/types/implicits/](../../../crates/macros/cgp-macro-core/src/types/implicits/) and their extraction in [cgp-macro-core/src/functions/implicits/](../../../crates/macros/cgp-macro-core/src/functions/implicits/); the field-mode conversion (`parse_field_type`) is in [cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), shared with the getter stack in [asts/cgp_getter.md](cgp_getter.md). +- Companion-attribute parsing is in [cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs). diff --git a/docs/implementation/asts/cgp_getter.md b/docs/implementation/asts/cgp_getter.md index b5e26640..edcb5f35 100644 --- a/docs/implementation/asts/cgp_getter.md +++ b/docs/implementation/asts/cgp_getter.md @@ -30,8 +30,11 @@ Each of these threads the optional associated type through as an extra generic p ## Tests -The stage transforms are exercised end-to-end by the expansion snapshots indexed in the two entrypoint documents' Snapshots sections — the [`#[cgp_getter]` snapshots](../entrypoints/cgp_getter.md) and the [`#[cgp_auto_getter]` snapshots](../entrypoints/cgp_auto_getter.md). There is no separate parser-rejection test file for either macro in `cgp-macro-tests`; the getter-method contract checks in `parse_getter_fields` (rejecting const/async/unsafe/generic getters, a bad receiver, or multiple associated types) are currently unpinned by dedicated failure cases. +- The stage transforms are exercised end-to-end by the expansion snapshots indexed in the two entrypoint documents' Snapshots sections — the [`#[cgp_getter]` snapshots](../entrypoints/cgp_getter.md) and the [`#[cgp_auto_getter]` snapshots](../entrypoints/cgp_auto_getter.md). +- There is no separate parser-rejection test file for either macro in `cgp-macro-tests`; the getter-method contract checks in `parse_getter_fields` (rejecting const/async/unsafe/generic getters, a bad receiver, or multiple associated types) are currently unpinned by dedicated failure cases. ## Source -The auto-getter stack lives in [cgp-macro-core/src/types/cgp_auto_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_auto_getter/) (`item.rs`, `blanket.rs`), driven by [cgp-macro-lib/src/cgp_auto_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs) and documented in [entrypoints/cgp_auto_getter.md](../entrypoints/cgp_auto_getter.md). The full-getter stack lives in [cgp-macro-core/src/types/cgp_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/) (`item.rs`, `getter_field.rs`, `to_use_fields_impl.rs`, `use_field.rs`, `with_provider.rs`), driven by [cgp-macro-lib/src/cgp_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_getter.rs) and documented in [entrypoints/cgp_getter.md](../entrypoints/cgp_getter.md); it reuses the [`cgp_component` stack](cgp_component.md). The shared getter-field parser is in [cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs), the field-mode conversion in [cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), and the field-mode and getter-method emit types in [cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/). +- The auto-getter stack lives in [cgp-macro-core/src/types/cgp_auto_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_auto_getter/) (`item.rs`, `blanket.rs`), driven by [cgp-macro-lib/src/cgp_auto_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs) and documented in [entrypoints/cgp_auto_getter.md](../entrypoints/cgp_auto_getter.md). +- The full-getter stack lives in [cgp-macro-core/src/types/cgp_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/) (`item.rs`, `getter_field.rs`, `to_use_fields_impl.rs`, `use_field.rs`, `with_provider.rs`), driven by [cgp-macro-lib/src/cgp_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_getter.rs) and documented in [entrypoints/cgp_getter.md](../entrypoints/cgp_getter.md); it reuses the [`cgp_component` stack](cgp_component.md). +- The shared getter-field parser is in [cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs), the field-mode conversion in [cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), and the field-mode and getter-method emit types in [cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/). diff --git a/docs/implementation/asts/cgp_impl.md b/docs/implementation/asts/cgp_impl.md index 33f9771a..d0829ef1 100644 --- a/docs/implementation/asts/cgp_impl.md +++ b/docs/implementation/asts/cgp_impl.md @@ -58,4 +58,6 @@ The receiver identifier and the context type these visitors substitute are the o ## Source -The stack lives in [cgp-macro-core/src/types/cgp_impl/](../../../crates/macros/cgp-macro-core/src/types/cgp_impl/): `ImplArgs` in `args.rs`, `ItemCgpImpl` in `item.rs`, `LoweredCgpImpl` and `to_raw_item_impl` in `lowered.rs`, and `CgpProviderOrBareImpl` in `provider_or_bare.rs`. The companion-attribute parsing is in [cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs), and the `self`/`Self` rewriting in [cgp-macro-core/src/visitors/replace_self/](../../../crates/macros/cgp-macro-core/src/visitors/replace_self/). The provider stage this stack hands off to is documented in [asts/cgp_provider.md](cgp_provider.md). +- The stack lives in [cgp-macro-core/src/types/cgp_impl/](../../../crates/macros/cgp-macro-core/src/types/cgp_impl/): `ImplArgs` in `args.rs`, `ItemCgpImpl` in `item.rs`, `LoweredCgpImpl` and `to_raw_item_impl` in `lowered.rs`, and `CgpProviderOrBareImpl` in `provider_or_bare.rs`. +- The companion-attribute parsing is in [cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs), and the `self`/`Self` rewriting in [cgp-macro-core/src/visitors/replace_self/](../../../crates/macros/cgp-macro-core/src/visitors/replace_self/). +- The provider stage this stack hands off to is documented in [asts/cgp_provider.md](cgp_provider.md). diff --git a/docs/implementation/asts/cgp_provider.md b/docs/implementation/asts/cgp_provider.md index 95e36af8..6e92c28d 100644 --- a/docs/implementation/asts/cgp_provider.md +++ b/docs/implementation/asts/cgp_provider.md @@ -60,4 +60,6 @@ pub struct SpawnAndRun(pub ::core::marker::PhantomData<(InCode)>); ## Source -The stack lives in [cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/): `ProviderArgs` in `args.rs`, `ItemCgpProvider` and its helpers in `item.rs`, `LoweredCgpProvider` in `lower.rs`, and `ProviderImplArgs` in `provider_impl_args.rs`. The `IsProviderFor` derivation (`ItemProviderImpl`) is in [cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs), the provider struct (`EmptyStruct`) in [cgp-macro-core/src/types/empty_struct.rs](../../../crates/macros/cgp-macro-core/src/types/empty_struct.rs), and the provider-name rewrite in [cgp-macro-core/src/visitors/replace_provider.rs](../../../crates/macros/cgp-macro-core/src/visitors/replace_provider.rs). The consumer-style stack that hands off to this one is documented in [asts/cgp_impl.md](cgp_impl.md). +- The stack lives in [cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/): `ProviderArgs` in `args.rs`, `ItemCgpProvider` and its helpers in `item.rs`, `LoweredCgpProvider` in `lower.rs`, and `ProviderImplArgs` in `provider_impl_args.rs`. +- The `IsProviderFor` derivation (`ItemProviderImpl`) is in [cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs), the provider struct (`EmptyStruct`) in [cgp-macro-core/src/types/empty_struct.rs](../../../crates/macros/cgp-macro-core/src/types/empty_struct.rs), and the provider-name rewrite in [cgp-macro-core/src/visitors/replace_provider.rs](../../../crates/macros/cgp-macro-core/src/visitors/replace_provider.rs). +- The consumer-style stack that hands off to this one is documented in [asts/cgp_impl.md](cgp_impl.md). diff --git a/docs/implementation/asts/cgp_type.md b/docs/implementation/asts/cgp_type.md index 71e8cc13..5a0804f9 100644 --- a/docs/implementation/asts/cgp_type.md +++ b/docs/implementation/asts/cgp_type.md @@ -18,4 +18,6 @@ The extra impls are built by `to_item_provider_impls`, which reads the component ## Source -`ItemCgpType` and `extract_item_type_from_trait` live in [cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs). The `ItemProviderImpl`/`ItemProviderImpls` helpers are in [cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs). The associated-type-bound rewriting is done by [`get_bounds_and_replace_self_assoc_type`](../../../crates/macros/cgp-macro-core/src/visitors/self_assoc_type.rs), and the shared component types are in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/), documented in [asts/cgp_component.md](cgp_component.md). +- `ItemCgpType` and `extract_item_type_from_trait` live in [cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs). +- The `ItemProviderImpl`/`ItemProviderImpls` helpers are in [cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs). +- The associated-type-bound rewriting is done by [`get_bounds_and_replace_self_assoc_type`](../../../crates/macros/cgp-macro-core/src/visitors/self_assoc_type.rs), and the shared component types are in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/), documented in [asts/cgp_component.md](cgp_component.md). diff --git a/docs/implementation/asts/check_components.md b/docs/implementation/asts/check_components.md index c99bede1..d87dcbcc 100644 --- a/docs/implementation/asts/check_components.md +++ b/docs/implementation/asts/check_components.md @@ -48,8 +48,11 @@ The wiring half is not re-derived here — the entrypoint calls `DelegateTable:: ## Tests -Both stacks are exercised by the expansion snapshots indexed in the [`check_components!`](../entrypoints/check_components.md) and [`delegate_and_check_components!`](../entrypoints/delegate_and_check_components.md) entrypoint documents; each is a compile-only test, so a successful build is the passing assertion. There are no `cgp-macro-tests` failure cases for the check family. +- Both stacks are exercised by the expansion snapshots indexed in the [`check_components!`](../entrypoints/check_components.md) and [`delegate_and_check_components!`](../entrypoints/delegate_and_check_components.md) entrypoint documents; each is a compile-only test, so a successful build is the passing assertion. +- There are no `cgp-macro-tests` failure cases for the check family. ## Source -The `check_components` stack lives in [cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/): the tables in `tables.rs` and `table.rs` (with the trait build, attribute parsing, name derivation, supertrait choice, and span override in `table.rs`), the entries in `entries.rs` and `entry.rs`, the key and value in `key.rs` and `value.rs`, `TypeWithGenerics` in `type_with_generics.rs`, and `EvaluatedCheckEntry` in `evaluated_check_entry.rs`. The `delegate_and_check_components` stack lives in [cgp-macro-core/src/types/delegate_and_check_components/](../../../crates/macros/cgp-macro-core/src/types/delegate_and_check_components/): the wrapper item in `item.rs`, the attributes in `check_params.rs`, the per-key conversion in `key_with_check_params.rs`, and the entry walk in `to_keys_with_check_params.rs`. It reuses the [`DelegateTable`](delegate_component.md). All impls are built with [parse_internal!](../macros/parse_internal.md). +- The `check_components` stack lives in [cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/): the tables in `tables.rs` and `table.rs` (with the trait build, attribute parsing, name derivation, supertrait choice, and span override in `table.rs`), the entries in `entries.rs` and `entry.rs`, the key and value in `key.rs` and `value.rs`, `TypeWithGenerics` in `type_with_generics.rs`, and `EvaluatedCheckEntry` in `evaluated_check_entry.rs`. +- The `delegate_and_check_components` stack lives in [cgp-macro-core/src/types/delegate_and_check_components/](../../../crates/macros/cgp-macro-core/src/types/delegate_and_check_components/): the wrapper item in `item.rs`, the attributes in `check_params.rs`, the per-key conversion in `key_with_check_params.rs`, and the entry walk in `to_keys_with_check_params.rs`. It reuses the [`DelegateTable`](delegate_component.md). +- All impls are built with [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/asts/delegate_component.md b/docs/implementation/asts/delegate_component.md index fcf88605..fca676e1 100644 --- a/docs/implementation/asts/delegate_component.md +++ b/docs/implementation/asts/delegate_component.md @@ -56,8 +56,10 @@ Only Normal and Direct mappings can carry a nested inner table (their values are ## Tests -The stack is exercised end-to-end by the expansion snapshots and behavioral tests indexed in the [entrypoint document](../entrypoints/delegate_components.md); there are no `cgp-macro-tests` failure cases for the delegate family. +- The stack is exercised end-to-end by the expansion snapshots and behavioral tests indexed in the [entrypoint document](../entrypoints/delegate_components.md); there are no `cgp-macro-tests` failure cases for the delegate family. ## Source -The stack lives in [cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/): the table and `new` keyword in `table/main.rs` and inner tables in `table/inner.rs`; the entries in `entries.rs`; the keys in `key/` (`single.rs`, `multi.rs`, `path.rs`, dispatched in `key/mod.rs`); the values in `value/` (`inner_table.rs`, dispatched in `value/mod.rs`); the mappings and their operator in `mapping/` (`normal.rs`, `direct.rs`, `redirect.rs`, `mode.rs`, and the `EvaluatedDelegateEntry` renderer in `mapping/eval.rs`); and the statements in `statement/` (`open.rs`, `namespace.rs`, `for_loop.rs`, and the shared for-entry evaluator in `statement/eval.rs`). Attribute rejection is in `validate_attributes.rs`, path parsing (`PathHead`, `UniPath`) in [types/path/](../../../crates/macros/cgp-macro-core/src/types/path/), and all impls are built with [parse_internal!](../macros/parse_internal.md). The `RedirectLookup` value the `open` and `=>` forms emit is the impl generated by [`#[cgp_component]`](../entrypoints/cgp_component.md). +- The stack lives in [cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/): the table and `new` keyword in `table/main.rs` and inner tables in `table/inner.rs`; the entries in `entries.rs`; the keys in `key/` (`single.rs`, `multi.rs`, `path.rs`, dispatched in `key/mod.rs`); the values in `value/` (`inner_table.rs`, dispatched in `value/mod.rs`); the mappings and their operator in `mapping/` (`normal.rs`, `direct.rs`, `redirect.rs`, `mode.rs`, and the `EvaluatedDelegateEntry` renderer in `mapping/eval.rs`); and the statements in `statement/` (`open.rs`, `namespace.rs`, `for_loop.rs`, and the shared for-entry evaluator in `statement/eval.rs`). +- Attribute rejection is in `validate_attributes.rs`, path parsing (`PathHead`, `UniPath`) in [types/path/](../../../crates/macros/cgp-macro-core/src/types/path/), and all impls are built with [parse_internal!](../macros/parse_internal.md). +- The `RedirectLookup` value the `open` and `=>` forms emit is the impl generated by [`#[cgp_component]`](../entrypoints/cgp_component.md). diff --git a/docs/implementation/asts/namespace.md b/docs/implementation/asts/namespace.md index afbaff5f..5b09a56c 100644 --- a/docs/implementation/asts/namespace.md +++ b/docs/implementation/asts/namespace.md @@ -42,4 +42,6 @@ Its only behavior is a `ToTokens` impl that renders the items in a fixed order ## Source -The stack lives in [cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/): `NamespaceTable` and its `build_*`/`eval` methods in `table.rs`, `InheritNamespaceStatement` in `inherit.rs`, and `EvaluatedNamespaceTable` in `eval.rs`. The entry table and the for-entry machinery it reuses live in [cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/). The entrypoint that drives the stack is documented in [entrypoints/cgp_namespace.md](../entrypoints/cgp_namespace.md). +- The stack lives in [cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/): `NamespaceTable` and its `build_*`/`eval` methods in `table.rs`, `InheritNamespaceStatement` in `inherit.rs`, and `EvaluatedNamespaceTable` in `eval.rs`. +- The entry table and the for-entry machinery it reuses live in [cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/). +- The entrypoint that drives the stack is documented in [entrypoints/cgp_namespace.md](../entrypoints/cgp_namespace.md). diff --git a/docs/implementation/asts/path.md b/docs/implementation/asts/path.md index 8016118a..4215fe81 100644 --- a/docs/implementation/asts/path.md +++ b/docs/implementation/asts/path.md @@ -42,4 +42,5 @@ The remaining types support the multi-path, generic-carrying grammar that `#[cgp ## Source -The stack lives in [cgp-macro-core/src/types/path/](../../../crates/macros/cgp-macro-core/src/types/path/): `PathElement` in `path_element.rs`, `UniPath` in `unipath.rs`, `PrefixPath` in `prefix.rs`, `PathHead` in `path_head.rs`, `PathElementWithGenerics` in `path_element_with_generics.rs`, and the `PathHeadOrType`/`UniPathOrType` disambiguators in `path_head_or_type.rs` and `unipath_or_type.rs`. The runtime spine `PathCons` is defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/path.rs). +- The stack lives in [cgp-macro-core/src/types/path/](../../../crates/macros/cgp-macro-core/src/types/path/): `PathElement` in `path_element.rs`, `UniPath` in `unipath.rs`, `PrefixPath` in `prefix.rs`, `PathHead` in `path_head.rs`, `PathElementWithGenerics` in `path_element_with_generics.rs`, and the `PathHeadOrType`/`UniPathOrType` disambiguators in `path_head_or_type.rs` and `unipath_or_type.rs`. +- The runtime spine `PathCons` is defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/path.rs). diff --git a/docs/implementation/asts/product.md b/docs/implementation/asts/product.md index b85ad527..4614446b 100644 --- a/docs/implementation/asts/product.md +++ b/docs/implementation/asts/product.md @@ -33,4 +33,5 @@ Note that its field is still named and typed as a list of `Type`, not `Expr` — ## Source -The stack lives in [cgp-macro-core/src/types/product/](../../../crates/macros/cgp-macro-core/src/types/product/): `ProductType` in `product_type.rs` and `ProductExpr` in `product_expr.rs`, both re-parsing their fold through [parse_internal!](../macros/parse_internal.md). The runtime types `Cons` and `Nil` are defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/). +- The stack lives in [cgp-macro-core/src/types/product/](../../../crates/macros/cgp-macro-core/src/types/product/): `ProductType` in `product_type.rs` and `ProductExpr` in `product_expr.rs`, both re-parsing their fold through [parse_internal!](../macros/parse_internal.md). +- The runtime types `Cons` and `Nil` are defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/). diff --git a/docs/implementation/asts/sum.md b/docs/implementation/asts/sum.md index 0d2e8d3f..c41e8ea5 100644 --- a/docs/implementation/asts/sum.md +++ b/docs/implementation/asts/sum.md @@ -22,4 +22,5 @@ The only thing that distinguishes this from `ProductType` is the terminator: a s ## Source -The type lives in [cgp-macro-core/src/types/sum.rs](../../../crates/macros/cgp-macro-core/src/types/sum.rs), re-parsing its fold through [parse_internal!](../macros/parse_internal.md). The runtime types `Either` and the uninhabited `Void` are defined in [cgp-field](../../../crates/core/cgp-field/src/types/sum.rs). +- The type lives in [cgp-macro-core/src/types/sum.rs](../../../crates/macros/cgp-macro-core/src/types/sum.rs), re-parsing its fold through [parse_internal!](../macros/parse_internal.md). +- The runtime types `Either` and the uninhabited `Void` are defined in [cgp-field](../../../crates/core/cgp-field/src/types/sum.rs). diff --git a/docs/implementation/asts/symbol.md b/docs/implementation/asts/symbol.md index e784cf5d..ac679d56 100644 --- a/docs/implementation/asts/symbol.md +++ b/docs/implementation/asts/symbol.md @@ -26,4 +26,5 @@ Beyond parsing a literal, `Symbol` is also constructed from a bare identifier th ## Source -The type lives in [cgp-macro-core/src/types/field/symbol.rs](../../../crates/macros/cgp-macro-core/src/types/field/symbol.rs). The runtime types `Symbol`, `Chars`, and `Nil` are defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/). +- The type lives in [cgp-macro-core/src/types/field/symbol.rs](../../../crates/macros/cgp-macro-core/src/types/field/symbol.rs). +- The runtime types `Symbol`, `Chars`, and `Nil` are defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/). diff --git a/docs/implementation/entrypoints/async_trait.md b/docs/implementation/entrypoints/async_trait.md index 5e7cca59..612dad39 100644 --- a/docs/implementation/entrypoints/async_trait.md +++ b/docs/implementation/entrypoints/async_trait.md @@ -46,4 +46,7 @@ There is no dedicated `snapshot_async_trait!` macro; the rewrite is only pinned ## Source -The macro entry point is `async_trait` in [cgp-async-macro/src/lib.rs](../../../crates/macros/cgp-async-macro/src/lib.rs), and the rewrite is `impl_async` in [cgp-async-macro/src/impl_async.rs](../../../crates/macros/cgp-async-macro/src/impl_async.rs). It is re-exported into the prelude from [crates/main/cgp-core/src/prelude.rs](../../../crates/main/cgp-core/src/prelude.rs). It is most often stacked with [`#[cgp_component]`](cgp_component.md) and [`#[cgp_fn]`](cgp_fn.md). +- Entry point: `async_trait` in [cgp-async-macro/src/lib.rs](../../../crates/macros/cgp-async-macro/src/lib.rs). +- The rewrite: `impl_async` in [cgp-async-macro/src/impl_async.rs](../../../crates/macros/cgp-async-macro/src/impl_async.rs). +- Re-exported into the prelude from [crates/main/cgp-core/src/prelude.rs](../../../crates/main/cgp-core/src/prelude.rs). +- It is most often stacked with [`#[cgp_component]`](cgp_component.md) and [`#[cgp_fn]`](cgp_fn.md). diff --git a/docs/implementation/entrypoints/blanket_trait.md b/docs/implementation/entrypoints/blanket_trait.md index 68753acf..1c5912a2 100644 --- a/docs/implementation/entrypoints/blanket_trait.md +++ b/docs/implementation/entrypoints/blanket_trait.md @@ -77,8 +77,14 @@ Two variants have no snapshot yet: an associated *constant* forwarded from its d ## Tests -The snapshot files double as behavioral tests — [blanket_traits/basic.rs](../../../crates/tests/cgp-tests/tests/blanket_traits/basic.rs) and the others each wire a concrete `Context` and assert through a `CanUse…` check trait that the generated blanket impl applies. No `cgp-macro-tests` failure case pins the "missing default body" error path, which is a candidate to add. +The snapshot files double as behavioral tests: + +- [blanket_traits/basic.rs](../../../crates/tests/cgp-tests/tests/blanket_traits/basic.rs) and the others each wire a concrete `Context` and assert through a `CanUse…` check trait that the generated blanket impl applies. +- No `cgp-macro-tests` failure case pins the "missing default body" error path, which is a candidate to add. ## Source -The entry point is `blanket_trait` in [cgp-macro-lib/src/blanket_trait.rs](../../../crates/macros/cgp-macro-lib/src/blanket_trait.rs); the logic lives in [cgp-macro-core/src/types/blanket_trait.rs](../../../crates/macros/cgp-macro-core/src/types/blanket_trait.rs) and is documented in [asts/blanket_trait.md](../asts/blanket_trait.md). The `Self::AssocType`-to-parameter rewriting is done by `RemoveSelfPathVisitor` in [cgp-macro-core/src/visitors/remove_self_path.rs](../../../crates/macros/cgp-macro-core/src/visitors/remove_self_path.rs), and all generated fragments are built with [parse_internal!](../macros/parse_internal.md). +- Entry point: `blanket_trait` in [cgp-macro-lib/src/blanket_trait.rs](../../../crates/macros/cgp-macro-lib/src/blanket_trait.rs). +- Logic: [cgp-macro-core/src/types/blanket_trait.rs](../../../crates/macros/cgp-macro-core/src/types/blanket_trait.rs), documented in [asts/blanket_trait.md](../asts/blanket_trait.md). +- `Self::AssocType`-to-parameter rewriting: `RemoveSelfPathVisitor` in [cgp-macro-core/src/visitors/remove_self_path.rs](../../../crates/macros/cgp-macro-core/src/visitors/remove_self_path.rs). +- Fragment construction: [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/entrypoints/cgp_auto_dispatch.md b/docs/implementation/entrypoints/cgp_auto_dispatch.md index 0374f4b5..5aed5ef4 100644 --- a/docs/implementation/entrypoints/cgp_auto_dispatch.md +++ b/docs/implementation/entrypoints/cgp_auto_dispatch.md @@ -74,4 +74,6 @@ There is no dedicated `snapshot_cgp_auto_dispatch!` macro; the macro's expansion ## Source -The entry point is `cgp_auto_dispatch` in [cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs), forwarded from the proc-macro shim in [cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs). The per-variant handlers are emitted through [`#[cgp_computer]`](cgp_computer.md), and the value-handler matchers it wires live in [crates/extra/cgp-dispatch/src/providers/matchers/](../../../crates/extra/cgp-dispatch/src/providers/matchers/). +- Entry point: `cgp_auto_dispatch` in [cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs), forwarded from the proc-macro shim in [cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs). +- The per-variant handlers are emitted through [`#[cgp_computer]`](cgp_computer.md). +- The value-handler matchers it wires: [crates/extra/cgp-dispatch/src/providers/matchers/](../../../crates/extra/cgp-dispatch/src/providers/matchers/). diff --git a/docs/implementation/entrypoints/cgp_auto_getter.md b/docs/implementation/entrypoints/cgp_auto_getter.md index 6635cc61..0c1de9cb 100644 --- a/docs/implementation/entrypoints/cgp_auto_getter.md +++ b/docs/implementation/entrypoints/cgp_auto_getter.md @@ -83,4 +83,7 @@ Each snapshot file also derives a concrete context and asserts the getter resolv ## Source -The entry point is `cgp_auto_getter` in [cgp-macro-lib/src/cgp_auto_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs), which rejects any attribute argument and runs `ItemCgpAutoGetter::preprocess(...).to_items()`. The stack lives in [cgp-macro-core/src/types/cgp_auto_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_auto_getter/) and is documented in [asts/cgp_getter.md](../asts/cgp_getter.md): `item.rs` sets the `__Context__` identifier and drives field parsing, and `blanket.rs` builds the single blanket impl. Getter-method parsing and the return-type shorthands are shared with `#[cgp_getter]` in [cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs), [cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), and [cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/), and all generated fragments are built with [parse_internal!](../macros/parse_internal.md). +- Entry point: `cgp_auto_getter` in [cgp-macro-lib/src/cgp_auto_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs), which rejects any attribute argument and runs `ItemCgpAutoGetter::preprocess(...).to_items()`. +- The stack: [cgp-macro-core/src/types/cgp_auto_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_auto_getter/), documented in [asts/cgp_getter.md](../asts/cgp_getter.md): `item.rs` sets the `__Context__` identifier and drives field parsing, and `blanket.rs` builds the single blanket impl. +- Getter-method parsing and the return-type shorthands, shared with `#[cgp_getter]`: [cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs), [cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), and [cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/). +- Fragment construction: [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/entrypoints/cgp_component.md b/docs/implementation/entrypoints/cgp_component.md index 6fffce5a..a4dfc8be 100644 --- a/docs/implementation/entrypoints/cgp_component.md +++ b/docs/implementation/entrypoints/cgp_component.md @@ -85,4 +85,8 @@ The behavioral tests confirm the generated wiring works: ## Source -The entry point is `cgp_component` in [cgp-macro-lib/src/cgp_component.rs](../../../crates/macros/cgp-macro-lib/src/cgp_component.rs); the pipeline and its AST types live in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/) and are documented in [asts/cgp_component.md](../asts/cgp_component.md). The forwarding bodies come from the [delegated-impl helpers](../functions/derive/delegated_impls.md), the params tuple from [parse_is_provider_params](../functions/parse/is_provider_params.md), and all generated fragments are built with [parse_internal!](../macros/parse_internal.md). +- Entry point: `cgp_component` in [cgp-macro-lib/src/cgp_component.rs](../../../crates/macros/cgp-macro-lib/src/cgp_component.rs). +- Pipeline and AST types: [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/), documented in [asts/cgp_component.md](../asts/cgp_component.md). +- Forwarding method bodies: the [delegated-impl helpers](../functions/derive/delegated_impls.md). +- `IsProviderFor` params tuple: [parse_is_provider_params](../functions/parse/is_provider_params.md). +- Fragment construction: [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/entrypoints/cgp_computer.md b/docs/implementation/entrypoints/cgp_computer.md index 1e356ebe..8e4b8ca0 100644 --- a/docs/implementation/entrypoints/cgp_computer.md +++ b/docs/implementation/entrypoints/cgp_computer.md @@ -64,4 +64,7 @@ There is no dedicated `snapshot_cgp_computer!` macro; the macro's expansion is n ## Source -The entry point is `cgp_computer` in [cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs), forwarded from the proc-macro shim in [cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs). The `Result`-versus-value split is [`MaybeResultType`](../../../crates/macros/cgp-extra-macro-lib/src/parse/maybe_result.rs). The emitted items lean on constructs documented separately — the base impl on [`#[cgp_new_provider]`](cgp_new_provider.md), the wiring on [`delegate_components!`](delegate_components.md) — and the input-less sibling macro is [`#[cgp_producer]`](cgp_producer.md). +- Entry point: `cgp_computer` in [cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs), forwarded from the proc-macro shim in [cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs). +- The `Result`-versus-value split: [`MaybeResultType`](../../../crates/macros/cgp-extra-macro-lib/src/parse/maybe_result.rs). +- The emitted items lean on the base impl from [`#[cgp_new_provider]`](cgp_new_provider.md) and the wiring from [`delegate_components!`](delegate_components.md). +- The input-less sibling macro is [`#[cgp_producer]`](cgp_producer.md). diff --git a/docs/implementation/entrypoints/cgp_fn.md b/docs/implementation/entrypoints/cgp_fn.md index cefff4d8..870a9b33 100644 --- a/docs/implementation/entrypoints/cgp_fn.md +++ b/docs/implementation/entrypoints/cgp_fn.md @@ -95,4 +95,9 @@ Because `#[cgp_fn]` emits a blanket impl, its snapshot tests double as behaviora ## Source -The entry point is `cgp_fn` in [cgp-macro-lib/src/cgp_fn.rs](../../../crates/macros/cgp-macro-lib/src/cgp_fn.rs); the pipeline and its AST types live in [cgp-macro-core/src/types/cgp_fn/](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/) and are documented in [asts/cgp_fn.md](../asts/cgp_fn.md). Implicit-argument extraction and the field-reading bindings come from [cgp-macro-core/src/functions/implicits/](../../../crates/macros/cgp-macro-core/src/functions/implicits/) and the field-mode helpers under [cgp-macro-core/src/functions/field/](../../../crates/macros/cgp-macro-core/src/functions/field/), companion-attribute parsing from [cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs), and all generated fragments are built with [parse_internal!](../macros/parse_internal.md). +- Entry point: `cgp_fn` in [cgp-macro-lib/src/cgp_fn.rs](../../../crates/macros/cgp-macro-lib/src/cgp_fn.rs). +- Pipeline and its AST types: [cgp-macro-core/src/types/cgp_fn/](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/), documented in [asts/cgp_fn.md](../asts/cgp_fn.md). +- Implicit-argument extraction and field-reading bindings: [cgp-macro-core/src/functions/implicits/](../../../crates/macros/cgp-macro-core/src/functions/implicits/). +- Field-mode helpers: [cgp-macro-core/src/functions/field/](../../../crates/macros/cgp-macro-core/src/functions/field/). +- Companion-attribute parsing: [cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs). +- Fragment construction: [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/entrypoints/cgp_getter.md b/docs/implementation/entrypoints/cgp_getter.md index 385de5a2..1877c53c 100644 --- a/docs/implementation/entrypoints/cgp_getter.md +++ b/docs/implementation/entrypoints/cgp_getter.md @@ -83,4 +83,8 @@ The getter snapshot files also wire concrete contexts and assert the getters res ## Source -The entry point is `cgp_getter` in [cgp-macro-lib/src/cgp_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_getter.rs), which derives the `Has…` → `…Getter` default name and reuses the component pipeline. The getter-specific stack lives in [cgp-macro-core/src/types/cgp_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/) and is documented in [asts/cgp_getter.md](../asts/cgp_getter.md): `item.rs` assembles the items, `to_use_fields_impl.rs`/`use_field.rs`/`with_provider.rs` build the three added provider impls. The component stages it reuses are in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/), documented in [asts/cgp_component.md](../asts/cgp_component.md). Getter-method parsing and the return-type shorthands are shared with `#[cgp_auto_getter]` in [cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs) and [cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), and all generated fragments are built with [parse_internal!](../macros/parse_internal.md). +- Entry point: `cgp_getter` in [cgp-macro-lib/src/cgp_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_getter.rs), which derives the `Has…` → `…Getter` default name and reuses the component pipeline. +- Getter-specific stack: [cgp-macro-core/src/types/cgp_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/), documented in [asts/cgp_getter.md](../asts/cgp_getter.md): `item.rs` assembles the items, `to_use_fields_impl.rs`/`use_field.rs`/`with_provider.rs` build the three added provider impls. +- Component stages it reuses: [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/), documented in [asts/cgp_component.md](../asts/cgp_component.md). +- Getter-method parsing and the return-type shorthands, shared with `#[cgp_auto_getter]`: [cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs) and [cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs). +- Fragment construction: [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/entrypoints/cgp_impl.md b/docs/implementation/entrypoints/cgp_impl.md index f43e29d7..943feb07 100644 --- a/docs/implementation/entrypoints/cgp_impl.md +++ b/docs/implementation/entrypoints/cgp_impl.md @@ -79,4 +79,7 @@ The behavioral tests confirm the lowered wiring works: ## Source -The entry point is `cgp_impl` in [cgp-macro-lib/src/cgp_impl.rs](../../../crates/macros/cgp-macro-lib/src/cgp_impl.rs); the two lowering stages and their AST types live in [cgp-macro-core/src/types/cgp_impl/](../../../crates/macros/cgp-macro-core/src/types/cgp_impl/) and are documented in [asts/cgp_impl.md](../asts/cgp_impl.md). The `self`/`Self` rewriting is done by the `replace_self` visitors in [cgp-macro-core/src/visitors/replace_self/](../../../crates/macros/cgp-macro-core/src/visitors/replace_self/). The handoff target — the provider impl and its `IsProviderFor` derivation — is documented in [entrypoints/cgp_provider.md](cgp_provider.md) and [asts/cgp_provider.md](../asts/cgp_provider.md). +- Entry point: `cgp_impl` in [cgp-macro-lib/src/cgp_impl.rs](../../../crates/macros/cgp-macro-lib/src/cgp_impl.rs). +- Lowering stages and their AST types: [cgp-macro-core/src/types/cgp_impl/](../../../crates/macros/cgp-macro-core/src/types/cgp_impl/), documented in [asts/cgp_impl.md](../asts/cgp_impl.md). +- `self`/`Self` rewriting: the `replace_self` visitors in [cgp-macro-core/src/visitors/replace_self/](../../../crates/macros/cgp-macro-core/src/visitors/replace_self/). +- Handoff target — the provider impl and its `IsProviderFor` derivation: documented in [entrypoints/cgp_provider.md](cgp_provider.md) and [asts/cgp_provider.md](../asts/cgp_provider.md). diff --git a/docs/implementation/entrypoints/cgp_namespace.md b/docs/implementation/entrypoints/cgp_namespace.md index e1f702c1..c7fca8b8 100644 --- a/docs/implementation/entrypoints/cgp_namespace.md +++ b/docs/implementation/entrypoints/cgp_namespace.md @@ -89,4 +89,8 @@ The behavioral tests confirm the generated namespaces wire correctly: ## Source -The entry point is `cgp_namespace` in [cgp-macro-lib/src/cgp_namespace.rs](../../../crates/macros/cgp-macro-lib/src/cgp_namespace.rs); the pipeline and its AST types live in [cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/) and are documented in [asts/namespace.md](../asts/namespace.md). The entry table reuses the `DelegateEntries` grammar from [cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/), the inheritance impl comes from `inherit.rs`, and the `RedirectLookup` marker and every generated fragment are built with [parse_internal!](../macros/parse_internal.md). The `#[prefix(...)]` attribute that attaches a component to a namespace is handled as part of `#[cgp_component]`; see [entrypoints/cgp_component.md](cgp_component.md). +- Entry point: `cgp_namespace` in [cgp-macro-lib/src/cgp_namespace.rs](../../../crates/macros/cgp-macro-lib/src/cgp_namespace.rs). +- Pipeline and its AST types: [cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/), documented in [asts/namespace.md](../asts/namespace.md). +- The entry table reuses the `DelegateEntries` grammar from [cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/); the inheritance impl comes from `inherit.rs`. +- The `RedirectLookup` marker and every generated fragment are built with [parse_internal!](../macros/parse_internal.md). +- The `#[prefix(...)]` attribute that attaches a component to a namespace is handled as part of `#[cgp_component]`; see [entrypoints/cgp_component.md](cgp_component.md). diff --git a/docs/implementation/entrypoints/cgp_new_provider.md b/docs/implementation/entrypoints/cgp_new_provider.md index 0f9b6be5..3372df90 100644 --- a/docs/implementation/entrypoints/cgp_new_provider.md +++ b/docs/implementation/entrypoints/cgp_new_provider.md @@ -39,4 +39,6 @@ None beyond those inherited from [`#[cgp_provider]`](cgp_provider.md#known-issue ## Source -The entry point is `cgp_new_provider` in [cgp-macro-lib/src/cgp_new_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_new_provider.rs). All of the generation logic — including the struct declaration built by `to_provider_struct` when `new` is set — is shared with `#[cgp_provider]` in [cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/), documented in [asts/cgp_provider.md](../asts/cgp_provider.md). The struct-declaring sugar [`#[cgp_impl(new …)]`](cgp_impl.md) desugars to this macro. +- Entry point: `cgp_new_provider` in [cgp-macro-lib/src/cgp_new_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_new_provider.rs). +- Generation logic — including the struct declaration built by `to_provider_struct` when `new` is set — shared with `#[cgp_provider]`: [cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/), documented in [asts/cgp_provider.md](../asts/cgp_provider.md). +- The struct-declaring sugar [`#[cgp_impl(new …)]`](cgp_impl.md) desugars to this macro. diff --git a/docs/implementation/entrypoints/cgp_producer.md b/docs/implementation/entrypoints/cgp_producer.md index f7afb7ea..cd794bda 100644 --- a/docs/implementation/entrypoints/cgp_producer.md +++ b/docs/implementation/entrypoints/cgp_producer.md @@ -50,4 +50,6 @@ There is no dedicated `snapshot_cgp_producer!` macro; the macro's expansion is n ## Source -The entry point is `cgp_producer` in [cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs), forwarded from the proc-macro shim in [cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs). The emitted items lean on [`#[cgp_new_provider]`](cgp_new_provider.md) for the base impl and [`delegate_components!`](delegate_components.md) for the wiring; the input-carrying sibling macro is [`#[cgp_computer]`](cgp_computer.md). +- Entry point: `cgp_producer` in [cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs), forwarded from the proc-macro shim in [cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs). +- The emitted items lean on [`#[cgp_new_provider]`](cgp_new_provider.md) for the base impl and [`delegate_components!`](delegate_components.md) for the wiring. +- The input-carrying sibling macro is [`#[cgp_computer]`](cgp_computer.md). diff --git a/docs/implementation/entrypoints/cgp_provider.md b/docs/implementation/entrypoints/cgp_provider.md index 66650987..f5de8889 100644 --- a/docs/implementation/entrypoints/cgp_provider.md +++ b/docs/implementation/entrypoints/cgp_provider.md @@ -70,4 +70,8 @@ A **const argument in the provider trait's arguments** is rejected with a spanne ## Source -The entry points are `cgp_provider` in [cgp-macro-lib/src/cgp_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_provider.rs) and `cgp_new_provider` in [cgp-macro-lib/src/cgp_new_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_new_provider.rs). The shared lowering and its AST types live in [cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/) and are documented in [asts/cgp_provider.md](../asts/cgp_provider.md); the `IsProviderFor` derivation itself is in [cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs), and the provider-name-to-`IsProviderFor` rewrite in the [`replace_provider` visitor](../../../crates/macros/cgp-macro-core/src/visitors/replace_provider.rs). This macro is the handoff target of [`#[cgp_impl]`](cgp_impl.md). +- Entry points: `cgp_provider` in [cgp-macro-lib/src/cgp_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_provider.rs) and `cgp_new_provider` in [cgp-macro-lib/src/cgp_new_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_new_provider.rs). +- Shared lowering and its AST types: [cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/), documented in [asts/cgp_provider.md](../asts/cgp_provider.md). +- `IsProviderFor` derivation: [cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs). +- Provider-name-to-`IsProviderFor` rewrite: the [`replace_provider` visitor](../../../crates/macros/cgp-macro-core/src/visitors/replace_provider.rs). +- This macro is the handoff target of [`#[cgp_impl]`](cgp_impl.md). diff --git a/docs/implementation/entrypoints/cgp_type.md b/docs/implementation/entrypoints/cgp_type.md index d922de40..79fa092a 100644 --- a/docs/implementation/entrypoints/cgp_type.md +++ b/docs/implementation/entrypoints/cgp_type.md @@ -82,4 +82,9 @@ The behavioral tests confirm the generated wiring and the `UseType` route work: ## Source -The entry point is `cgp_type` in [cgp-macro-lib/src/cgp_type.rs](../../../crates/macros/cgp-macro-lib/src/cgp_type.rs). The extra codegen lives in [cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs) and is documented in [asts/cgp_type.md](../asts/cgp_type.md); the shared component pipeline it wraps is in [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/), documented in [entrypoints/cgp_component.md](cgp_component.md). The associated-type-bound rewriting comes from [`get_bounds_and_replace_self_assoc_type`](../../../crates/macros/cgp-macro-core/src/visitors/self_assoc_type.rs), and the paired provider/`IsProviderFor` impls from `ItemProviderImpl` in [cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs). All generated fragments are built with [parse_internal!](../macros/parse_internal.md). +- Entry point: `cgp_type` in [cgp-macro-lib/src/cgp_type.rs](../../../crates/macros/cgp-macro-lib/src/cgp_type.rs). +- Extra codegen: [cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs), documented in [asts/cgp_type.md](../asts/cgp_type.md). +- Shared component pipeline it wraps: [cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/), documented in [entrypoints/cgp_component.md](cgp_component.md). +- Associated-type-bound rewriting: [`get_bounds_and_replace_self_assoc_type`](../../../crates/macros/cgp-macro-core/src/visitors/self_assoc_type.rs). +- Paired provider/`IsProviderFor` impls: `ItemProviderImpl` in [cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs). +- Fragment construction: [parse_internal!](../macros/parse_internal.md). diff --git a/docs/implementation/entrypoints/check_components.md b/docs/implementation/entrypoints/check_components.md index aeef8715..a947cdc0 100644 --- a/docs/implementation/entrypoints/check_components.md +++ b/docs/implementation/entrypoints/check_components.md @@ -56,8 +56,15 @@ No snapshot pins the plainest single-block, single-bare-component case on its ow ## Tests -The behavioral coverage for `check_components!` is the compile-time assertion itself: the files listed under Snapshots are compile-only tests, so a successful build is the passing check. Each pins both the expansion (via the snapshot) and the fact that the asserted wiring resolves. There are no `cgp-macro-tests` failure cases for the check family. +The behavioral coverage for `check_components!` is the compile-time assertion itself: + +- The files listed under Snapshots are compile-only tests, so a successful build is the passing check. Each pins both the expansion (via the snapshot) and the fact that the asserted wiring resolves. +- There are no `cgp-macro-tests` failure cases for the check family. ## Source -The entry point is `check_components` in [cgp-macro-lib/src/check_components.rs](../../../crates/macros/cgp-macro-lib/src/check_components.rs); the tables, entries, keys, and values live in [cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/) and are documented together with the `delegate_and_check_components!` stack in [asts/check_components.md](../asts/check_components.md). The check trait, the `#[check_trait]`/`#[check_providers]` attributes, the `__Check{Context}` name derivation, the supertrait choice, and the span override are all in `table.rs`; the cartesian-product expansion is in `entry.rs`. All generated fragments are built with [parse_internal!](../macros/parse_internal.md). The `delegate_and_check_components!` macro reuses this stack; see its [entrypoint document](delegate_and_check_components.md). +- Entry point: `check_components` in [cgp-macro-lib/src/check_components.rs](../../../crates/macros/cgp-macro-lib/src/check_components.rs). +- Tables, entries, keys, and values: [cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/), documented together with the `delegate_and_check_components!` stack in [asts/check_components.md](../asts/check_components.md). +- The check trait, the `#[check_trait]`/`#[check_providers]` attributes, the `__Check{Context}` name derivation, the supertrait choice, and the span override are all in `table.rs`; the cartesian-product expansion is in `entry.rs`. +- Fragment construction: [parse_internal!](../macros/parse_internal.md). +- The `delegate_and_check_components!` macro reuses this stack; see its [entrypoint document](delegate_and_check_components.md). diff --git a/docs/implementation/entrypoints/delegate_and_check_components.md b/docs/implementation/entrypoints/delegate_and_check_components.md index 1f596286..83f13b5e 100644 --- a/docs/implementation/entrypoints/delegate_and_check_components.md +++ b/docs/implementation/entrypoints/delegate_and_check_components.md @@ -70,8 +70,12 @@ One variant has no snapshot: a `#[skip_check]` entry alongside checked entries, ## Tests -The snapshot files above are compile-only tests, so a successful build is the passing assertion for both the wiring and the derived check. There are no separate behavioral or `cgp-macro-tests` failure cases for this macro. +- The snapshot files above are compile-only tests, so a successful build is the passing assertion for both the wiring and the derived check. +- There are no separate behavioral or `cgp-macro-tests` failure cases for this macro. ## Source -The entry point is `delegate_and_check_components` in [cgp-macro-lib/src/delegate_and_check_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs); the wrapper item, key-to-check conversion, and attribute types live in [cgp-macro-core/src/types/delegate_and_check_components/](../../../crates/macros/cgp-macro-core/src/types/delegate_and_check_components/) and are documented with the `check_components!` stack in [asts/check_components.md](../asts/check_components.md). The `__CanUse{Context}` default name and `#[check_trait]` handling are in `item.rs`, the `#[check_params]`/`#[skip_check]` parsing and mutual exclusion in `check_params.rs`, the per-key conversion in `key_with_check_params.rs`, and the walk over delegation entries in `to_keys_with_check_params.rs`. It reuses the [`DelegateTable`](../asts/delegate_component.md) for the wiring half and the [`CheckComponentsTable`](../asts/check_components.md) for the checking half. +- Entry point: `delegate_and_check_components` in [cgp-macro-lib/src/delegate_and_check_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs). +- Wrapper item, key-to-check conversion, and attribute types: [cgp-macro-core/src/types/delegate_and_check_components/](../../../crates/macros/cgp-macro-core/src/types/delegate_and_check_components/), documented with the `check_components!` stack in [asts/check_components.md](../asts/check_components.md). +- The `__CanUse{Context}` default name and `#[check_trait]` handling are in `item.rs`, the `#[check_params]`/`#[skip_check]` parsing and mutual exclusion in `check_params.rs`, the per-key conversion in `key_with_check_params.rs`, and the walk over delegation entries in `to_keys_with_check_params.rs`. +- Reuses the [`DelegateTable`](../asts/delegate_component.md) for the wiring half and the [`CheckComponentsTable`](../asts/check_components.md) for the checking half. diff --git a/docs/implementation/entrypoints/delegate_components.md b/docs/implementation/entrypoints/delegate_components.md index 44061233..87127666 100644 --- a/docs/implementation/entrypoints/delegate_components.md +++ b/docs/implementation/entrypoints/delegate_components.md @@ -98,4 +98,8 @@ The behavioral tests confirm the generated wiring resolves and compiles: ## Source -The entry point is `delegate_components` in [cgp-macro-lib/src/delegate_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_components.rs); the table, its entries, keys, values, and statements live in [cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/) and are documented in [asts/delegate_component.md](../asts/delegate_component.md). Attribute rejection is in `validate_attributes.rs`, the impl pair is built in `mapping/eval.rs`, and all generated fragments are built with [parse_internal!](../macros/parse_internal.md). The `open` and `@`-path forms build on the [`RedirectLookup`](cgp_component.md) impl that `#[cgp_component]` generates. +- Entry point: `delegate_components` in [cgp-macro-lib/src/delegate_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_components.rs). +- The table, its entries, keys, values, and statements: [cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/), documented in [asts/delegate_component.md](../asts/delegate_component.md). +- Attribute rejection is in `validate_attributes.rs`; the impl pair is built in `mapping/eval.rs`. +- Fragment construction: [parse_internal!](../macros/parse_internal.md). +- The `open` and `@`-path forms build on the [`RedirectLookup`](cgp_component.md) impl that `#[cgp_component]` generates. diff --git a/docs/implementation/entrypoints/derive_build_field.md b/docs/implementation/entrypoints/derive_build_field.md index 33c07dad..8305b908 100644 --- a/docs/implementation/entrypoints/derive_build_field.md +++ b/docs/implementation/entrypoints/derive_build_field.md @@ -47,8 +47,14 @@ An **empty struct** produces a `__Partial{Name}` with no field markers, a trivia ## Tests -`#[derive(BuildField)]` has no snapshot macro of its own; the builder items it emits are part of the record expansion pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). The behavioral builder tests in [crates/tests/cgp-tests/tests/extensible_records/](../../../crates/tests/cgp-tests/tests/extensible_records/) exercise the machinery: [record_build_from.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_from.rs) drives `builder`/`build_from`/`build_field`/`finalize_build`, [optional_builder.rs](../../../crates/tests/cgp-tests/tests/extensible_records/optional_builder.rs) the optional-builder path, and [point_cast.rs](../../../crates/tests/cgp-tests/tests/extensible_records/point_cast.rs) the `build_with_default` cast. +`#[derive(BuildField)]` has no snapshot macro of its own; the builder items it emits are part of the record expansion pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). The behavioral builder tests in [crates/tests/cgp-tests/tests/extensible_records/](../../../crates/tests/cgp-tests/tests/extensible_records/) exercise the machinery: + +- [record_build_from.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_from.rs) drives `builder`/`build_from`/`build_field`/`finalize_build`. +- [optional_builder.rs](../../../crates/tests/cgp-tests/tests/extensible_records/optional_builder.rs) drives the optional-builder path. +- [point_cast.rs](../../../crates/tests/cgp-tests/tests/extensible_records/point_cast.rs) drives the `build_with_default` cast. ## Source -The entry point is `derive_build_field` in [cgp-macro-lib/src/derive_build_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_build_field.rs). The codegen is `ItemCgpRecord::to_build_field_items` in [cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), which composes the [derive_builder/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/) helpers (`builder_struct.rs`, `has_builder_impl.rs`, `into_builder_impl.rs`, `partial_data.rs`, `finalize_build_impl.rs`, `update_field_impls.rs`, `has_field_impls.rs`); the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The `BuildField`, `FinalizeBuild`, `UpdateField`, `HasBuilder`, `IntoBuilder`, and `PartialData` traits and the `MapType` markers live under [crates/core/cgp-field/src/](../../../crates/core/cgp-field/src/). +- Entry point: `derive_build_field` in [cgp-macro-lib/src/derive_build_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_build_field.rs). +- Codegen: `ItemCgpRecord::to_build_field_items` in [cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), which composes the [derive_builder/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/) helpers (`builder_struct.rs`, `has_builder_impl.rs`, `into_builder_impl.rs`, `partial_data.rs`, `finalize_build_impl.rs`, `update_field_impls.rs`, `has_field_impls.rs`); the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). +- The `BuildField`, `FinalizeBuild`, `UpdateField`, `HasBuilder`, `IntoBuilder`, and `PartialData` traits and the `MapType` markers live under [crates/core/cgp-field/src/](../../../crates/core/cgp-field/src/). diff --git a/docs/implementation/entrypoints/derive_cgp_data.md b/docs/implementation/entrypoints/derive_cgp_data.md index 0e7ddf28..0e7421f4 100644 --- a/docs/implementation/entrypoints/derive_cgp_data.md +++ b/docs/implementation/entrypoints/derive_cgp_data.md @@ -50,8 +50,17 @@ Every `snapshot_derive_cgp_data!` invocation across the suite is indexed here, s ## Tests -The snapshot tests above also carry runtime assertions that exercise the composed machinery: `person_record.rs` builds an `Employee` from a `Person` via the builder, `optional_builder.rs` drives the optional builder (`set`/`finalize_optional`/`finalize_with_default`), `point_cast.rs` casts a smaller record up into a larger one, and the `derive_cgp_data*` variant snapshots run the extractor and the upcast/downcast casts. The neighboring [record_build_from.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_from.rs), [record_build_with_handlers.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_with_handlers.rs), [shape_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch.rs), [shape_dispatch_ref.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch_ref.rs), and [variant_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/variant_dispatch.rs) exercise the builder and dispatch behaviors on `CgpData` types without pinning a snapshot. +The snapshot tests above also carry runtime assertions that exercise the composed machinery: + +- `person_record.rs` builds an `Employee` from a `Person` via the builder. +- `optional_builder.rs` drives the optional builder (`set`/`finalize_optional`/`finalize_with_default`). +- `point_cast.rs` casts a smaller record up into a larger one. +- The `derive_cgp_data*` variant snapshots run the extractor and the upcast/downcast casts. +- The neighboring [record_build_from.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_from.rs), [record_build_with_handlers.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_with_handlers.rs), [shape_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch.rs), [shape_dispatch_ref.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch_ref.rs), and [variant_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/variant_dispatch.rs) exercise the builder and dispatch behaviors on `CgpData` types without pinning a snapshot. ## Source -The entry point is `derive_cgp_data` in [cgp-macro-lib/src/cgp_data.rs](../../../crates/macros/cgp-macro-lib/src/cgp_data.rs); the shape dispatch is `ItemCgpData` in [cgp-macro-core/src/types/cgp_data/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/item.rs), documented in [asts/cgp_data.md](../asts/cgp_data.md). The record path is `ItemCgpRecord::to_items` in `record.rs` (see [`derive_cgp_record`](derive_cgp_record.md)) and the variant path `ItemCgpVariant::to_items` in `variant.rs` (see [`derive_cgp_variant`](derive_cgp_variant.md)), both under [cgp-macro-core/src/types/cgp_data/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/). The runtime traits live in [crates/core/cgp-field/src/](../../../crates/core/cgp-field/src/). +- Entry point: `derive_cgp_data` in [cgp-macro-lib/src/cgp_data.rs](../../../crates/macros/cgp-macro-lib/src/cgp_data.rs). +- Shape dispatch: `ItemCgpData` in [cgp-macro-core/src/types/cgp_data/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/item.rs), documented in [asts/cgp_data.md](../asts/cgp_data.md). +- The record path is `ItemCgpRecord::to_items` in `record.rs` (see [`derive_cgp_record`](derive_cgp_record.md)) and the variant path `ItemCgpVariant::to_items` in `variant.rs` (see [`derive_cgp_variant`](derive_cgp_variant.md)), both under [cgp-macro-core/src/types/cgp_data/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/). +- The runtime traits live in [crates/core/cgp-field/src/](../../../crates/core/cgp-field/src/). diff --git a/docs/implementation/entrypoints/derive_cgp_record.md b/docs/implementation/entrypoints/derive_cgp_record.md index 0bc3c49b..f45f8a20 100644 --- a/docs/implementation/entrypoints/derive_cgp_record.md +++ b/docs/implementation/entrypoints/derive_cgp_record.md @@ -21,8 +21,12 @@ The record's corner cases — `Symbol!` versus `Index` tagging, the newtype ` ## Tests -`#[derive(CgpRecord)]` has no snapshot macro of its own; its expansion is identical to the record path of `#[derive(CgpData)]` and is pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). The behavioral record tests in [crates/tests/cgp-tests/tests/extensible_records/](../../../crates/tests/cgp-tests/tests/extensible_records/) — notably [record_build_from.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_from.rs) and [record_build_with_handlers.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_with_handlers.rs) — exercise the builder that this derive produces. +`#[derive(CgpRecord)]` has no snapshot macro of its own; its expansion is identical to the record path of `#[derive(CgpData)]` and is pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). + +- The behavioral record tests in [crates/tests/cgp-tests/tests/extensible_records/](../../../crates/tests/cgp-tests/tests/extensible_records/) — notably [record_build_from.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_from.rs) and [record_build_with_handlers.rs](../../../crates/tests/cgp-tests/tests/extensible_records/record_build_with_handlers.rs) — exercise the builder that this derive produces. ## Source -The entry point is `derive_cgp_record` in [cgp-macro-lib/src/cgp_record.rs](../../../crates/macros/cgp-macro-lib/src/cgp_record.rs). The codegen is `ItemCgpRecord::to_items` in [cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), which composes `derive_has_field_impls_from_struct`, `derive_has_fields_impls_from_struct`, and the [derive_builder/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/) helpers; the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The runtime traits live in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). +- Entry point: `derive_cgp_record` in [cgp-macro-lib/src/cgp_record.rs](../../../crates/macros/cgp-macro-lib/src/cgp_record.rs). +- Codegen: `ItemCgpRecord::to_items` in [cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), which composes `derive_has_field_impls_from_struct`, `derive_has_fields_impls_from_struct`, and the [derive_builder/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/) helpers; the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). +- The runtime traits live in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). diff --git a/docs/implementation/entrypoints/derive_cgp_variant.md b/docs/implementation/entrypoints/derive_cgp_variant.md index 4f98e45a..3813b515 100644 --- a/docs/implementation/entrypoints/derive_cgp_variant.md +++ b/docs/implementation/entrypoints/derive_cgp_variant.md @@ -21,8 +21,12 @@ The variant corner cases are inherited from those building blocks: variant names ## Tests -`#[derive(CgpVariant)]` has no snapshot macro of its own; its expansion is identical to the enum path of `#[derive(CgpData)]` and is pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). The behavioral variant tests in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/) — notably [shape_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch.rs), [shape_dispatch_ref.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch_ref.rs), and [variant_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/variant_dispatch.rs) — exercise the extractor and constructors this derive produces. +`#[derive(CgpVariant)]` has no snapshot macro of its own; its expansion is identical to the enum path of `#[derive(CgpData)]` and is pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). + +- The behavioral variant tests in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/) — notably [shape_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch.rs), [shape_dispatch_ref.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch_ref.rs), and [variant_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/variant_dispatch.rs) — exercise the extractor and constructors this derive produces. ## Source -The entry point is `derive_cgp_variant` in [cgp-macro-lib/src/cgp_variant.rs](../../../crates/macros/cgp-macro-lib/src/cgp_variant.rs). The codegen is `ItemCgpVariant::to_items` in [cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which composes `derive_has_fields_impls_from_enum`, `derive_from_variant_from_enum`, and the [derive_extractor/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/) helpers; the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The runtime traits live in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). +- Entry point: `derive_cgp_variant` in [cgp-macro-lib/src/cgp_variant.rs](../../../crates/macros/cgp-macro-lib/src/cgp_variant.rs). +- Codegen: `ItemCgpVariant::to_items` in [cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which composes `derive_has_fields_impls_from_enum`, `derive_from_variant_from_enum`, and the [derive_extractor/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/) helpers; the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). +- The runtime traits live in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). diff --git a/docs/implementation/entrypoints/derive_extract_field.md b/docs/implementation/entrypoints/derive_extract_field.md index bb1cb166..bdea7684 100644 --- a/docs/implementation/entrypoints/derive_extract_field.md +++ b/docs/implementation/entrypoints/derive_extract_field.md @@ -52,8 +52,15 @@ The extractor codegen requires every variant to be a single-unnamed-field tuple ## Tests -`#[derive(ExtractField)]` has no snapshot macro of its own; the extractor items it emits are part of the variant expansion pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). The behavioral extractor tests in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/) exercise the machinery: [shape_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch.rs) drives the owned extractor, [shape_dispatch_ref.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch_ref.rs) the borrowed extractor, and [variant_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/variant_dispatch.rs) the extract-and-dispatch flow. The single-unnamed-field requirement has no dedicated failure case in `cgp-macro-tests` and is a candidate for one. +`#[derive(ExtractField)]` has no snapshot macro of its own; the extractor items it emits are part of the variant expansion pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). The behavioral extractor tests in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/) exercise the machinery: + +- [shape_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch.rs) drives the owned extractor. +- [shape_dispatch_ref.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/shape_dispatch_ref.rs) drives the borrowed extractor. +- [variant_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/variant_dispatch.rs) drives the extract-and-dispatch flow. +- The single-unnamed-field requirement has no dedicated failure case in `cgp-macro-tests` and is a candidate for one. ## Source -The entry point is `derive_extract_field` in [cgp-macro-lib/src/derive_extract_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_extract_field.rs). The codegen is `ItemCgpVariant::to_extract_field_items` in [cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which composes the [derive_extractor/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/) helpers (`extractor_enum.rs`, `partial_data.rs`, `has_extractor_impl.rs`, `finalize_extract_impl.rs`, `extract_field_impls.rs`, `utils.rs`); the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The `ExtractField`, `HasExtractor`/`HasExtractorRef`/`HasExtractorMut`, `FinalizeExtract`, `FinalizeExtractResult`, and `PartialData` traits and the `MapType`/`MapTypeRef` markers live under [crates/core/cgp-field/src/](../../../crates/core/cgp-field/src/). +- Entry point: `derive_extract_field` in [cgp-macro-lib/src/derive_extract_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_extract_field.rs). +- Codegen: `ItemCgpVariant::to_extract_field_items` in [cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which composes the [derive_extractor/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/) helpers (`extractor_enum.rs`, `partial_data.rs`, `has_extractor_impl.rs`, `finalize_extract_impl.rs`, `extract_field_impls.rs`, `utils.rs`); the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). +- The `ExtractField`, `HasExtractor`/`HasExtractorRef`/`HasExtractorMut`, `FinalizeExtract`, `FinalizeExtractResult`, and `PartialData` traits and the `MapType`/`MapTypeRef` markers live under [crates/core/cgp-field/src/](../../../crates/core/cgp-field/src/). diff --git a/docs/implementation/entrypoints/derive_from_variant.md b/docs/implementation/entrypoints/derive_from_variant.md index a26bf78a..6830be7a 100644 --- a/docs/implementation/entrypoints/derive_from_variant.md +++ b/docs/implementation/entrypoints/derive_from_variant.md @@ -40,8 +40,13 @@ Like the extractor derive, `#[derive(FromVariant)]` requires every variant to be ## Tests -`#[derive(FromVariant)]` has no snapshot macro of its own; the constructor impls it emits are part of the variant expansion pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). The behavioral variant tests in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/) — notably [variant_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/variant_dispatch.rs) — construct enums through the generated `from_variant`. The single-unnamed-field requirement has no dedicated failure case in `cgp-macro-tests` and is a candidate for one. +`#[derive(FromVariant)]` has no snapshot macro of its own; the constructor impls it emits are part of the variant expansion pinned by the `snapshot_derive_cgp_data!` snapshots indexed in [derive_cgp_data.md's Snapshots section](derive_cgp_data.md#snapshots). + +- The behavioral variant tests in [crates/tests/cgp-tests/tests/extensible_variants/](../../../crates/tests/cgp-tests/tests/extensible_variants/) — notably [variant_dispatch.rs](../../../crates/tests/cgp-tests/tests/extensible_variants/variant_dispatch.rs) — construct enums through the generated `from_variant`. +- The single-unnamed-field requirement has no dedicated failure case in `cgp-macro-tests` and is a candidate for one. ## Source -The entry point is `derive_from_variant` in [cgp-macro-lib/src/derive_from_variant.rs](../../../crates/macros/cgp-macro-lib/src/derive_from_variant.rs). The codegen is `ItemCgpVariant::to_from_variant_impls` in [cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which delegates to `derive_from_variant_from_enum` in [cgp-macro-core/src/types/cgp_data/derive_from_variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs); the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The `FromVariant` trait is defined in [crates/core/cgp-field/src/traits/from_variant.rs](../../../crates/core/cgp-field/src/traits/from_variant.rs). +- Entry point: `derive_from_variant` in [cgp-macro-lib/src/derive_from_variant.rs](../../../crates/macros/cgp-macro-lib/src/derive_from_variant.rs). +- Codegen: `ItemCgpVariant::to_from_variant_impls` in [cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which delegates to `derive_from_variant_from_enum` in [cgp-macro-core/src/types/cgp_data/derive_from_variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs); the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). +- The `FromVariant` trait is defined in [crates/core/cgp-field/src/traits/from_variant.rs](../../../crates/core/cgp-field/src/traits/from_variant.rs). diff --git a/docs/implementation/entrypoints/derive_has_field.md b/docs/implementation/entrypoints/derive_has_field.md index a8998e33..2306b0c3 100644 --- a/docs/implementation/entrypoints/derive_has_field.md +++ b/docs/implementation/entrypoints/derive_has_field.md @@ -66,4 +66,6 @@ The behavioral tests confirm the generated getters read the right fields: ## Source -The entry point is `derive_has_field` in [cgp-macro-lib/src/derive_has_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_field.rs). It calls `ItemCgpRecord::to_has_field_impls` in [cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), whose codegen is `derive_has_field_impls_from_struct` in [cgp-macro-core/src/types/cgp_data/derive_has_field.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_field.rs); the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The `HasField`/`HasFieldMut` traits are defined in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). +- Entry point: `derive_has_field` in [cgp-macro-lib/src/derive_has_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_field.rs). +- It calls `ItemCgpRecord::to_has_field_impls` in [cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), whose codegen is `derive_has_field_impls_from_struct` in [cgp-macro-core/src/types/cgp_data/derive_has_field.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_field.rs); the AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). +- The `HasField`/`HasFieldMut` traits are defined in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). diff --git a/docs/implementation/entrypoints/derive_has_fields.md b/docs/implementation/entrypoints/derive_has_fields.md index 1c914ea0..6ae73bb8 100644 --- a/docs/implementation/entrypoints/derive_has_fields.md +++ b/docs/implementation/entrypoints/derive_has_fields.md @@ -62,8 +62,14 @@ Every `snapshot_derive_has_fields!` invocation across the suite is indexed here, ## Tests -The snapshot tests above double as the coverage: each pins one field-shape and, where paired with runtime assertions, round-trips a value through `to_fields`/`from_fields`. The `struct_single_unnamed_field` snapshot is the guard on the newtype special case, and `struct_generic`/`struct_generic_lifetime` and `has_fields_enum_generic` guard the generic-threading behavior. +The snapshot tests above double as the coverage: + +- Each pins one field-shape and, where paired with runtime assertions, round-trips a value through `to_fields`/`from_fields`. +- The `struct_single_unnamed_field` snapshot is the guard on the newtype special case. +- `struct_generic`/`struct_generic_lifetime` and `has_fields_enum_generic` guard the generic-threading behavior. ## Source -The entry point is `derive_has_fields` in [cgp-macro-lib/src/derive_has_fields.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_fields.rs). The struct path calls `ItemCgpRecord::to_has_fields_impls` in [cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs); both paths land in the [derive_has_fields/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/) submodule, where `derive_struct.rs`/`derive_enum.rs` drive the five impls, `product.rs` (`item_fields_to_product_type`) builds the struct product, `sum.rs` (`variants_to_sum_type`) builds the enum sum, and the `from_fields_*`/`to_fields_*`/`to_fields_ref_*` files build the conversions. The AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). The `HasFields`, `HasFieldsRef`, `FromFields`, `ToFields`, and `ToFieldsRef` traits and the `Field`/`Either`/`Void` building blocks live under [crates/core/cgp-field/src/](../../../crates/core/cgp-field/src/). +- Entry point: `derive_has_fields` in [cgp-macro-lib/src/derive_has_fields.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_fields.rs). +- The struct path calls `ItemCgpRecord::to_has_fields_impls` in [cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs); both paths land in the [derive_has_fields/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/) submodule, where `derive_struct.rs`/`derive_enum.rs` drive the five impls, `product.rs` (`item_fields_to_product_type`) builds the struct product, `sum.rs` (`variants_to_sum_type`) builds the enum sum, and the `from_fields_*`/`to_fields_*`/`to_fields_ref_*` files build the conversions. The AST types are documented in [asts/cgp_data.md](../asts/cgp_data.md). +- The `HasFields`, `HasFieldsRef`, `FromFields`, `ToFields`, and `ToFieldsRef` traits and the `Field`/`Either`/`Void` building blocks live under [crates/core/cgp-field/src/](../../../crates/core/cgp-field/src/). diff --git a/docs/implementation/entrypoints/path.md b/docs/implementation/entrypoints/path.md index 6ae83594..3d9504c2 100644 --- a/docs/implementation/entrypoints/path.md +++ b/docs/implementation/entrypoints/path.md @@ -46,4 +46,7 @@ Each segment is first parsed as a full Rust `Type`, then reclassified: only a se ## Source -The entry point is `Path` in [cgp-macro-lib/src/path.rs](../../../crates/macros/cgp-macro-lib/src/path.rs); the `UniPath`, `PathElement`, and the wider path stack live in [cgp-macro-core/src/types/path/](../../../crates/macros/cgp-macro-core/src/types/path/) and are documented in [asts/path.md](../asts/path.md). The runtime spine `PathCons` is defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/path.rs), and the [`RedirectLookup`](../../reference/providers/redirect_lookup.md) provider that walks a path is in [cgp-component](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs). +- Entry point: `Path` in [cgp-macro-lib/src/path.rs](../../../crates/macros/cgp-macro-lib/src/path.rs). +- The `UniPath`, `PathElement`, and the wider path stack: [cgp-macro-core/src/types/path/](../../../crates/macros/cgp-macro-core/src/types/path/), documented in [asts/path.md](../asts/path.md). +- Runtime spine `PathCons`: defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/path.rs). +- The [`RedirectLookup`](../../reference/providers/redirect_lookup.md) provider that walks a path: [cgp-component](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs). diff --git a/docs/implementation/entrypoints/product.md b/docs/implementation/entrypoints/product.md index 7ca9f270..fe961ed6 100644 --- a/docs/implementation/entrypoints/product.md +++ b/docs/implementation/entrypoints/product.md @@ -55,4 +55,7 @@ Because `eval` re-parses its output through `parse_internal!`, a fold that produ ## Source -The entry points are `Product` and `product` in [cgp-macro-lib/src/product.rs](../../../crates/macros/cgp-macro-lib/src/product.rs); the `ProductType` and `ProductExpr` AST types live in [cgp-macro-core/src/types/product/](../../../crates/macros/cgp-macro-core/src/types/product/) and are documented in [asts/product.md](../asts/product.md). The fold re-parses through [parse_internal!](../macros/parse_internal.md). The runtime types `Cons` and `Nil` are defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/). +- Entry points: `Product` and `product` in [cgp-macro-lib/src/product.rs](../../../crates/macros/cgp-macro-lib/src/product.rs). +- `ProductType` and `ProductExpr` AST types: [cgp-macro-core/src/types/product/](../../../crates/macros/cgp-macro-core/src/types/product/), documented in [asts/product.md](../asts/product.md). +- The fold re-parses through [parse_internal!](../macros/parse_internal.md). +- Runtime types `Cons` and `Nil`: defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/). diff --git a/docs/implementation/entrypoints/snapshot_macros.md b/docs/implementation/entrypoints/snapshot_macros.md index ac6af5a2..a22968c0 100644 --- a/docs/implementation/entrypoints/snapshot_macros.md +++ b/docs/implementation/entrypoints/snapshot_macros.md @@ -73,4 +73,9 @@ The per-macro Snapshots sections — for example [cgp_component.md](cgp_componen ## Source -The proc-macro shims are in [cgp-macro-test-util/src/lib.rs](../../../crates/macros/cgp-macro-test-util/src/lib.rs); the per-macro entrypoints are in [cgp-macro-test-util-lib/src/entrypoints/](../../../crates/macros/cgp-macro-test-util-lib/src/entrypoints/), the snapshot wrapper types in [src/types/](../../../crates/macros/cgp-macro-test-util-lib/src/types/), the pretty-printer in [src/functions/pretty_format.rs](../../../crates/macros/cgp-macro-test-util-lib/src/functions/pretty_format.rs), and the keyword markers in [src/keywords.rs](../../../crates/macros/cgp-macro-test-util-lib/src/keywords.rs). Each snapshot calls the matching production entry function in [cgp-macro-lib](../../../crates/macros/cgp-macro-lib/). +- Proc-macro shims: [cgp-macro-test-util/src/lib.rs](../../../crates/macros/cgp-macro-test-util/src/lib.rs). +- Per-macro entrypoints: [cgp-macro-test-util-lib/src/entrypoints/](../../../crates/macros/cgp-macro-test-util-lib/src/entrypoints/). +- Snapshot wrapper types: [src/types/](../../../crates/macros/cgp-macro-test-util-lib/src/types/). +- Pretty-printer: [src/functions/pretty_format.rs](../../../crates/macros/cgp-macro-test-util-lib/src/functions/pretty_format.rs). +- Keyword markers: [src/keywords.rs](../../../crates/macros/cgp-macro-test-util-lib/src/keywords.rs). +- Each snapshot calls the matching production entry function in [cgp-macro-lib](../../../crates/macros/cgp-macro-lib/). diff --git a/docs/implementation/entrypoints/sum.md b/docs/implementation/entrypoints/sum.md index 7daa9309..21e42dec 100644 --- a/docs/implementation/entrypoints/sum.md +++ b/docs/implementation/entrypoints/sum.md @@ -41,4 +41,7 @@ The only structural difference from `Product!` is the terminator: a sum folds on ## Source -The entry point is `Sum` in [cgp-macro-lib/src/sum.rs](../../../crates/macros/cgp-macro-lib/src/sum.rs); the `SumType` AST type lives in [cgp-macro-core/src/types/sum.rs](../../../crates/macros/cgp-macro-core/src/types/sum.rs) and is documented in [asts/sum.md](../asts/sum.md). The fold re-parses through [parse_internal!](../macros/parse_internal.md). The runtime types `Either` and the uninhabited `Void` are defined in [cgp-field](../../../crates/core/cgp-field/src/types/sum.rs). +- Entry point: `Sum` in [cgp-macro-lib/src/sum.rs](../../../crates/macros/cgp-macro-lib/src/sum.rs). +- `SumType` AST type: [cgp-macro-core/src/types/sum.rs](../../../crates/macros/cgp-macro-core/src/types/sum.rs), documented in [asts/sum.md](../asts/sum.md). +- The fold re-parses through [parse_internal!](../macros/parse_internal.md). +- Runtime types `Either` and the uninhabited `Void`: defined in [cgp-field](../../../crates/core/cgp-field/src/types/sum.rs). diff --git a/docs/implementation/entrypoints/symbol.md b/docs/implementation/entrypoints/symbol.md index 749668d8..06fa81df 100644 --- a/docs/implementation/entrypoints/symbol.md +++ b/docs/implementation/entrypoints/symbol.md @@ -49,4 +49,6 @@ The `Symbol!` expansion has no snapshot macro of its own; its behavior is exerci ## Source -The entry point is `Symbol` in [cgp-macro-lib/src/symbol.rs](../../../crates/macros/cgp-macro-lib/src/symbol.rs); the `Symbol` AST type lives in [cgp-macro-core/src/types/field/symbol.rs](../../../crates/macros/cgp-macro-core/src/types/field/symbol.rs) and is documented in [asts/symbol.md](../asts/symbol.md). The runtime types `Symbol`, `Chars`, and `Nil` are defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/). +- Entry point: `Symbol` in [cgp-macro-lib/src/symbol.rs](../../../crates/macros/cgp-macro-lib/src/symbol.rs). +- `Symbol` AST type: [cgp-macro-core/src/types/field/symbol.rs](../../../crates/macros/cgp-macro-core/src/types/field/symbol.rs), documented in [asts/symbol.md](../asts/symbol.md). +- Runtime types `Symbol`, `Chars`, and `Nil`: defined in [cgp-base-types](../../../crates/core/cgp-base-types/src/types/). diff --git a/docs/implementation/functions/derive/delegated_impls.md b/docs/implementation/functions/derive/delegated_impls.md index 10f150f2..0b1fa7e1 100644 --- a/docs/implementation/functions/derive/delegated_impls.md +++ b/docs/implementation/functions/derive/delegated_impls.md @@ -20,8 +20,13 @@ The forwarding qualifies associated types and consts through the supplied trait ## Tests -These functions have no dedicated unit test; they are covered through the `#[cgp_component]` expansion snapshots, which pin the forwarding bodies of all four impls. The plain case in [basic_delegation/component_macro.rs](../../../../crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs) shows method forwarding through `<__Provider__ as DelegateComponent<…>>::Delegate::foo(…)` and through `UseContext`/`RedirectLookup`; the default-method case in [basic_delegation/default_methods.rs](../../../../crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs) confirms a forwarded call resolves to a default body. Associated-type and const forwarding are pinned by the `#[cgp_type]` snapshots in the `abstract_types` target. +These functions have no dedicated unit test; they are covered through the `#[cgp_component]` expansion snapshots, which pin the forwarding bodies of all four impls. + +- The plain case in [basic_delegation/component_macro.rs](../../../../crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs) shows method forwarding through `<__Provider__ as DelegateComponent<…>>::Delegate::foo(…)` and through `UseContext`/`RedirectLookup`. +- The default-method case in [basic_delegation/default_methods.rs](../../../../crates/tests/cgp-tests/tests/basic_delegation/default_methods.rs) confirms a forwarded call resolves to a default body. +- Associated-type and const forwarding are pinned by the `#[cgp_type]` snapshots in the `abstract_types` target. ## Source -The functions live in [cgp-macro-core/src/functions/delegated_impls/](../../../../crates/macros/cgp-macro-core/src/functions/delegated_impls/): `trait_items.rs` holds `trait_items_to_delegated_impl_items` and the per-item dispatch, `provider_trait.rs` holds `provider_trait_to_impl_items`, `signature.rs` holds the method-forwarding builder `signature_to_delegated_impl_item_fn`, and `item_type.rs` holds `trait_to_impl_item_type`. The callers are documented in [entrypoints/cgp_component.md](../../entrypoints/cgp_component.md) and the [cgp_component AST stack](../../asts/cgp_component.md). +- The functions live in [cgp-macro-core/src/functions/delegated_impls/](../../../../crates/macros/cgp-macro-core/src/functions/delegated_impls/): `trait_items.rs` holds `trait_items_to_delegated_impl_items` and the per-item dispatch, `provider_trait.rs` holds `provider_trait_to_impl_items`, `signature.rs` holds the method-forwarding builder `signature_to_delegated_impl_item_fn`, and `item_type.rs` holds `trait_to_impl_item_type`. +- The callers are documented in [entrypoints/cgp_component.md](../../entrypoints/cgp_component.md) and the [cgp_component AST stack](../../asts/cgp_component.md). diff --git a/docs/implementation/functions/derive/generics.md b/docs/implementation/functions/derive/generics.md index 9a40f7bc..858ff6f0 100644 --- a/docs/implementation/functions/derive/generics.md +++ b/docs/implementation/functions/derive/generics.md @@ -6,8 +6,8 @@ The merge is a straightforward concatenation: the parameters of the first `Gener ## Tests -The helper has no dedicated test; it is covered indirectly through the expansion snapshots of the macros that assemble multi-source impls. +- The helper has no dedicated test; it is covered indirectly through the expansion snapshots of the macros that assemble multi-source impls. ## Source -The function lives in [cgp-macro-core/src/functions/generics/merge_generics.rs](../../../../crates/macros/cgp-macro-core/src/functions/generics/merge_generics.rs). +- The function lives in [cgp-macro-core/src/functions/generics/merge_generics.rs](../../../../crates/macros/cgp-macro-core/src/functions/generics/merge_generics.rs). diff --git a/docs/implementation/functions/derive/idents.md b/docs/implementation/functions/derive/idents.md index 4a5ae36c..5d7fc20c 100644 --- a/docs/implementation/functions/derive/idents.md +++ b/docs/implementation/functions/derive/idents.md @@ -8,8 +8,8 @@ The one non-obvious helper is `to_snake_case_ident`, which additionally wraps it ## Tests -These helpers have no dedicated test; they are covered through the expansion snapshots, where the derived names appear in the generated code. +- These helpers have no dedicated test; they are covered through the expansion snapshots, where the derived names appear in the generated code. ## Source -The functions live in [cgp-macro-core/src/functions/camel_case.rs](../../../../crates/macros/cgp-macro-core/src/functions/camel_case.rs) and [cgp-macro-core/src/functions/snake_case.rs](../../../../crates/macros/cgp-macro-core/src/functions/snake_case.rs). +- The functions live in [cgp-macro-core/src/functions/camel_case.rs](../../../../crates/macros/cgp-macro-core/src/functions/camel_case.rs) and [cgp-macro-core/src/functions/snake_case.rs](../../../../crates/macros/cgp-macro-core/src/functions/snake_case.rs). diff --git a/docs/implementation/functions/parse/is_provider_params.md b/docs/implementation/functions/parse/is_provider_params.md index cb584983..a71e1a56 100644 --- a/docs/implementation/functions/parse/is_provider_params.md +++ b/docs/implementation/functions/parse/is_provider_params.md @@ -14,8 +14,13 @@ A const generic parameter triggers a panic. The `GenericParam::Const` arm is `un ## Tests -The function is covered indirectly through the expansion snapshots that pin the `IsProviderFor` params tuple: the empty `()` case in [basic_delegation/component_macro.rs](../../../../crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs) and the `(Life<'a>, T)` case in [generic_components/component_lifetime.rs](../../../../crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs). The const-generic panic has no test yet and is a candidate failure case for `cgp-macro-tests`. +The function is covered indirectly through the expansion snapshots that pin the `IsProviderFor` params tuple. + +- The empty `()` case in [basic_delegation/component_macro.rs](../../../../crates/tests/cgp-tests/tests/basic_delegation/component_macro.rs). +- The `(Life<'a>, T)` case in [generic_components/component_lifetime.rs](../../../../crates/tests/cgp-tests/tests/generic_components/component_lifetime.rs). +- The const-generic panic has no test yet and is a candidate failure case for `cgp-macro-tests`. ## Source -The function lives in [cgp-macro-core/src/functions/is_provider_params.rs](../../../../crates/macros/cgp-macro-core/src/functions/is_provider_params.rs). It is called by the provider-trait and blanket-impl builders in [cgp-macro-core/src/types/cgp_component/preprocessed/](../../../../crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/); the `Life` wrapper it emits is documented in [reference/types/life.md](../../../reference/types/life.md). +- The function lives in [cgp-macro-core/src/functions/is_provider_params.rs](../../../../crates/macros/cgp-macro-core/src/functions/is_provider_params.rs). +- It is called by the provider-trait and blanket-impl builders in [cgp-macro-core/src/types/cgp_component/preprocessed/](../../../../crates/macros/cgp-macro-core/src/types/cgp_component/preprocessed/); the `Life` wrapper it emits is documented in [reference/types/life.md](../../../reference/types/life.md). diff --git a/docs/implementation/macros/define_keyword.md b/docs/implementation/macros/define_keyword.md index 45bef5f4..c353d88b 100644 --- a/docs/implementation/macros/define_keyword.md +++ b/docs/implementation/macros/define_keyword.md @@ -10,8 +10,9 @@ The keyword string and the struct name are independent, so the marker can be nam ## Tests -`define_keyword!` has no dedicated test; the keywords it defines are exercised through the parser tests and expansion snapshots of the macros that use them — for example the `new`-prefixed forms pinned in the `basic_delegation` snapshots and the `open` statement pinned in the `namespaces` and `dispatching` targets. +- `define_keyword!` has no dedicated test; the keywords it defines are exercised through the parser tests and expansion snapshots of the macros that use them — for example the `new`-prefixed forms pinned in the `basic_delegation` snapshots and the `open` statement pinned in the `namespaces` and `dispatching` targets. ## Source -The macro is defined in [cgp-macro-core/src/macros/keyword.rs](../../../crates/macros/cgp-macro-core/src/macros/keyword.rs); the `IsKeyword` trait it implements lives in `cgp-macro-core/src/traits/`, and the keyword marker types that use it live in `cgp-macro-core/src/types/keyword*.rs`. The convention that custom keywords go through this macro is recorded in [cgp-macro-core/CLAUDE.md](../../../crates/macros/cgp-macro-core/CLAUDE.md). +- The macro is defined in [cgp-macro-core/src/macros/keyword.rs](../../../crates/macros/cgp-macro-core/src/macros/keyword.rs); the `IsKeyword` trait it implements lives in `cgp-macro-core/src/traits/`, and the keyword marker types that use it live in `cgp-macro-core/src/types/keyword*.rs`. +- The convention that custom keywords go through this macro is recorded in [cgp-macro-core/CLAUDE.md](../../../crates/macros/cgp-macro-core/CLAUDE.md). diff --git a/docs/implementation/macros/export_constructs.md b/docs/implementation/macros/export_constructs.md index 64bd33fc..68860f09 100644 --- a/docs/implementation/macros/export_constructs.md +++ b/docs/implementation/macros/export_constructs.md @@ -8,8 +8,9 @@ The point of the indirection is hygiene. Generated code interpolates the marker ## Tests -These macros have no dedicated test; they are exercised by every expansion snapshot in the suite, since the fully-qualified paths in generated code all originate from these markers. +- These macros have no dedicated test; they are exercised by every expansion snapshot in the suite, since the fully-qualified paths in generated code all originate from these markers. ## Source -The macros are defined in [cgp-macro-core/src/macros/export.rs](../../../crates/macros/cgp-macro-core/src/macros/export.rs); the marker set they generate lives in [cgp-macro-core/src/exports.rs](../../../crates/macros/cgp-macro-core/src/exports.rs), and the `::cgp::macro_prelude` re-export surface is what makes the emitted paths resolve. The convention that all CGP items are referenced through these markers is recorded in [cgp-macro-core/CLAUDE.md](../../../crates/macros/cgp-macro-core/CLAUDE.md). +- The macros are defined in [cgp-macro-core/src/macros/export.rs](../../../crates/macros/cgp-macro-core/src/macros/export.rs); the marker set they generate lives in [cgp-macro-core/src/exports.rs](../../../crates/macros/cgp-macro-core/src/exports.rs), and the `::cgp::macro_prelude` re-export surface is what makes the emitted paths resolve. +- The convention that all CGP items are referenced through these markers is recorded in [cgp-macro-core/CLAUDE.md](../../../crates/macros/cgp-macro-core/CLAUDE.md). diff --git a/docs/implementation/macros/parse_internal.md b/docs/implementation/macros/parse_internal.md index b99df22c..88e3fe18 100644 --- a/docs/implementation/macros/parse_internal.md +++ b/docs/implementation/macros/parse_internal.md @@ -14,8 +14,10 @@ A subtle interaction with the `?` expansion is that `parse_internal!` cannot be ## Tests -`parse_internal!` has no dedicated test; it is exercised by every macro-expansion snapshot in the suite, since essentially all generated code passes through it. Its error path is observed indirectly whenever a codegen change produces unparseable tokens during development. +- `parse_internal!` has no dedicated test; it is exercised by every macro-expansion snapshot in the suite, since essentially all generated code passes through it. Its error path is observed indirectly whenever a codegen change produces unparseable tokens during development. ## Source -The macro is defined in [cgp-macro-core/src/macros/parse.rs](../../../crates/macros/cgp-macro-core/src/macros/parse.rs) and the backing function in [cgp-macro-core/src/functions/parse_internal.rs](../../../crates/macros/cgp-macro-core/src/functions/parse_internal.rs). The `quote!` re-export it depends on is in `cgp-macro-core/src/vendor.rs`, and the prefix-stripping helper is `strip_macro_prelude` in `cgp-macro-core/src/functions/strip.rs`. The convention that all AST nodes are built through this macro is recorded in [cgp-macro-core/CLAUDE.md](../../../crates/macros/cgp-macro-core/CLAUDE.md). +- The macro is defined in [cgp-macro-core/src/macros/parse.rs](../../../crates/macros/cgp-macro-core/src/macros/parse.rs) and the backing function in [cgp-macro-core/src/functions/parse_internal.rs](../../../crates/macros/cgp-macro-core/src/functions/parse_internal.rs). +- The `quote!` re-export it depends on is in `cgp-macro-core/src/vendor.rs`, and the prefix-stripping helper is `strip_macro_prelude` in `cgp-macro-core/src/functions/strip.rs`. +- The convention that all AST nodes are built through this macro is recorded in [cgp-macro-core/CLAUDE.md](../../../crates/macros/cgp-macro-core/CLAUDE.md). diff --git a/docs/reference/attributes/derive_delegate.md b/docs/reference/attributes/derive_delegate.md index 1b527e24..ffd7c69b 100644 --- a/docs/reference/attributes/derive_delegate.md +++ b/docs/reference/attributes/derive_delegate.md @@ -147,6 +147,8 @@ Now `MyApp` implements `CanCalculateArea` through `RectangleArea` and ## Source -The attribute is parsed by `DeriveDelegateAttribute::parse` in [crates/macros/cgp-macro-core/src/types/attributes/derive_delegate/attribute.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/derive_delegate/attribute.rs), which reads the wrapper identifier and the angle-bracketed key (a single identifier or a parenthesized tuple). The dispatcher impl is built by the same file's `to_provider_impl`, which appends `__Components__` and `__Delegate__` generics, emits the `DelegateComponent<(params), Delegate = __Delegate__>` and `__Delegate__: ProviderTrait` bounds, and forwards each method through `trait_items_to_delegated_impl_items`. The attribute is collected in `types/attributes/cgp_component_attributes.rs` and emitted by `to_use_delegate_impls` in [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/item.rs). The `UseDelegate` provider and a worked single-key expansion are documented in [crates/core/cgp-component/src/providers/use_delegate.rs](../../../crates/core/cgp-component/src/providers/use_delegate.rs); the multi-attribute form with a custom `UseInputDelegate` is used in [crates/extra/cgp-handler/src/components/computer.rs](../../../crates/extra/cgp-handler/src/components/computer.rs). - -For the dispatcher impl it generates and the index of tests and snapshots, see the implementation document [implementation/asts/attributes.md](../../implementation/asts/attributes.md). +- Parsing: `DeriveDelegateAttribute::parse` in [crates/macros/cgp-macro-core/src/types/attributes/derive_delegate/attribute.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/derive_delegate/attribute.rs), which reads the wrapper identifier and the angle-bracketed key (a single identifier or a parenthesized tuple). +- Dispatcher impl: built by the same file's `to_provider_impl`, which appends `__Components__` and `__Delegate__` generics, emits the `DelegateComponent<(params), Delegate = __Delegate__>` and `__Delegate__: ProviderTrait` bounds, and forwards each method through `trait_items_to_delegated_impl_items`. +- Collection and emission: the attribute is collected in `types/attributes/cgp_component_attributes.rs` and emitted by `to_use_delegate_impls` in [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/item.rs). +- `UseDelegate` provider (and a worked single-key expansion): [crates/core/cgp-component/src/providers/use_delegate.rs](../../../crates/core/cgp-component/src/providers/use_delegate.rs); the multi-attribute form with a custom `UseInputDelegate` is used in [crates/extra/cgp-handler/src/components/computer.rs](../../../crates/extra/cgp-handler/src/components/computer.rs). +- Implementation document (the dispatcher impl it generates and the index of tests and snapshots): [implementation/asts/attributes.md](../../implementation/asts/attributes.md). diff --git a/docs/reference/attributes/extend.md b/docs/reference/attributes/extend.md index 3b2e0d15..fc1b715e 100644 --- a/docs/reference/attributes/extend.md +++ b/docs/reference/attributes/extend.md @@ -121,6 +121,7 @@ Because `HasScalarType` is a supertrait of `RectangleArea`, the abstract `Self:: ## Source -`#[extend(...)]` is parsed in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs) (the `extend` field of `FunctionAttributes`). For `#[cgp_fn]`, the bounds are added to the trait's supertraits and to the impl `where` clause in [crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs). For `#[cgp_component]`, the attribute is parsed by `CgpComponentAttributes::parse` and its bounds appended to the consumer trait's supertraits in [crates/macros/cgp-macro-core/src/types/attributes/cgp_component_attributes.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/cgp_component_attributes.rs). - -For what the attribute injects into each host and the index of tests and snapshots, see the implementation document [implementation/asts/attributes.md](../../implementation/asts/attributes.md). +- Parsing: `#[extend(...)]` is parsed in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs) (the `extend` field of `FunctionAttributes`). +- For `#[cgp_fn]`: the bounds are added to the trait's supertraits and to the impl `where` clause in [crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs). +- For `#[cgp_component]`: the attribute is parsed by `CgpComponentAttributes::parse` and its bounds appended to the consumer trait's supertraits in [crates/macros/cgp-macro-core/src/types/attributes/cgp_component_attributes.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/cgp_component_attributes.rs). +- Implementation document (what the attribute injects into each host and the index of tests and snapshots): [implementation/asts/attributes.md](../../implementation/asts/attributes.md). diff --git a/docs/reference/attributes/extend_where.md b/docs/reference/attributes/extend_where.md index 468fac9e..663bf22a 100644 --- a/docs/reference/attributes/extend_where.md +++ b/docs/reference/attributes/extend_where.md @@ -62,6 +62,6 @@ The `Scalar: Mul` bound, written in the function body, stays as ## Source -`#[extend_where(...)]` is parsed in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs) (the `extend_where` field of `FunctionAttributes`), and its predicates are added to both the trait and impl `where` clauses in [crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs). - -For what the attribute injects into its host and the index of tests and snapshots, see the implementation document [implementation/asts/attributes.md](../../implementation/asts/attributes.md). +- Parsing: `#[extend_where(...)]` is parsed in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs) (the `extend_where` field of `FunctionAttributes`). +- Injection: its predicates are added to both the trait and impl `where` clauses in [crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs). +- Implementation document (what the attribute injects into its host and the index of tests and snapshots): [implementation/asts/attributes.md](../../implementation/asts/attributes.md). diff --git a/docs/reference/attributes/implicit.md b/docs/reference/attributes/implicit.md index f1b00f41..071437c4 100644 --- a/docs/reference/attributes/implicit.md +++ b/docs/reference/attributes/implicit.md @@ -115,6 +115,7 @@ fn print_area(rect: &Rectangle) { ## Source -Implicit-argument parsing lives in [crates/macros/cgp-macro-core/src/functions/implicits/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/implicits/parse.rs), which extracts `#[implicit]`-marked arguments and validates the `self`/`mut` rules. The per-argument model is in [crates/macros/cgp-macro-core/src/types/implicits/](../../../crates/macros/cgp-macro-core/src/types/implicits/): `arg_field.rs` builds the `HasField` bound and the `let` binding, and `arg_fields.rs` adds the bounds to the impl generics and prepends the bindings to the body. The field-type-to-access-mode mapping (`.clone()`, `.as_str()`, and the reference/option/slice cases) is in [crates/macros/cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs) and [crates/macros/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs](../../../crates/macros/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs). - -For how `#[implicit]` arguments are parsed and lowered into `HasField` bounds and `let` bindings, and the index of tests, see the implementation document [implementation/entrypoints/cgp_fn.md](../../implementation/entrypoints/cgp_fn.md). +- Parsing: implicit-argument parsing lives in [crates/macros/cgp-macro-core/src/functions/implicits/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/implicits/parse.rs), which extracts `#[implicit]`-marked arguments and validates the `self`/`mut` rules. +- Per-argument model: [crates/macros/cgp-macro-core/src/types/implicits/](../../../crates/macros/cgp-macro-core/src/types/implicits/) — `arg_field.rs` builds the `HasField` bound and the `let` binding, and `arg_fields.rs` adds the bounds to the impl generics and prepends the bindings to the body. +- Field-type-to-access-mode mapping (`.clone()`, `.as_str()`, and the reference/option/slice cases): [crates/macros/cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs) and [crates/macros/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs](../../../crates/macros/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs). +- Implementation document (how `#[implicit]` arguments are parsed and lowered into `HasField` bounds and `let` bindings, and the index of tests): [implementation/entrypoints/cgp_fn.md](../../implementation/entrypoints/cgp_fn.md). diff --git a/docs/reference/attributes/use_provider.md b/docs/reference/attributes/use_provider.md index 0452f7a6..602b31ea 100644 --- a/docs/reference/attributes/use_provider.md +++ b/docs/reference/attributes/use_provider.md @@ -127,6 +127,7 @@ A context can now wire `AreaCalculatorComponent` to `ScaledArea`, ## Source -The outer form is parsed by `UseProviderAttribute` in [crates/macros/cgp-macro-core/src/types/attributes/use_provider/attribute.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/use_provider/attribute.rs); its `to_type_param_bounds` inserts the context type at index 0 of the trait's generic arguments, and `to_provider_bounds` builds the `where` predicate. The bounds are appended to the impl by `add_type_param_bounds` in `attributes.rs`. The attribute is collected for `#[cgp_impl]` in `types/attributes/cgp_impl_attributes.rs` and for `#[cgp_fn]` in `types/attributes/function.rs`, and applied in `types/cgp_impl/item.rs` and `types/cgp_fn/preprocessed.rs`. - -For the internal AST type, the bound completion, and the index of tests and snapshots, see the implementation document [implementation/asts/attributes.md](../../implementation/asts/attributes.md). +- Parsing: the outer form is parsed by `UseProviderAttribute` in [crates/macros/cgp-macro-core/src/types/attributes/use_provider/attribute.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/use_provider/attribute.rs); its `to_type_param_bounds` inserts the context type at index 0 of the trait's generic arguments, and `to_provider_bounds` builds the `where` predicate. +- Bound insertion: the bounds are appended to the impl by `add_type_param_bounds` in `attributes.rs`. +- Collection and application: the attribute is collected for `#[cgp_impl]` in `types/attributes/cgp_impl_attributes.rs` and for `#[cgp_fn]` in `types/attributes/function.rs`, and applied in `types/cgp_impl/item.rs` and `types/cgp_fn/preprocessed.rs`. +- Implementation document (the internal AST type, the bound completion, and the index of tests and snapshots): [implementation/asts/attributes.md](../../implementation/asts/attributes.md). diff --git a/docs/reference/attributes/use_type.md b/docs/reference/attributes/use_type.md index 909ef853..3ae1a115 100644 --- a/docs/reference/attributes/use_type.md +++ b/docs/reference/attributes/use_type.md @@ -178,6 +178,8 @@ The provider's `#[use_type]` adds `Self: HasScalarType` to its `where` clause an ## Source -The attribute is parsed by `UseTypeAttribute` in [crates/macros/cgp-macro-core/src/types/attributes/use_type/attribute.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/use_type/attribute.rs), with per-type entries (`as` alias and `=` equality) in `ident.rs`. The two-phase transform — substitute then add bounds — lives in `attributes.rs` as `transform_item_trait` (supertrait for `#[cgp_component]`) and `transform_item_impl` (`where` bound for impls), and the type-equality and foreign-context resolution are in `type_predicates.rs`. The identifier substitution itself is the `SubstituteAbstractType` `VisitMut` pass in [crates/macros/cgp-macro-core/src/visitors/substitute_abstract_type.rs](../../../crates/macros/cgp-macro-core/src/visitors/substitute_abstract_type.rs), which matches single-segment, argument-free type paths. The `= ...` rejection for component traits is enforced in `types/attributes/cgp_component_attributes.rs`. - -For the internal AST types, the two-phase transform, and the index of tests and snapshots, see the implementation document [implementation/asts/attributes.md](../../implementation/asts/attributes.md). +- Parsing: the attribute is parsed by `UseTypeAttribute` in [crates/macros/cgp-macro-core/src/types/attributes/use_type/attribute.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/use_type/attribute.rs), with per-type entries (`as` alias and `=` equality) in `ident.rs`. +- Two-phase transform (substitute then add bounds): lives in `attributes.rs` as `transform_item_trait` (supertrait for `#[cgp_component]`) and `transform_item_impl` (`where` bound for impls); the type-equality and foreign-context resolution are in `type_predicates.rs`. +- Identifier substitution: the `SubstituteAbstractType` `VisitMut` pass in [crates/macros/cgp-macro-core/src/visitors/substitute_abstract_type.rs](../../../crates/macros/cgp-macro-core/src/visitors/substitute_abstract_type.rs), which matches single-segment, argument-free type paths. +- `= ...` rejection for component traits: enforced in `types/attributes/cgp_component_attributes.rs`. +- Implementation document (the internal AST types, the two-phase transform, and the index of tests and snapshots): [implementation/asts/attributes.md](../../implementation/asts/attributes.md). diff --git a/docs/reference/attributes/uses.md b/docs/reference/attributes/uses.md index e9ca3074..7e63e7b2 100644 --- a/docs/reference/attributes/uses.md +++ b/docs/reference/attributes/uses.md @@ -105,6 +105,7 @@ The `#[uses(CanCalculateArea)]` attribute adds `Self: CanCalculateArea` to the g ## Source -`#[uses(...)]` parsing lives in [crates/macros/cgp-macro-core/src/types/attributes/uses.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/uses.rs) (the `UsesAttributes` type and its `to_type_param_bounds`), with the attribute dispatch in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs) for `#[cgp_fn]` and [crates/macros/cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs) for `#[cgp_impl]`. The bounds are added to the impl `where` clause in [crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs). - -For the internal AST type, what the attribute injects into each host, and the index of tests and snapshots, see the implementation document [implementation/asts/attributes.md](../../implementation/asts/attributes.md). +- Parsing: `#[uses(...)]` parsing lives in [crates/macros/cgp-macro-core/src/types/attributes/uses.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/uses.rs) (the `UsesAttributes` type and its `to_type_param_bounds`). +- Dispatch: the attribute dispatch is in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs) for `#[cgp_fn]` and [crates/macros/cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/cgp_impl_attributes.rs) for `#[cgp_impl]`. +- Injection: the bounds are added to the impl `where` clause in [crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/preprocessed.rs). +- Implementation document (the internal AST type, what the attribute injects into each host, and the index of tests and snapshots): [implementation/asts/attributes.md](../../implementation/asts/attributes.md). diff --git a/docs/reference/components/can_raise_error.md b/docs/reference/components/can_raise_error.md index f96417c2..5cb1330a 100644 --- a/docs/reference/components/can_raise_error.md +++ b/docs/reference/components/can_raise_error.md @@ -79,4 +79,6 @@ The provider names neither the context nor its concrete error type. It requires ## Source -`CanRaiseError` is defined in [crates/core/cgp-error/src/traits/can_raise_error.rs](../../../crates/core/cgp-error/src/traits/can_raise_error.rs) and `CanWrapError` in [crates/core/cgp-error/src/traits/can_wrap_error.rs](../../../crates/core/cgp-error/src/traits/can_wrap_error.rs). Both build on `HasErrorType` from [crates/core/cgp-error/src/traits/has_error_type.rs](../../../crates/core/cgp-error/src/traits/has_error_type.rs). The pluggable providers that implement them live in [crates/standalone/error/](../../../crates/standalone/error/). +- `CanRaiseError` is defined in [crates/core/cgp-error/src/traits/can_raise_error.rs](../../../crates/core/cgp-error/src/traits/can_raise_error.rs) and `CanWrapError` in [crates/core/cgp-error/src/traits/can_wrap_error.rs](../../../crates/core/cgp-error/src/traits/can_wrap_error.rs). +- Both build on `HasErrorType` from [crates/core/cgp-error/src/traits/has_error_type.rs](../../../crates/core/cgp-error/src/traits/has_error_type.rs). +- The pluggable providers that implement them live in [crates/standalone/error/](../../../crates/standalone/error/). diff --git a/docs/reference/components/computer.md b/docs/reference/components/computer.md index 621d6054..94349c48 100644 --- a/docs/reference/components/computer.md +++ b/docs/reference/components/computer.md @@ -106,4 +106,7 @@ The computer components are the infallible corner of the [handler family](../../ ## Source -The synchronous computers `Computer`/`ComputerRef` are defined in [crates/extra/cgp-handler/src/components/computer.rs](../../../crates/extra/cgp-handler/src/components/computer.rs), and the async computers `AsyncComputer`/`AsyncComputerRef` in [crates/extra/cgp-handler/src/components/async_computer.rs](../../../crates/extra/cgp-handler/src/components/async_computer.rs). The `UseInputDelegate` dispatch type is in [crates/extra/cgp-handler/src/types.rs](../../../crates/extra/cgp-handler/src/types.rs). The components are re-exported through `cgp::extra::handler`. For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_computer](../../implementation/entrypoints/cgp_computer.md). +- The synchronous computers `Computer`/`ComputerRef` are defined in [crates/extra/cgp-handler/src/components/computer.rs](../../../crates/extra/cgp-handler/src/components/computer.rs), and the async computers `AsyncComputer`/`AsyncComputerRef` in [crates/extra/cgp-handler/src/components/async_computer.rs](../../../crates/extra/cgp-handler/src/components/async_computer.rs). +- The `UseInputDelegate` dispatch type is in [crates/extra/cgp-handler/src/types.rs](../../../crates/extra/cgp-handler/src/types.rs). +- The components are re-exported through `cgp::extra::handler`. +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_computer](../../implementation/entrypoints/cgp_computer.md). diff --git a/docs/reference/components/handler.md b/docs/reference/components/handler.md index 90fe2146..c983187b 100644 --- a/docs/reference/components/handler.md +++ b/docs/reference/components/handler.md @@ -84,4 +84,6 @@ The function `run_with` works for any context that wires a handler for the given ## Source -`Handler` and `HandlerRef` are defined in [crates/extra/cgp-handler/src/components/handler.rs](../../../crates/extra/cgp-handler/src/components/handler.rs). The `ReturnInput` provider is in [crates/extra/cgp-handler/src/providers/return_input.rs](../../../crates/extra/cgp-handler/src/providers/return_input.rs), and the promotion combinators that lift simpler providers into `Handler` are in [crates/extra/cgp-handler/src/providers/](../../../crates/extra/cgp-handler/src/). The components are re-exported through `cgp::extra::handler`. +- `Handler` and `HandlerRef` are defined in [crates/extra/cgp-handler/src/components/handler.rs](../../../crates/extra/cgp-handler/src/components/handler.rs). +- The `ReturnInput` provider is in [crates/extra/cgp-handler/src/providers/return_input.rs](../../../crates/extra/cgp-handler/src/providers/return_input.rs), and the promotion combinators that lift simpler providers into `Handler` are in [crates/extra/cgp-handler/src/providers/](../../../crates/extra/cgp-handler/src/). +- The components are re-exported through `cgp::extra::handler`. diff --git a/docs/reference/components/has_error_type.md b/docs/reference/components/has_error_type.md index 549560da..e67b185a 100644 --- a/docs/reference/components/has_error_type.md +++ b/docs/reference/components/has_error_type.md @@ -70,4 +70,6 @@ This direct form makes plain that `HasErrorType` is an ordinary trait with a `De ## Source -The trait and the `ErrorOf` alias are defined in [crates/core/cgp-error/src/traits/has_error_type.rs](../../../crates/core/cgp-error/src/traits/has_error_type.rs). The `#[cgp_type]` machinery it relies on lives in [crates/macros/cgp-macro-core/src/types/cgp_type/](../../../crates/macros/cgp-macro-core/src/types/cgp_type/), and the underlying `HasType`/`TypeProvider`/`UseType` definitions are in [crates/core/cgp-type/src/](../../../crates/core/cgp-type/src/). The pluggable concrete error backends are in [crates/standalone/error/](../../../crates/standalone/error/). +- The trait and the `ErrorOf` alias are defined in [crates/core/cgp-error/src/traits/has_error_type.rs](../../../crates/core/cgp-error/src/traits/has_error_type.rs). +- The `#[cgp_type]` machinery it relies on lives in [crates/macros/cgp-macro-core/src/types/cgp_type/](../../../crates/macros/cgp-macro-core/src/types/cgp_type/), and the underlying `HasType`/`TypeProvider`/`UseType` definitions are in [crates/core/cgp-type/src/](../../../crates/core/cgp-type/src/). +- The pluggable concrete error backends are in [crates/standalone/error/](../../../crates/standalone/error/). diff --git a/docs/reference/components/has_runtime.md b/docs/reference/components/has_runtime.md index cada4a04..3ebf216b 100644 --- a/docs/reference/components/has_runtime.md +++ b/docs/reference/components/has_runtime.md @@ -89,4 +89,6 @@ The function names neither `TokioRuntime` nor any field; it works for any contex ## Source -`HasRuntimeType`, the `RuntimeTypeProvider` provider trait, and the `RuntimeOf` alias are defined in [crates/extra/cgp-runtime/src/traits/has_runtime_type.rs](../../../crates/extra/cgp-runtime/src/traits/has_runtime_type.rs). `HasRuntime` and its `RuntimeGetter` provider trait are in [crates/extra/cgp-runtime/src/traits/has_runtime.rs](../../../crates/extra/cgp-runtime/src/traits/has_runtime.rs), re-exported through [crates/extra/cgp-runtime/src/lib.rs](../../../crates/extra/cgp-runtime/src/lib.rs) and reached from the facade as `cgp::extra::runtime`. The `#[cgp_type]` and `#[cgp_getter]` expansions these rely on live under [crates/macros/cgp-macro-core/src/types/](../../../crates/macros/cgp-macro-core/src/types/). +- `HasRuntimeType`, the `RuntimeTypeProvider` provider trait, and the `RuntimeOf` alias are defined in [crates/extra/cgp-runtime/src/traits/has_runtime_type.rs](../../../crates/extra/cgp-runtime/src/traits/has_runtime_type.rs). +- `HasRuntime` and its `RuntimeGetter` provider trait are in [crates/extra/cgp-runtime/src/traits/has_runtime.rs](../../../crates/extra/cgp-runtime/src/traits/has_runtime.rs), re-exported through [crates/extra/cgp-runtime/src/lib.rs](../../../crates/extra/cgp-runtime/src/lib.rs) and reached from the facade as `cgp::extra::runtime`. +- The `#[cgp_type]` and `#[cgp_getter]` expansions these rely on live under [crates/macros/cgp-macro-core/src/types/](../../../crates/macros/cgp-macro-core/src/types/). diff --git a/docs/reference/components/has_type.md b/docs/reference/components/has_type.md index 4e98d75c..697c83ed 100644 --- a/docs/reference/components/has_type.md +++ b/docs/reference/components/has_type.md @@ -72,4 +72,7 @@ where ## Source -The trait, the `TypeProvider` provider trait, and the `TypeOf` alias are defined in [crates/core/cgp-type/src/traits/has_type.rs](../../../crates/core/cgp-type/src/traits/has_type.rs). The `UseType` provider and its `TypeProvider` impl are in [crates/core/cgp-type/src/impls/use_type.rs](../../../crates/core/cgp-type/src/impls/use_type.rs). The `#[cgp_type]` macro that builds named components on this substrate lives in [crates/macros/cgp-macro-core/src/types/cgp_type/](../../../crates/macros/cgp-macro-core/src/types/cgp_type/). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_type](../../implementation/entrypoints/cgp_type.md). +- The trait, the `TypeProvider` provider trait, and the `TypeOf` alias are defined in [crates/core/cgp-type/src/traits/has_type.rs](../../../crates/core/cgp-type/src/traits/has_type.rs). +- The `UseType` provider and its `TypeProvider` impl are in [crates/core/cgp-type/src/impls/use_type.rs](../../../crates/core/cgp-type/src/impls/use_type.rs). +- The `#[cgp_type]` macro that builds named components on this substrate lives in [crates/macros/cgp-macro-core/src/types/cgp_type/](../../../crates/macros/cgp-macro-core/src/types/cgp_type/). +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_type](../../implementation/entrypoints/cgp_type.md). diff --git a/docs/reference/components/producer.md b/docs/reference/components/producer.md index 26f23112..7fe7df1b 100644 --- a/docs/reference/components/producer.md +++ b/docs/reference/components/producer.md @@ -80,4 +80,7 @@ Here `MagicNumber` produces `42` from the `Code` tag alone, and `App` delegates ## Source -`Producer` is defined in [crates/extra/cgp-handler/src/components/produce.rs](../../../crates/extra/cgp-handler/src/components/produce.rs). The `Promote` combinator that lifts it into a `Computer` is in [crates/extra/cgp-handler/src/providers/promote.rs](../../../crates/extra/cgp-handler/src/providers/promote.rs), and the `PromoteProducer` table in [crates/extra/cgp-handler/src/providers/promote_all.rs](../../../crates/extra/cgp-handler/src/providers/promote_all.rs). The component is re-exported through `cgp::extra::handler`. For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_producer](../../implementation/entrypoints/cgp_producer.md). +- `Producer` is defined in [crates/extra/cgp-handler/src/components/produce.rs](../../../crates/extra/cgp-handler/src/components/produce.rs). +- The `Promote` combinator that lifts it into a `Computer` is in [crates/extra/cgp-handler/src/providers/promote.rs](../../../crates/extra/cgp-handler/src/providers/promote.rs), and the `PromoteProducer` table in [crates/extra/cgp-handler/src/providers/promote_all.rs](../../../crates/extra/cgp-handler/src/providers/promote_all.rs). +- The component is re-exported through `cgp::extra::handler`. +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_producer](../../implementation/entrypoints/cgp_producer.md). diff --git a/docs/reference/components/runner.md b/docs/reference/components/runner.md index 962f8d68..ac9a62f6 100644 --- a/docs/reference/components/runner.md +++ b/docs/reference/components/runner.md @@ -103,4 +103,5 @@ The `Runner` family is most often paired with [`HasRuntime`](has_runtime.md): a ## Source -`CanRun` / `Runner` and `CanSendRun` / `SendRunner` are defined together in [crates/extra/cgp-run/src/lib.rs](../../../crates/extra/cgp-run/src/lib.rs), reached from the facade as `cgp::extra::run`. The `#[cgp_component]` and `#[derive_delegate]` expansions they rely on live under [crates/macros/cgp-macro-core/src/](../../../crates/macros/cgp-macro-core/src/). +- `CanRun` / `Runner` and `CanSendRun` / `SendRunner` are defined together in [crates/extra/cgp-run/src/lib.rs](../../../crates/extra/cgp-run/src/lib.rs), reached from the facade as `cgp::extra::run`. +- The `#[cgp_component]` and `#[derive_delegate]` expansions they rely on live under [crates/macros/cgp-macro-core/src/](../../../crates/macros/cgp-macro-core/src/). diff --git a/docs/reference/components/try_computer.md b/docs/reference/components/try_computer.md index ede928a1..2aff9064 100644 --- a/docs/reference/components/try_computer.md +++ b/docs/reference/components/try_computer.md @@ -94,4 +94,7 @@ The provider `ParseU64` returns its `u64` output or the context's abstract error ## Source -`TryComputer` and `TryComputerRef` are defined in [crates/extra/cgp-handler/src/components/try_compute.rs](../../../crates/extra/cgp-handler/src/components/try_compute.rs). The `ReturnInput` provider is in [crates/extra/cgp-handler/src/providers/return_input.rs](../../../crates/extra/cgp-handler/src/providers/return_input.rs), and the promotion combinators in [crates/extra/cgp-handler/src/providers/](../../../crates/extra/cgp-handler/src/). The components are re-exported through `cgp::extra::handler`. For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_computer](../../implementation/entrypoints/cgp_computer.md). +- `TryComputer` and `TryComputerRef` are defined in [crates/extra/cgp-handler/src/components/try_compute.rs](../../../crates/extra/cgp-handler/src/components/try_compute.rs). +- The `ReturnInput` provider is in [crates/extra/cgp-handler/src/providers/return_input.rs](../../../crates/extra/cgp-handler/src/providers/return_input.rs), and the promotion combinators in [crates/extra/cgp-handler/src/providers/](../../../crates/extra/cgp-handler/src/). +- The components are re-exported through `cgp::extra::handler`. +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_computer](../../implementation/entrypoints/cgp_computer.md). diff --git a/docs/reference/derives/derive_build_field.md b/docs/reference/derives/derive_build_field.md index 50f2602c..3790fcb1 100644 --- a/docs/reference/derives/derive_build_field.md +++ b/docs/reference/derives/derive_build_field.md @@ -129,6 +129,7 @@ Each step changes the partial type, and only after the last field is set does th ## Source -The derive entry point is `derive_build_field` in [crates/macros/cgp-macro-lib/src/derive_build_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_build_field.rs), which builds an `ItemCgpRecord` and calls `to_build_field_items()`. That method, in [crates/macros/cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), composes the helpers in the [`derive_builder/`](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/) submodule (`builder_struct.rs`, `has_builder_impl.rs`, `into_builder_impl.rs`, `partial_data.rs`, `finalize_build_impl.rs`, `update_field_impls.rs`, `has_field_impls.rs`). The `BuildField` and `FinalizeBuild` traits are in [crates/core/cgp-field/src/traits/build_field.rs](../../../crates/core/cgp-field/src/traits/build_field.rs), `UpdateField` in `update_field.rs`, `HasBuilder`/`IntoBuilder` in `has_builder.rs`, `PartialData` in `partial_data.rs`, and the `MapType` markers in `crates/core/cgp-field/src/impls/map_type.rs`. - -For the full internal walkthrough — the builder helpers, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_build_field.md](../../implementation/entrypoints/derive_build_field.md). +- Entry point: `derive_build_field` in [crates/macros/cgp-macro-lib/src/derive_build_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_build_field.rs), which builds an `ItemCgpRecord` and calls `to_build_field_items()`. +- Codegen: that method, in [crates/macros/cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), composes the helpers in the [`derive_builder/`](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/) submodule (`builder_struct.rs`, `has_builder_impl.rs`, `into_builder_impl.rs`, `partial_data.rs`, `finalize_build_impl.rs`, `update_field_impls.rs`, `has_field_impls.rs`). +- Runtime traits: `BuildField` and `FinalizeBuild` in [crates/core/cgp-field/src/traits/build_field.rs](../../../crates/core/cgp-field/src/traits/build_field.rs), `UpdateField` in `update_field.rs`, `HasBuilder`/`IntoBuilder` in `has_builder.rs`, `PartialData` in `partial_data.rs`, and the `MapType` markers in `crates/core/cgp-field/src/impls/map_type.rs`. +- Internal walkthrough (the builder helpers, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/derive_build_field.md](../../implementation/entrypoints/derive_build_field.md). diff --git a/docs/reference/derives/derive_cgp_data.md b/docs/reference/derives/derive_cgp_data.md index 094b26a5..03a7ec19 100644 --- a/docs/reference/derives/derive_cgp_data.md +++ b/docs/reference/derives/derive_cgp_data.md @@ -197,6 +197,7 @@ These two views are what higher-level constructs build on: builders and field-di ## Source -The derive entry point is `derive_cgp_data` in [crates/macros/cgp-macro-lib/src/cgp_data.rs](../../../crates/macros/cgp-macro-lib/src/cgp_data.rs), which parses the input into `ItemCgpData` and calls `to_items()`. The dispatch on struct vs. enum is in [crates/macros/cgp-macro-core/src/types/cgp_data/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/item.rs); the record path is in `record.rs` and the variant path in `variant.rs` in the same directory, which delegate to the `derive_has_fields/`, `derive_builder/`, `derive_extractor/`, and `derive_from_variant.rs` submodules. The runtime traits are in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/) and the `MapType` markers in `crates/core/cgp-field/src/impls/map_type.rs`. - -For the full internal walkthrough — the shape dispatch, the record and variant codegen it composes, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_cgp_data.md](../../implementation/entrypoints/derive_cgp_data.md). +- Entry point: `derive_cgp_data` in [crates/macros/cgp-macro-lib/src/cgp_data.rs](../../../crates/macros/cgp-macro-lib/src/cgp_data.rs), which parses the input into `ItemCgpData` and calls `to_items()`. +- Shape dispatch: struct vs. enum in [crates/macros/cgp-macro-core/src/types/cgp_data/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/item.rs); the record path is in `record.rs` and the variant path in `variant.rs` in the same directory, which delegate to the `derive_has_fields/`, `derive_builder/`, `derive_extractor/`, and `derive_from_variant.rs` submodules. +- Runtime traits: [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/); the `MapType` markers in `crates/core/cgp-field/src/impls/map_type.rs`. +- Internal walkthrough (the shape dispatch, the record and variant codegen it composes, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/derive_cgp_data.md](../../implementation/entrypoints/derive_cgp_data.md). diff --git a/docs/reference/derives/derive_cgp_record.md b/docs/reference/derives/derive_cgp_record.md index 8319865c..88f955ca 100644 --- a/docs/reference/derives/derive_cgp_record.md +++ b/docs/reference/derives/derive_cgp_record.md @@ -134,6 +134,7 @@ If a field were left unset before `finalize_build`, the call would not compile ## Source -The derive entry point is `derive_cgp_record` in [crates/macros/cgp-macro-lib/src/cgp_record.rs](../../../crates/macros/cgp-macro-lib/src/cgp_record.rs), which parses an `ItemCgpRecord` and calls `to_items()`. The record codegen is in [crates/macros/cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), which composes `derive_has_field_impls_from_struct`, `derive_has_fields_impls_from_struct`, and the builder helpers in the `derive_builder/` submodule. The runtime traits (`HasBuilder`, `IntoBuilder`, `PartialData`, `FinalizeBuild`, `UpdateField`, `BuildField`, `HasFields`, `FromFields`, `ToFields`) live in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). - -For the full internal walkthrough — the codegen it composes, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_cgp_record.md](../../implementation/entrypoints/derive_cgp_record.md). +- Entry point: `derive_cgp_record` in [crates/macros/cgp-macro-lib/src/cgp_record.rs](../../../crates/macros/cgp-macro-lib/src/cgp_record.rs), which parses an `ItemCgpRecord` and calls `to_items()`. +- Record codegen: [crates/macros/cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs), which composes `derive_has_field_impls_from_struct`, `derive_has_fields_impls_from_struct`, and the builder helpers in the `derive_builder/` submodule. +- Runtime traits: `HasBuilder`, `IntoBuilder`, `PartialData`, `FinalizeBuild`, `UpdateField`, `BuildField`, `HasFields`, `FromFields`, `ToFields` in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). +- Internal walkthrough (the codegen it composes, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/derive_cgp_record.md](../../implementation/entrypoints/derive_cgp_record.md). diff --git a/docs/reference/derives/derive_cgp_variant.md b/docs/reference/derives/derive_cgp_variant.md index 4be59141..48cd31a0 100644 --- a/docs/reference/derives/derive_cgp_variant.md +++ b/docs/reference/derives/derive_cgp_variant.md @@ -120,6 +120,7 @@ Because each `extract_field` narrows the remainder type, the compiler knows afte ## Source -The derive entry point is `derive_cgp_variant` in [crates/macros/cgp-macro-lib/src/cgp_variant.rs](../../../crates/macros/cgp-macro-lib/src/cgp_variant.rs), which parses an `ItemCgpVariant` and calls `to_items()`. The variant codegen is in [crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which composes `derive_has_fields_impls_from_enum`, `derive_from_variant_from_enum`, and the extractor helpers in the `derive_extractor/` submodule. The runtime traits (`HasExtractor`, `HasExtractorRef`, `HasExtractorMut`, `ExtractField`, `FinalizeExtract`, `FromVariant`, `HasFields`, `FromFields`, `ToFields`) live in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). - -For the full internal walkthrough — the codegen it composes, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_cgp_variant.md](../../implementation/entrypoints/derive_cgp_variant.md). +- Entry point: `derive_cgp_variant` in [crates/macros/cgp-macro-lib/src/cgp_variant.rs](../../../crates/macros/cgp-macro-lib/src/cgp_variant.rs), which parses an `ItemCgpVariant` and calls `to_items()`. +- Variant codegen: [crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), which composes `derive_has_fields_impls_from_enum`, `derive_from_variant_from_enum`, and the extractor helpers in the `derive_extractor/` submodule. +- Runtime traits: `HasExtractor`, `HasExtractorRef`, `HasExtractorMut`, `ExtractField`, `FinalizeExtract`, `FromVariant`, `HasFields`, `FromFields`, `ToFields` in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). +- Internal walkthrough (the codegen it composes, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/derive_cgp_variant.md](../../implementation/entrypoints/derive_cgp_variant.md). diff --git a/docs/reference/derives/derive_extract_field.md b/docs/reference/derives/derive_extract_field.md index 3782b199..0853b3d9 100644 --- a/docs/reference/derives/derive_extract_field.md +++ b/docs/reference/derives/derive_extract_field.md @@ -146,6 +146,7 @@ The derive only accepts enums whose every variant is a single-field tuple varian ## Source -The derive entry point is `derive_extract_field` in [crates/macros/cgp-macro-lib/src/derive_extract_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_extract_field.rs), which builds an `ItemCgpVariant` and calls `to_extract_field_items()`. That method, in [crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), composes the helpers in the [`derive_extractor/`](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/) submodule (`extractor_enum.rs`, `has_extractor_impl.rs`, `partial_data.rs`, `finalize_extract_impl.rs`, `extract_field_impls.rs`). The `ExtractField`, `HasExtractor`/`HasExtractorRef`/`HasExtractorMut`, `FinalizeExtract`, and `FinalizeExtractResult` traits are in [crates/core/cgp-field/src/traits/extract_field.rs](../../../crates/core/cgp-field/src/traits/extract_field.rs), `PartialData` in `partial_data.rs`, and the `MapType`/`MapTypeRef` markers in `crates/core/cgp-field/src/impls/`. - -For the full internal walkthrough — the extractor helpers, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_extract_field.md](../../implementation/entrypoints/derive_extract_field.md). +- Entry point: `derive_extract_field` in [crates/macros/cgp-macro-lib/src/derive_extract_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_extract_field.rs), which builds an `ItemCgpVariant` and calls `to_extract_field_items()`. +- Codegen: that method, in [crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), composes the helpers in the [`derive_extractor/`](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/) submodule (`extractor_enum.rs`, `has_extractor_impl.rs`, `partial_data.rs`, `finalize_extract_impl.rs`, `extract_field_impls.rs`). +- Runtime traits: `ExtractField`, `HasExtractor`/`HasExtractorRef`/`HasExtractorMut`, `FinalizeExtract`, and `FinalizeExtractResult` in [crates/core/cgp-field/src/traits/extract_field.rs](../../../crates/core/cgp-field/src/traits/extract_field.rs), `PartialData` in `partial_data.rs`, and the `MapType`/`MapTypeRef` markers in `crates/core/cgp-field/src/impls/`. +- Internal walkthrough (the extractor helpers, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/derive_extract_field.md](../../implementation/entrypoints/derive_extract_field.md). diff --git a/docs/reference/derives/derive_from_variant.md b/docs/reference/derives/derive_from_variant.md index 7902d564..03031ab2 100644 --- a/docs/reference/derives/derive_from_variant.md +++ b/docs/reference/derives/derive_from_variant.md @@ -86,6 +86,7 @@ The derive only accepts enums whose every variant is a single-field tuple varian ## Source -The derive entry point is `derive_from_variant` in [crates/macros/cgp-macro-lib/src/derive_from_variant.rs](../../../crates/macros/cgp-macro-lib/src/derive_from_variant.rs), which builds an `ItemCgpVariant` and calls `to_from_variant_impls()`. That method, in [crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), delegates to `derive_from_variant_from_enum` in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs). The `FromVariant` trait is in [crates/core/cgp-field/src/traits/from_variant.rs](../../../crates/core/cgp-field/src/traits/from_variant.rs). - -For the full internal walkthrough — the per-variant codegen, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_from_variant.md](../../implementation/entrypoints/derive_from_variant.md). +- Entry point: `derive_from_variant` in [crates/macros/cgp-macro-lib/src/derive_from_variant.rs](../../../crates/macros/cgp-macro-lib/src/derive_from_variant.rs), which builds an `ItemCgpVariant` and calls `to_from_variant_impls()`. +- Codegen: that method, in [crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs), delegates to `derive_from_variant_from_enum` in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs). +- `FromVariant` trait: [crates/core/cgp-field/src/traits/from_variant.rs](../../../crates/core/cgp-field/src/traits/from_variant.rs). +- Internal walkthrough (the per-variant codegen, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/derive_from_variant.md](../../implementation/entrypoints/derive_from_variant.md). diff --git a/docs/reference/derives/derive_has_field.md b/docs/reference/derives/derive_has_field.md index 404a0df3..d107a6ed 100644 --- a/docs/reference/derives/derive_has_field.md +++ b/docs/reference/derives/derive_has_field.md @@ -173,6 +173,7 @@ In practice the explicit `HasField` bound is rarely written by hand. The same `n ## Source -The derive entry point is `derive_has_field` in [crates/macros/cgp-macro-lib/src/derive_has_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_field.rs), registered as the `HasField` proc-macro derive in [crates/macros/cgp-macro/src/lib.rs](../../../crates/macros/cgp-macro/src/lib.rs). It parses the input as a `syn::ItemStruct`, wraps it in an `ItemCgpRecord` ([crates/macros/cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs)), and calls `to_has_field_impls`, whose codegen lives in `derive_has_field_impls_from_struct` in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_field.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_field.rs) — this is where named fields are mapped to `Symbol` tags and unnamed fields to `Index` tags, and where both the `HasField` and `HasFieldMut` impls are emitted. The traits themselves are defined in [crates/core/cgp-field/src/traits/has_field.rs](../../../crates/core/cgp-field/src/traits/has_field.rs) and [crates/core/cgp-field/src/traits/has_field_mut.rs](../../../crates/core/cgp-field/src/traits/has_field_mut.rs). - -For the full internal walkthrough — the codegen helper that synthesizes each impl, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_has_field.md](../../implementation/entrypoints/derive_has_field.md). +- Entry point: `derive_has_field` in [crates/macros/cgp-macro-lib/src/derive_has_field.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_field.rs), registered as the `HasField` proc-macro derive in [crates/macros/cgp-macro/src/lib.rs](../../../crates/macros/cgp-macro/src/lib.rs). It parses the input as a `syn::ItemStruct`, wraps it in an `ItemCgpRecord` ([crates/macros/cgp-macro-core/src/types/cgp_data/record.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/record.rs)), and calls `to_has_field_impls`. +- Codegen: `derive_has_field_impls_from_struct` in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_field.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_field.rs) — this is where named fields are mapped to `Symbol` tags and unnamed fields to `Index` tags, and where both the `HasField` and `HasFieldMut` impls are emitted. +- Traits: [crates/core/cgp-field/src/traits/has_field.rs](../../../crates/core/cgp-field/src/traits/has_field.rs) and [crates/core/cgp-field/src/traits/has_field_mut.rs](../../../crates/core/cgp-field/src/traits/has_field_mut.rs). +- Internal walkthrough (the codegen helper that synthesizes each impl, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/derive_has_field.md](../../implementation/entrypoints/derive_has_field.md). diff --git a/docs/reference/derives/derive_has_fields.md b/docs/reference/derives/derive_has_fields.md index fb189579..13589066 100644 --- a/docs/reference/derives/derive_has_fields.md +++ b/docs/reference/derives/derive_has_fields.md @@ -149,6 +149,7 @@ Generic algorithms key off the `Fields` type rather than the concrete struct. Th ## Source -The derive entry point is `derive_has_fields` in [crates/macros/cgp-macro-lib/src/derive_has_fields.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_fields.rs), registered as the `HasFields` proc-macro derive in [crates/macros/cgp-macro/src/lib.rs](../../../crates/macros/cgp-macro/src/lib.rs). It dispatches on the parsed item: structs go through `ItemCgpRecord::to_has_fields_impls` → `derive_has_fields_impls_from_struct`, and enums through `derive_has_fields_impls_from_enum`, both in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/). Within that module, `product.rs` (`item_fields_to_product_type`) builds the struct `Fields` product, `sum.rs` (`variants_to_sum_type`) builds the enum `Fields` sum, and `from_fields_*`, `to_fields_*`, and `to_fields_ref_*` build the conversion impls. The traits are defined in [crates/core/cgp-field/src/traits/has_fields.rs](../../../crates/core/cgp-field/src/traits/has_fields.rs), [crates/core/cgp-field/src/traits/to_fields.rs](../../../crates/core/cgp-field/src/traits/to_fields.rs), and [crates/core/cgp-field/src/traits/from_fields.rs](../../../crates/core/cgp-field/src/traits/from_fields.rs); the `Field`, `Either`, and `Void` building blocks live under [crates/core/cgp-field/src/types/](../../../crates/core/cgp-field/src/types/). - -For the full internal walkthrough — the codegen helpers that build the product and sum spines, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/derive_has_fields.md](../../implementation/entrypoints/derive_has_fields.md). +- Entry point: `derive_has_fields` in [crates/macros/cgp-macro-lib/src/derive_has_fields.rs](../../../crates/macros/cgp-macro-lib/src/derive_has_fields.rs), registered as the `HasFields` proc-macro derive in [crates/macros/cgp-macro/src/lib.rs](../../../crates/macros/cgp-macro/src/lib.rs). It dispatches on the parsed item: structs go through `ItemCgpRecord::to_has_fields_impls` → `derive_has_fields_impls_from_struct`, and enums through `derive_has_fields_impls_from_enum`, both in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/). +- Codegen: within that module, `product.rs` (`item_fields_to_product_type`) builds the struct `Fields` product, `sum.rs` (`variants_to_sum_type`) builds the enum `Fields` sum, and `from_fields_*`, `to_fields_*`, and `to_fields_ref_*` build the conversion impls. +- Traits: [crates/core/cgp-field/src/traits/has_fields.rs](../../../crates/core/cgp-field/src/traits/has_fields.rs), [crates/core/cgp-field/src/traits/to_fields.rs](../../../crates/core/cgp-field/src/traits/to_fields.rs), and [crates/core/cgp-field/src/traits/from_fields.rs](../../../crates/core/cgp-field/src/traits/from_fields.rs); the `Field`, `Either`, and `Void` building blocks live under [crates/core/cgp-field/src/types/](../../../crates/core/cgp-field/src/types/). +- Internal walkthrough (the codegen helpers that build the product and sum spines, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/derive_has_fields.md](../../implementation/entrypoints/derive_has_fields.md). diff --git a/docs/reference/macros/async_trait.md b/docs/reference/macros/async_trait.md index a9b12b5a..b538c636 100644 --- a/docs/reference/macros/async_trait.md +++ b/docs/reference/macros/async_trait.md @@ -135,6 +135,7 @@ The generated future carries no `Send` bound. Because the rewrite produces a bar ## Source -The macro entry point is `async_trait` in [crates/macros/cgp-async-macro/src/lib.rs](../../../crates/macros/cgp-async-macro/src/lib.rs), a `#[proc_macro_attribute]` that discards its attribute arguments and forwards the annotated item to `impl_async`. The rewrite lives in [crates/macros/cgp-async-macro/src/impl_async.rs](../../../crates/macros/cgp-async-macro/src/impl_async.rs): it parses the item as a `syn::ItemTrait`, and on success walks the trait's methods, replacing each `async` signature's output with `-> impl ::core::future::Future` and clearing the `async` keyword; if the item does not parse as a trait, it is returned unchanged. The macro is re-exported into the prelude from [crates/main/cgp-core/src/prelude.rs](../../../crates/main/cgp-core/src/prelude.rs), so `use cgp::prelude::*;` brings it into scope. - -For the internal walkthrough — the parse-or-passthrough structure, the signature rewrite, the default-body limitation, and the index of tests — see the implementation document [implementation/entrypoints/async_trait.md](../../implementation/entrypoints/async_trait.md). +- Entry point: `async_trait` in [crates/macros/cgp-async-macro/src/lib.rs](../../../crates/macros/cgp-async-macro/src/lib.rs), a `#[proc_macro_attribute]` that discards its attribute arguments and forwards the annotated item to `impl_async`. +- Rewrite: [crates/macros/cgp-async-macro/src/impl_async.rs](../../../crates/macros/cgp-async-macro/src/impl_async.rs) — it parses the item as a `syn::ItemTrait`, and on success walks the trait's methods, replacing each `async` signature's output with `-> impl ::core::future::Future` and clearing the `async` keyword; if the item does not parse as a trait, it is returned unchanged. +- Prelude re-export: [crates/main/cgp-core/src/prelude.rs](../../../crates/main/cgp-core/src/prelude.rs), so `use cgp::prelude::*;` brings it into scope. +- Internal walkthrough (the parse-or-passthrough structure, the signature rewrite, the default-body limitation, and the index of tests): [implementation/entrypoints/async_trait.md](../../implementation/entrypoints/async_trait.md). diff --git a/docs/reference/macros/blanket_trait.md b/docs/reference/macros/blanket_trait.md index aedd6961..6ec2d28c 100644 --- a/docs/reference/macros/blanket_trait.md +++ b/docs/reference/macros/blanket_trait.md @@ -167,6 +167,7 @@ fn run(ctx: &Context) { ## Source -The macro entry point is `blanket_trait` in [crates/macros/cgp-macro-lib/src/blanket_trait.rs](../../../crates/macros/cgp-macro-lib/src/blanket_trait.rs), which parses the optional context identifier (defaulting to `__Context__` when the attribute argument is empty) and the trait, then runs `item.to_items()?`. The logic lives in [crates/macros/cgp-macro-core/src/types/blanket_trait.rs](../../../crates/macros/cgp-macro-core/src/types/blanket_trait.rs): `to_item_impl` walks the trait items, forwards each default method/const body and associated-type assignment into the impl, lifts associated types into impl generics, moves associated-type bounds into the `where` clause, and appends the trait's supertraits as the `__Context__: ...` predicate. The `Self`-to-parameter rewriting for associated types is done by `RemoveSelfPathVisitor` in [crates/macros/cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). - -For the full internal walkthrough — the codegen walk, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/blanket_trait.md](../../implementation/entrypoints/blanket_trait.md). +- Entry point: `blanket_trait` in [crates/macros/cgp-macro-lib/src/blanket_trait.rs](../../../crates/macros/cgp-macro-lib/src/blanket_trait.rs), which parses the optional context identifier (defaulting to `__Context__` when the attribute argument is empty) and the trait, then runs `item.to_items()?`. +- Logic: [crates/macros/cgp-macro-core/src/types/blanket_trait.rs](../../../crates/macros/cgp-macro-core/src/types/blanket_trait.rs) — `to_item_impl` walks the trait items, forwards each default method/const body and associated-type assignment into the impl, lifts associated types into impl generics, moves associated-type bounds into the `where` clause, and appends the trait's supertraits as the `__Context__: ...` predicate. +- `Self`-to-parameter rewriting for associated types: `RemoveSelfPathVisitor` in [crates/macros/cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). +- Internal walkthrough (the codegen walk, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/blanket_trait.md](../../implementation/entrypoints/blanket_trait.md). diff --git a/docs/reference/macros/cgp_auto_dispatch.md b/docs/reference/macros/cgp_auto_dispatch.md index 88a00651..53eafa4a 100644 --- a/docs/reference/macros/cgp_auto_dispatch.md +++ b/docs/reference/macros/cgp_auto_dispatch.md @@ -135,6 +135,6 @@ The macro rejects trait methods with non-lifetime generic parameters, so a dispa ## Source -The macro is the `cgp_auto_dispatch` entry point in [crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs), forwarded from the proc-macro shim in [crates/macros/cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs) and re-exported through [crates/main/cgp-extra/src/prelude.rs](../../../crates/main/cgp-extra/src/prelude.rs). The matchers it generates live in [crates/extra/cgp-dispatch/src/providers/matchers/](../../../crates/extra/cgp-dispatch/src/providers/matchers/). - -For the internal walkthrough — the blanket-impl and per-variant-computer helpers, the matcher selection, the lifetime elaboration, and the index of behavioral tests — see the implementation document [implementation/entrypoints/cgp_auto_dispatch.md](../../implementation/entrypoints/cgp_auto_dispatch.md). +- Entry point: `cgp_auto_dispatch` in [crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs), forwarded from the proc-macro shim in [crates/macros/cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs) and re-exported through [crates/main/cgp-extra/src/prelude.rs](../../../crates/main/cgp-extra/src/prelude.rs). +- Matchers it generates: [crates/extra/cgp-dispatch/src/providers/matchers/](../../../crates/extra/cgp-dispatch/src/providers/matchers/). +- Internal walkthrough (the blanket-impl and per-variant-computer helpers, the matcher selection, the lifetime elaboration, and the index of behavioral tests): [implementation/entrypoints/cgp_auto_dispatch.md](../../implementation/entrypoints/cgp_auto_dispatch.md). diff --git a/docs/reference/macros/cgp_auto_getter.md b/docs/reference/macros/cgp_auto_getter.md index b1cf1329..4c0c9df9 100644 --- a/docs/reference/macros/cgp_auto_getter.md +++ b/docs/reference/macros/cgp_auto_getter.md @@ -158,6 +158,7 @@ The explicit form is more verbose but requires no understanding of `HasField` or ## Source -The macro entry point is `cgp_auto_getter` in [crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs), which rejects any attribute argument and runs `ItemCgpAutoGetter::preprocess(...).to_items()`. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_auto_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_auto_getter/): `item.rs` sets the `__Context__` context identifier and drives field parsing, and `blanket.rs` builds the single blanket impl. Getter parsing — including the `&str`/`Option<&T>`/`&[T]`/owned shorthands and the associated-type rules — is shared with `#[cgp_getter]` in [crates/macros/cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs), [crates/macros/cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), and [crates/macros/cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/). - -For the full internal walkthrough — the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/cgp_auto_getter.md](../../implementation/entrypoints/cgp_auto_getter.md). +- Entry point: `cgp_auto_getter` in [crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs), which rejects any attribute argument and runs `ItemCgpAutoGetter::preprocess(...).to_items()`. +- Logic: [crates/macros/cgp-macro-core/src/types/cgp_auto_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_auto_getter/) — `item.rs` sets the `__Context__` context identifier and drives field parsing, and `blanket.rs` builds the single blanket impl. +- Getter parsing (including the `&str`/`Option<&T>`/`&[T]`/owned shorthands and the associated-type rules), shared with `#[cgp_getter]`: [crates/macros/cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs), [crates/macros/cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs), and [crates/macros/cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/). +- Internal walkthrough (the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/cgp_auto_getter.md](../../implementation/entrypoints/cgp_auto_getter.md). diff --git a/docs/reference/macros/cgp_component.md b/docs/reference/macros/cgp_component.md index 94474504..57a86c8a 100644 --- a/docs/reference/macros/cgp_component.md +++ b/docs/reference/macros/cgp_component.md @@ -183,6 +183,7 @@ The call `rect.area()` resolves through the consumer blanket impl to `Rectangle: ## Source -The macro entry point is `cgp_component` in [crates/macros/cgp-macro-lib/src/cgp_component.rs](../../../crates/macros/cgp-macro-lib/src/cgp_component.rs), which drives the `preprocess → eval → to_items` pipeline. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/): argument parsing in `args/`, the provider trait and blanket impls in `preprocessed/`, and the standard provider impls (`UseContext`, `RedirectLookup`, `UseDelegate`) in `evaluated/`. The default identifiers `__Context__` and `{Provider}Component` are set in `args/component_args.rs`. - -For the full internal walkthrough — the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/cgp_component.md](../../implementation/entrypoints/cgp_component.md). +- Entry point: `cgp_component` in [crates/macros/cgp-macro-lib/src/cgp_component.rs](../../../crates/macros/cgp-macro-lib/src/cgp_component.rs), which drives the `preprocess → eval → to_items` pipeline. +- Logic: [crates/macros/cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/) — argument parsing in `args/`, the provider trait and blanket impls in `preprocessed/`, the standard provider impls (`UseContext`, `RedirectLookup`, `UseDelegate`) in `evaluated/`. +- Default identifiers `__Context__` and `{Provider}Component`: set in `args/component_args.rs`. +- Internal walkthrough (pipeline stages, synthesizing functions, corner cases, and the index of tests and snapshots): [implementation/entrypoints/cgp_component.md](../../implementation/entrypoints/cgp_component.md). diff --git a/docs/reference/macros/cgp_computer.md b/docs/reference/macros/cgp_computer.md index dbc3cade..53e7cf61 100644 --- a/docs/reference/macros/cgp_computer.md +++ b/docs/reference/macros/cgp_computer.md @@ -145,6 +145,7 @@ Because the function returns a plain `u64`, the `try_compute` and `handle` forms ## Source -The macro entrypoint is [crates/macros/cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs), forwarding to the implementation in [crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs); the `Result`-versus-value detection is the `MaybeResultType` parser in [crates/macros/cgp-extra-macro-lib/src/parse/maybe_result.rs](../../../crates/macros/cgp-extra-macro-lib/src/parse/maybe_result.rs). The base `Computer`/`AsyncComputer` traits are defined in [crates/extra/cgp-handler/src/components/](../../../crates/extra/cgp-handler/src/components/), and the promotion bundles in [crates/extra/cgp-handler/src/providers/promote_all.rs](../../../crates/extra/cgp-handler/src/providers/promote_all.rs). - -For the internal walkthrough — the sync/async and value/`Result` branching, the generated items, and the index of behavioral tests — see the implementation document [implementation/entrypoints/cgp_computer.md](../../implementation/entrypoints/cgp_computer.md). +- Entrypoint: [crates/macros/cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs), forwarding to the implementation in [crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_computer.rs). +- `Result`-versus-value detection: the `MaybeResultType` parser in [crates/macros/cgp-extra-macro-lib/src/parse/maybe_result.rs](../../../crates/macros/cgp-extra-macro-lib/src/parse/maybe_result.rs). +- Base `Computer`/`AsyncComputer` traits: [crates/extra/cgp-handler/src/components/](../../../crates/extra/cgp-handler/src/components/); the promotion bundles in [crates/extra/cgp-handler/src/providers/promote_all.rs](../../../crates/extra/cgp-handler/src/providers/promote_all.rs). +- Internal walkthrough (the sync/async and value/`Result` branching, the generated items, and the index of behavioral tests): [implementation/entrypoints/cgp_computer.md](../../implementation/entrypoints/cgp_computer.md). diff --git a/docs/reference/macros/cgp_fn.md b/docs/reference/macros/cgp_fn.md index a2d12c71..5f25a863 100644 --- a/docs/reference/macros/cgp_fn.md +++ b/docs/reference/macros/cgp_fn.md @@ -170,6 +170,7 @@ Because `Rectangle` derives `HasField` and carries `width`, `height`, and `scale ## Source -The macro entry point is `cgp_fn` in [crates/macros/cgp-macro-lib/src/cgp_fn.rs](../../../crates/macros/cgp-macro-lib/src/cgp_fn.rs), which parses the optional trait-name identifier and the function, then runs `item.preprocess()?.to_items()?`. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_fn/](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/): `item.rs` performs the PascalCase default-name derivation (`to_camel_case_str`), implicit-argument extraction, and attribute parsing; `preprocessed.rs` builds the trait in `to_item_trait` and the blanket impl in `to_item_impl`, including the generics/`where`-clause split and the insertion of the leading `__Context__` parameter. Implicit-argument handling is in [crates/macros/cgp-macro-core/src/types/implicits/](../../../crates/macros/cgp-macro-core/src/types/implicits/), and the companion-attribute parsing is in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs). - -For the full internal walkthrough — the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/cgp_fn.md](../../implementation/entrypoints/cgp_fn.md). +- Entry point: `cgp_fn` in [crates/macros/cgp-macro-lib/src/cgp_fn.rs](../../../crates/macros/cgp-macro-lib/src/cgp_fn.rs), which parses the optional trait-name identifier and the function, then runs `item.preprocess()?.to_items()?`. +- Logic: [crates/macros/cgp-macro-core/src/types/cgp_fn/](../../../crates/macros/cgp-macro-core/src/types/cgp_fn/) — `item.rs` performs the PascalCase default-name derivation (`to_camel_case_str`), implicit-argument extraction, and attribute parsing; `preprocessed.rs` builds the trait in `to_item_trait` and the blanket impl in `to_item_impl`, including the generics/`where`-clause split and the insertion of the leading `__Context__` parameter. +- Implicit-argument handling: [crates/macros/cgp-macro-core/src/types/implicits/](../../../crates/macros/cgp-macro-core/src/types/implicits/); the companion-attribute parsing in [crates/macros/cgp-macro-core/src/types/attributes/function.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/function.rs). +- Internal walkthrough (the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/cgp_fn.md](../../implementation/entrypoints/cgp_fn.md). diff --git a/docs/reference/macros/cgp_getter.md b/docs/reference/macros/cgp_getter.md index 30b49112..f7fceea5 100644 --- a/docs/reference/macros/cgp_getter.md +++ b/docs/reference/macros/cgp_getter.md @@ -150,6 +150,7 @@ The direct implementation is the most transparent option and shows that a `#[cgp ## Source -The macro entry point is `cgp_getter` in [crates/macros/cgp-macro-lib/src/cgp_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_getter.rs), which derives the default provider name (strip `Has`, append `Getter`), runs the `#[cgp_component]` `preprocess → eval` pipeline, then converts the result into `ItemCgpGetter` and emits the extra provider impls. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/): `item.rs` assembles the items, `use_field.rs` builds the `UseField` impl with the free `__Tag__` parameter, `to_use_fields_impl.rs` builds the `UseFields` impl keyed by method name, and `with_provider.rs` builds the `WithProvider` impl. Getter-method parsing and the return-type shorthands are shared with `#[cgp_auto_getter]` in [crates/macros/cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs) and [crates/macros/cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/). - -For the full internal walkthrough — the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/cgp_getter.md](../../implementation/entrypoints/cgp_getter.md). +- Entry point: `cgp_getter` in [crates/macros/cgp-macro-lib/src/cgp_getter.rs](../../../crates/macros/cgp-macro-lib/src/cgp_getter.rs), which derives the default provider name (strip `Has`, append `Getter`), runs the `#[cgp_component]` `preprocess → eval` pipeline, then converts the result into `ItemCgpGetter` and emits the extra provider impls. +- Logic: [crates/macros/cgp-macro-core/src/types/cgp_getter/](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/) — `item.rs` assembles the items, `use_field.rs` builds the `UseField` impl with the free `__Tag__` parameter, `to_use_fields_impl.rs` builds the `UseFields` impl keyed by method name, and `with_provider.rs` builds the `WithProvider` impl. +- Getter-method parsing and the return-type shorthands, shared with `#[cgp_auto_getter]`: [crates/macros/cgp-macro-core/src/functions/getter/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/getter/parse.rs) and [crates/macros/cgp-macro-core/src/types/getter/](../../../crates/macros/cgp-macro-core/src/types/getter/). +- Internal walkthrough (the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/cgp_getter.md](../../implementation/entrypoints/cgp_getter.md). diff --git a/docs/reference/macros/cgp_impl.md b/docs/reference/macros/cgp_impl.md index 9b0dd3a0..20efc854 100644 --- a/docs/reference/macros/cgp_impl.md +++ b/docs/reference/macros/cgp_impl.md @@ -177,6 +177,7 @@ The call `rect.area()` resolves through the consumer blanket impl to `Rectangle` ## Source -The macro entry point is `cgp_impl` in [crates/macros/cgp-macro-lib/src/cgp_impl.rs](../../../crates/macros/cgp-macro-lib/src/cgp_impl.rs), which lowers the impl and emits the lowered provider impl alongside any default impls. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_impl/](../../../crates/macros/cgp-macro-core/src/types/cgp_impl/): attribute argument parsing (the `new` keyword, provider type, optional component type) in `args.rs`; the lowering that extracts implicit arguments, applies companion attributes, and inserts the `__Context__` parameter when `for` is omitted in `item.rs`; the rewrite of `self`/`Self` and the handoff to `#[cgp_provider]` in `lowered.rs`; and the bare-impl passthrough for `#[cgp_impl(Self)]` in `provider_or_bare.rs`. The `self`/`Self` rewriting is performed by the `ReplaceSelfType`, `ReplaceSelfReceiver`, and `ReplaceSelfValue` visitors in [crates/macros/cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). - -For the internal walkthrough — pipeline, generated items, corner cases, and the index of tests and snapshots — see [implementation/entrypoints/cgp_impl.md](../../implementation/entrypoints/cgp_impl.md). +- Entry point: `cgp_impl` in [crates/macros/cgp-macro-lib/src/cgp_impl.rs](../../../crates/macros/cgp-macro-lib/src/cgp_impl.rs), which lowers the impl and emits the lowered provider impl alongside any default impls. +- Logic: [crates/macros/cgp-macro-core/src/types/cgp_impl/](../../../crates/macros/cgp-macro-core/src/types/cgp_impl/) — attribute argument parsing (the `new` keyword, provider type, optional component type) in `args.rs`; the lowering that extracts implicit arguments, applies companion attributes, and inserts the `__Context__` parameter when `for` is omitted in `item.rs`; the rewrite of `self`/`Self` and the handoff to `#[cgp_provider]` in `lowered.rs`; and the bare-impl passthrough for `#[cgp_impl(Self)]` in `provider_or_bare.rs`. +- `self`/`Self` rewriting: the `ReplaceSelfType`, `ReplaceSelfReceiver`, and `ReplaceSelfValue` visitors in [crates/macros/cgp-macro-core/src/visitors/](../../../crates/macros/cgp-macro-core/src/visitors/). +- Internal walkthrough (pipeline, generated items, corner cases, and the index of tests and snapshots): [implementation/entrypoints/cgp_impl.md](../../implementation/entrypoints/cgp_impl.md). diff --git a/docs/reference/macros/cgp_namespace.md b/docs/reference/macros/cgp_namespace.md index 65a747a6..ed2d5bd4 100644 --- a/docs/reference/macros/cgp_namespace.md +++ b/docs/reference/macros/cgp_namespace.md @@ -210,6 +210,8 @@ Inheritance composes the same way at the namespace level: `ExtendedNamespace: De ## Source -The macro entry point is `cgp_namespace` in [crates/macros/cgp-macro-lib/src/cgp_namespace.rs](../../../crates/macros/cgp-macro-lib/src/cgp_namespace.rs), which parses a `NamespaceTable` and calls `.eval()`. The logic lives in [crates/macros/cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/): `table.rs` parses the header (`new`, namespace name, optional `: parent`) and builds the trait, struct, per-entry impls, and the parent-inheritance impl; `inherit.rs` builds the path-rewriting inheritance entry; `eval.rs` holds the emitted `EvaluatedNamespaceTable`. The `#[prefix(...)]` attribute that attaches a component to a namespace is parsed in [crates/macros/cgp-macro-core/src/types/attributes/prefix.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/prefix.rs), and the matching `RedirectLookup` provider impl is emitted by [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs). The runtime traits `DefaultNamespace`/`DefaultImpls1`/`DefaultImpls2` are in [crates/core/cgp-component/src/namespaces.rs](../../../crates/core/cgp-component/src/namespaces.rs) and `RedirectLookup` in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs). - -For the full internal walkthrough — the pipeline, the item each entry form generates, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/cgp_namespace.md](../../implementation/entrypoints/cgp_namespace.md). +- Entry point: `cgp_namespace` in [crates/macros/cgp-macro-lib/src/cgp_namespace.rs](../../../crates/macros/cgp-macro-lib/src/cgp_namespace.rs), which parses a `NamespaceTable` and calls `.eval()`. +- Logic: [crates/macros/cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/) — `table.rs` parses the header (`new`, namespace name, optional `: parent`) and builds the trait, struct, per-entry impls, and the parent-inheritance impl; `inherit.rs` builds the path-rewriting inheritance entry; `eval.rs` holds the emitted `EvaluatedNamespaceTable`. +- `#[prefix(...)]` attribute (attaches a component to a namespace): parsed in [crates/macros/cgp-macro-core/src/types/attributes/prefix.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/prefix.rs); the matching `RedirectLookup` provider impl is emitted by [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs). +- Runtime traits: `DefaultNamespace`/`DefaultImpls1`/`DefaultImpls2` in [crates/core/cgp-component/src/namespaces.rs](../../../crates/core/cgp-component/src/namespaces.rs) and `RedirectLookup` in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs). +- Internal walkthrough (the pipeline, the item each entry form generates, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/cgp_namespace.md](../../implementation/entrypoints/cgp_namespace.md). diff --git a/docs/reference/macros/cgp_new_provider.md b/docs/reference/macros/cgp_new_provider.md index 6dfa96e9..6e310d72 100644 --- a/docs/reference/macros/cgp_new_provider.md +++ b/docs/reference/macros/cgp_new_provider.md @@ -115,6 +115,6 @@ This is equivalent to writing `pub struct RectangleArea;` followed by the same i ## Source -The macro entry point is `cgp_new_provider` in [crates/macros/cgp-macro-lib/src/cgp_new_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_new_provider.rs); it parses the same `ProviderArgs`, sets `new` to enabled, and then runs the identical lowering as [`#[cgp_provider]`](cgp_provider.md). All of the generation logic — including the struct declaration emitted when `new` is set — lives in [crates/macros/cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/); the struct shape is built in `item.rs` (`to_provider_struct`). - -For the internal walkthrough — pipeline, generated items, corner cases, and the index of tests and snapshots — see [implementation/entrypoints/cgp_new_provider.md](../../implementation/entrypoints/cgp_new_provider.md). +- Entry point: `cgp_new_provider` in [crates/macros/cgp-macro-lib/src/cgp_new_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_new_provider.rs); it parses the same `ProviderArgs`, sets `new` to enabled, and then runs the identical lowering as [`#[cgp_provider]`](cgp_provider.md). +- Generation logic (including the struct declaration emitted when `new` is set): [crates/macros/cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/); the struct shape is built in `item.rs` (`to_provider_struct`). +- Internal walkthrough (pipeline, generated items, corner cases, and the index of tests and snapshots): [implementation/entrypoints/cgp_new_provider.md](../../implementation/entrypoints/cgp_new_provider.md). diff --git a/docs/reference/macros/cgp_producer.md b/docs/reference/macros/cgp_producer.md index 90e6af30..5d5a7213 100644 --- a/docs/reference/macros/cgp_producer.md +++ b/docs/reference/macros/cgp_producer.md @@ -118,6 +118,6 @@ The computer and handler forms accept an input argument and ignore it, since the ## Source -The macro entrypoint is [crates/macros/cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs), forwarding to the implementation in [crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs). The `Producer` trait is defined in [crates/extra/cgp-handler/src/components/produce.rs](../../../crates/extra/cgp-handler/src/components/produce.rs), and the `PromoteProducer` bundle in [crates/extra/cgp-handler/src/providers/promote_all.rs](../../../crates/extra/cgp-handler/src/providers/promote_all.rs). - -For the internal walkthrough — the signature validation, the generated items, and the index of behavioral tests — see the implementation document [implementation/entrypoints/cgp_producer.md](../../implementation/entrypoints/cgp_producer.md). +- Entrypoint: [crates/macros/cgp-extra-macro/src/lib.rs](../../../crates/macros/cgp-extra-macro/src/lib.rs), forwarding to the implementation in [crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs](../../../crates/macros/cgp-extra-macro-lib/src/entrypoints/cgp_producer.rs). +- `Producer` trait: [crates/extra/cgp-handler/src/components/produce.rs](../../../crates/extra/cgp-handler/src/components/produce.rs); the `PromoteProducer` bundle in [crates/extra/cgp-handler/src/providers/promote_all.rs](../../../crates/extra/cgp-handler/src/providers/promote_all.rs). +- Internal walkthrough (the signature validation, the generated items, and the index of behavioral tests): [implementation/entrypoints/cgp_producer.md](../../implementation/entrypoints/cgp_producer.md). diff --git a/docs/reference/macros/cgp_provider.md b/docs/reference/macros/cgp_provider.md index e6430666..8d34c75e 100644 --- a/docs/reference/macros/cgp_provider.md +++ b/docs/reference/macros/cgp_provider.md @@ -138,6 +138,7 @@ In most code, the same provider would be written more concisely with [`#[cgp_imp ## Source -The macro entry point is `cgp_provider` in [crates/macros/cgp-macro-lib/src/cgp_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_provider.rs), which parses the optional component argument, lowers the impl, and emits the result. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/): attribute argument parsing (the optional `new` keyword and component type) in `args.rs`; the lowering that derives the component default, the provider struct, and the `IsProviderFor` impl in `item.rs`; the emitted-token assembly in `lower.rs`; and the splitting of provider-trait arguments into context and `Params` tuple in `provider_impl_args.rs`. The `IsProviderFor` derivation itself is in [crates/macros/cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs). - -For the internal walkthrough — pipeline, generated items, corner cases, and the index of tests and snapshots — see [implementation/entrypoints/cgp_provider.md](../../implementation/entrypoints/cgp_provider.md). +- Entry point: `cgp_provider` in [crates/macros/cgp-macro-lib/src/cgp_provider.rs](../../../crates/macros/cgp-macro-lib/src/cgp_provider.rs), which parses the optional component argument, lowers the impl, and emits the result. +- Logic: [crates/macros/cgp-macro-core/src/types/cgp_provider/](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/) — attribute argument parsing (the optional `new` keyword and component type) in `args.rs`; the lowering that derives the component default, the provider struct, and the `IsProviderFor` impl in `item.rs`; the emitted-token assembly in `lower.rs`; and the splitting of provider-trait arguments into context and `Params` tuple in `provider_impl_args.rs`. +- `IsProviderFor` derivation: [crates/macros/cgp-macro-core/src/types/provider_impl.rs](../../../crates/macros/cgp-macro-core/src/types/provider_impl.rs). +- Internal walkthrough (pipeline, generated items, corner cases, and the index of tests and snapshots): [implementation/entrypoints/cgp_provider.md](../../implementation/entrypoints/cgp_provider.md). diff --git a/docs/reference/macros/cgp_type.md b/docs/reference/macros/cgp_type.md index b023e124..a5ff6515 100644 --- a/docs/reference/macros/cgp_type.md +++ b/docs/reference/macros/cgp_type.md @@ -128,6 +128,7 @@ This direct form is only marginally longer than the wired form and is the most a ## Source -The macro entry point is `cgp_type` in [crates/macros/cgp-macro-lib/src/cgp_type.rs](../../../crates/macros/cgp-macro-lib/src/cgp_type.rs), which extracts the single associated type, derives the default `{Type}TypeProvider` provider name from the associated type's identifier, runs the `#[cgp_component]` `preprocess → eval` pipeline, and converts the result into `ItemCgpType`. The logic lives in [crates/macros/cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs), which validates the trait shape (`extract_item_type_from_trait`) and builds the `UseType` and `WithProvider` provider impls. The runtime `HasType`, `TypeProvider`, and `UseType` definitions are in [crates/core/cgp-type/src/](../../../crates/core/cgp-type/src/) (`traits/has_type.rs` and `impls/use_type.rs`). - -For the full internal walkthrough — the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/cgp_type.md](../../implementation/entrypoints/cgp_type.md). +- Entry point: `cgp_type` in [crates/macros/cgp-macro-lib/src/cgp_type.rs](../../../crates/macros/cgp-macro-lib/src/cgp_type.rs), which extracts the single associated type, derives the default `{Type}TypeProvider` provider name from the associated type's identifier, runs the `#[cgp_component]` `preprocess → eval` pipeline, and converts the result into `ItemCgpType`. +- Logic: [crates/macros/cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs), which validates the trait shape (`extract_item_type_from_trait`) and builds the `UseType` and `WithProvider` provider impls. +- Runtime `HasType`, `TypeProvider`, and `UseType` definitions: [crates/core/cgp-type/src/](../../../crates/core/cgp-type/src/) (`traits/has_type.rs` and `impls/use_type.rs`). +- Internal walkthrough (the pipeline stages, the function that synthesizes each generated item, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/cgp_type.md](../../implementation/entrypoints/cgp_type.md). diff --git a/docs/reference/macros/check_components.md b/docs/reference/macros/check_components.md index 4f270114..e8a785f5 100644 --- a/docs/reference/macros/check_components.md +++ b/docs/reference/macros/check_components.md @@ -213,6 +213,6 @@ This verifies `MyApp: CanCalculateAreaOfShape` and `MyApp: CanCalcula ## Source -The macro entry point is `check_components` in [crates/macros/cgp-macro-lib/src/check_components.rs](../../../crates/macros/cgp-macro-lib/src/check_components.rs), which parses `CheckComponentsTables` and emits their items. The logic lives in [crates/macros/cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/): table parsing, the `#[check_trait]`/`#[check_providers]` attributes, the `__Check{Context}` name derivation, and the choice between `CanUseComponent` and `IsProviderFor` supertraits are all in `table.rs`; key and value parsing (including array syntax) in `key.rs` and `value.rs`; and the cartesian-product expansion of entries in `entry.rs`. - -For the full internal walkthrough — the pipeline, the AST types behind each grammar form, the corner-case handling, and the index of expansion snapshots — see the implementation document [implementation/entrypoints/check_components.md](../../implementation/entrypoints/check_components.md). +- Entry point: `check_components` in [crates/macros/cgp-macro-lib/src/check_components.rs](../../../crates/macros/cgp-macro-lib/src/check_components.rs), which parses `CheckComponentsTables` and emits their items. +- Logic: [crates/macros/cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/) — table parsing, the `#[check_trait]`/`#[check_providers]` attributes, the `__Check{Context}` name derivation, and the choice between `CanUseComponent` and `IsProviderFor` supertraits are all in `table.rs`; key and value parsing (including array syntax) in `key.rs` and `value.rs`; and the cartesian-product expansion of entries in `entry.rs`. +- Internal walkthrough (the pipeline, the AST types behind each grammar form, the corner-case handling, and the index of expansion snapshots): [implementation/entrypoints/check_components.md](../../implementation/entrypoints/check_components.md). diff --git a/docs/reference/macros/delegate_and_check_components.md b/docs/reference/macros/delegate_and_check_components.md index 09b22c9d..176b035e 100644 --- a/docs/reference/macros/delegate_and_check_components.md +++ b/docs/reference/macros/delegate_and_check_components.md @@ -182,6 +182,7 @@ delegate_and_check_components! { ## Source -The macro entry point is `delegate_and_check_components` in [crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs), which parses the table, evaluates the delegation half via the shared `DelegateTable`, derives a `CheckComponentsTable` from the keys, and emits both. The logic lives in [crates/macros/cgp-macro-core/src/types/delegate_and_check_components/](../../../crates/macros/cgp-macro-core/src/types/delegate_and_check_components/): the `__CanUse{Context}` default name and `#[check_trait]` handling in `item.rs`, the `#[check_params]`/`#[skip_check]` parsing and their mutual exclusion in `check_params.rs`, the per-key conversion to check entries in `key_with_check_params.rs`, and the walk over delegation entries in `to_keys_with_check_params.rs`. It reuses the `DelegateTable` from [delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/) and the `CheckComponentsTable` from [check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/). - -For the full internal walkthrough — the two reused pipelines, the key-to-check derivation, the corner-case handling, and the index of expansion snapshots — see the implementation document [implementation/entrypoints/delegate_and_check_components.md](../../implementation/entrypoints/delegate_and_check_components.md). +- Entry point: `delegate_and_check_components` in [crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs), which parses the table, evaluates the delegation half via the shared `DelegateTable`, derives a `CheckComponentsTable` from the keys, and emits both. +- Logic: [crates/macros/cgp-macro-core/src/types/delegate_and_check_components/](../../../crates/macros/cgp-macro-core/src/types/delegate_and_check_components/) — the `__CanUse{Context}` default name and `#[check_trait]` handling in `item.rs`, the `#[check_params]`/`#[skip_check]` parsing and their mutual exclusion in `check_params.rs`, the per-key conversion to check entries in `key_with_check_params.rs`, and the walk over delegation entries in `to_keys_with_check_params.rs`. +- Reused tables: the `DelegateTable` from [delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/) and the `CheckComponentsTable` from [check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/). +- Internal walkthrough (the two reused pipelines, the key-to-check derivation, the corner-case handling, and the index of expansion snapshots): [implementation/entrypoints/delegate_and_check_components.md](../../implementation/entrypoints/delegate_and_check_components.md). diff --git a/docs/reference/macros/delegate_components.md b/docs/reference/macros/delegate_components.md index 30a6d331..883ddd6a 100644 --- a/docs/reference/macros/delegate_components.md +++ b/docs/reference/macros/delegate_components.md @@ -253,6 +253,7 @@ delegate_components! { ## Source -The macro entry point is `delegate_components` in [crates/macros/cgp-macro-lib/src/delegate_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_components.rs), which parses a `DelegateTable`, validates that no attributes are present, evaluates it, and emits the tokens. The logic lives in [crates/macros/cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/): the top-level table and the `new` keyword in `table/main.rs`, key parsing (single, array/`Multi`, path) in `key/`, value parsing including the nested-table form in `value/`, the statement forms (`open`, `namespace`, `for`) in `statement/` — with the `open` statement and its `RedirectLookup` expansion in `statement/open.rs` — and the `DelegateComponent`/`IsProviderFor` impl construction in `mapping/eval.rs`. Attribute rejection is in `validate_attributes.rs`. - -For the full internal walkthrough — the pipeline, the AST types behind each grammar form, the corner-case handling, and the index of tests and expansion snapshots — see the implementation document [implementation/entrypoints/delegate_components.md](../../implementation/entrypoints/delegate_components.md). +- Entry point: `delegate_components` in [crates/macros/cgp-macro-lib/src/delegate_components.rs](../../../crates/macros/cgp-macro-lib/src/delegate_components.rs), which parses a `DelegateTable`, validates that no attributes are present, evaluates it, and emits the tokens. +- Logic: [crates/macros/cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/) — the top-level table and the `new` keyword in `table/main.rs`, key parsing (single, array/`Multi`, path) in `key/`, value parsing including the nested-table form in `value/`, the statement forms (`open`, `namespace`, `for`) in `statement/` — with the `open` statement and its `RedirectLookup` expansion in `statement/open.rs` — and the `DelegateComponent`/`IsProviderFor` impl construction in `mapping/eval.rs`. +- Attribute rejection: `validate_attributes.rs`. +- Internal walkthrough (the pipeline, the AST types behind each grammar form, the corner-case handling, and the index of tests and expansion snapshots): [implementation/entrypoints/delegate_components.md](../../implementation/entrypoints/delegate_components.md). diff --git a/docs/reference/macros/path.md b/docs/reference/macros/path.md index e07de081..04f34458 100644 --- a/docs/reference/macros/path.md +++ b/docs/reference/macros/path.md @@ -93,6 +93,7 @@ Either way the path is the same `PathCons` list; the macro and the namespace sim ## Source -The macro entry point is `Path` in [crates/macros/cgp-macro-lib/src/path.rs](../../../crates/macros/cgp-macro-lib/src/path.rs), which parses the body into a `UniPath` and emits its tokens. The parsing and codegen live in [crates/macros/cgp-macro-core/src/types/path/](../../../crates/macros/cgp-macro-core/src/types/path/): `unipath.rs` requires the leading `@`, parses the dot-separated segments, and right-folds them with `PathCons` onto `Nil`; `path_element.rs` decides per segment whether a lowercase, non-primitive identifier becomes a `Symbol` or the segment stays a named type. The runtime spine `PathCons` is defined in [crates/core/cgp-base-types/src/types/path.rs](../../../crates/core/cgp-base-types/src/types/path.rs), and the `RedirectLookup` provider that walks a path is in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs). - -For the full internal walkthrough — the parse-and-emit pipeline, the per-segment symbol/type classification, the `PathCons` fold, and the index of tests — see the implementation document [implementation/entrypoints/path.md](../../implementation/entrypoints/path.md). +- Entry point: `Path` in [crates/macros/cgp-macro-lib/src/path.rs](../../../crates/macros/cgp-macro-lib/src/path.rs), which parses the body into a `UniPath` and emits its tokens. +- Parsing and codegen: [crates/macros/cgp-macro-core/src/types/path/](../../../crates/macros/cgp-macro-core/src/types/path/) — `unipath.rs` requires the leading `@`, parses the dot-separated segments, and right-folds them with `PathCons` onto `Nil`; `path_element.rs` decides per segment whether a lowercase, non-primitive identifier becomes a `Symbol` or the segment stays a named type. +- Runtime spine `PathCons`: [crates/core/cgp-base-types/src/types/path.rs](../../../crates/core/cgp-base-types/src/types/path.rs); the `RedirectLookup` provider that walks a path is in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs). +- Internal walkthrough (the parse-and-emit pipeline, the per-segment symbol/type classification, the `PathCons` fold, and the index of tests): [implementation/entrypoints/path.md](../../implementation/entrypoints/path.md). diff --git a/docs/reference/macros/product.md b/docs/reference/macros/product.md index 2bb5d847..945535c7 100644 --- a/docs/reference/macros/product.md +++ b/docs/reference/macros/product.md @@ -101,6 +101,8 @@ let row: Row = product![1, "hi".to_string(), true]; ## Source -The macro entry points are `Product` and `product` in [crates/macros/cgp-macro-lib/src/product.rs](../../../crates/macros/cgp-macro-lib/src/product.rs). The type form is the `ProductType` construct in [crates/macros/cgp-macro-core/src/types/product/product_type.rs](../../../crates/macros/cgp-macro-core/src/types/product/product_type.rs), whose `eval` right-folds the elements with `Cons` onto `Nil`; the value form is `ProductExpr` in [crates/macros/cgp-macro-core/src/types/product/product_expr.rs](../../../crates/macros/cgp-macro-core/src/types/product/product_expr.rs), which does the same fold using the `Cons(..)` constructor. The runtime types are defined in [crates/core/cgp-base-types/src/types/cons.rs](../../../crates/core/cgp-base-types/src/types/cons.rs) (`Cons`) and [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs) (`Nil`). - -For the full internal walkthrough — the parse-and-`eval` pipeline shared by both forms, the right-fold onto `Nil`, and the index of tests — see the implementation document [implementation/entrypoints/product.md](../../implementation/entrypoints/product.md). +- Entry points: `Product` and `product` in [crates/macros/cgp-macro-lib/src/product.rs](../../../crates/macros/cgp-macro-lib/src/product.rs). +- Type form: the `ProductType` construct in [crates/macros/cgp-macro-core/src/types/product/product_type.rs](../../../crates/macros/cgp-macro-core/src/types/product/product_type.rs), whose `eval` right-folds the elements with `Cons` onto `Nil`. +- Value form: `ProductExpr` in [crates/macros/cgp-macro-core/src/types/product/product_expr.rs](../../../crates/macros/cgp-macro-core/src/types/product/product_expr.rs), which does the same fold using the `Cons(..)` constructor. +- Runtime types: [crates/core/cgp-base-types/src/types/cons.rs](../../../crates/core/cgp-base-types/src/types/cons.rs) (`Cons`) and [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs) (`Nil`). +- Internal walkthrough (the parse-and-`eval` pipeline shared by both forms, the right-fold onto `Nil`, and the index of tests): [implementation/entrypoints/product.md](../../implementation/entrypoints/product.md). diff --git a/docs/reference/macros/sum.md b/docs/reference/macros/sum.md index a814e871..ca065179 100644 --- a/docs/reference/macros/sum.md +++ b/docs/reference/macros/sum.md @@ -88,6 +88,7 @@ type Token = Sum![u32, String, bool]; ## Source -The macro entry point is `Sum` in [crates/macros/cgp-macro-lib/src/sum.rs](../../../crates/macros/cgp-macro-lib/src/sum.rs), forwarding to the `SumType` construct in [crates/macros/cgp-macro-core/src/types/sum.rs](../../../crates/macros/cgp-macro-core/src/types/sum.rs), whose `eval` right-folds the element types with `Either` onto `Void`. The runtime types `Either` and the uninhabited `Void` are both defined in [crates/core/cgp-field/src/types/sum.rs](../../../crates/core/cgp-field/src/types/sum.rs). The enum `HasFields` derive that emits a `Sum!` of `Field` branches lives in [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs). - -For the full internal walkthrough — the parse-and-`eval` pipeline, the right-fold onto `Void`, and the index of tests — see the implementation document [implementation/entrypoints/sum.md](../../implementation/entrypoints/sum.md). +- Entry point: `Sum` in [crates/macros/cgp-macro-lib/src/sum.rs](../../../crates/macros/cgp-macro-lib/src/sum.rs), forwarding to the `SumType` construct in [crates/macros/cgp-macro-core/src/types/sum.rs](../../../crates/macros/cgp-macro-core/src/types/sum.rs), whose `eval` right-folds the element types with `Either` onto `Void`. +- Runtime types: `Either` and the uninhabited `Void`, both defined in [crates/core/cgp-field/src/types/sum.rs](../../../crates/core/cgp-field/src/types/sum.rs). +- Enum `HasFields` derive that emits a `Sum!` of `Field` branches: [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs). +- Internal walkthrough (the parse-and-`eval` pipeline, the right-fold onto `Void`, and the index of tests): [implementation/entrypoints/sum.md](../../implementation/entrypoints/sum.md). diff --git a/docs/reference/macros/symbol.md b/docs/reference/macros/symbol.md index d7ebc087..0fcccf88 100644 --- a/docs/reference/macros/symbol.md +++ b/docs/reference/macros/symbol.md @@ -85,6 +85,6 @@ When a struct derives [`HasField`](../derives/derive_has_field.md), each named f ## Source -The macro entry point is `Symbol` in [crates/macros/cgp-macro-lib/src/symbol.rs](../../../crates/macros/cgp-macro-lib/src/symbol.rs), which forwards to the `Symbol` construct in [crates/macros/cgp-macro-core/src/types/field/symbol.rs](../../../crates/macros/cgp-macro-core/src/types/field/symbol.rs) — its `ToTokens` impl performs the right-fold over the characters, computes `LEN` from `str::len()`, and wraps the result in `Symbol`. The runtime types are defined in [crates/core/cgp-base-types/src/types/symbol.rs](../../../crates/core/cgp-base-types/src/types/symbol.rs) (`Symbol`) and [crates/core/cgp-base-types/src/types/chars.rs](../../../crates/core/cgp-base-types/src/types/chars.rs) (`Chars`), with `Nil` in [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs). - -For the full internal walkthrough — the parse-and-emit pipeline, the character fold and the `LEN` const workaround, and the index of tests — see the implementation document [implementation/entrypoints/symbol.md](../../implementation/entrypoints/symbol.md). +- Entry point: `Symbol` in [crates/macros/cgp-macro-lib/src/symbol.rs](../../../crates/macros/cgp-macro-lib/src/symbol.rs), which forwards to the `Symbol` construct in [crates/macros/cgp-macro-core/src/types/field/symbol.rs](../../../crates/macros/cgp-macro-core/src/types/field/symbol.rs) — its `ToTokens` impl performs the right-fold over the characters, computes `LEN` from `str::len()`, and wraps the result in `Symbol`. +- Runtime types: [crates/core/cgp-base-types/src/types/symbol.rs](../../../crates/core/cgp-base-types/src/types/symbol.rs) (`Symbol`) and [crates/core/cgp-base-types/src/types/chars.rs](../../../crates/core/cgp-base-types/src/types/chars.rs) (`Chars`), with `Nil` in [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs). +- Internal walkthrough (the parse-and-emit pipeline, the character fold and the `LEN` const workaround, and the index of tests): [implementation/entrypoints/symbol.md](../../implementation/entrypoints/symbol.md). diff --git a/docs/reference/providers/chain_getters.md b/docs/reference/providers/chain_getters.md index 52052825..ffc3a5c3 100644 --- a/docs/reference/providers/chain_getters.md +++ b/docs/reference/providers/chain_getters.md @@ -98,4 +98,6 @@ delegate_components! { ## Source -The `ChainGetters` struct and its two `FieldGetter` impls (the `Cons` recursion step and the `Nil` base case) are in [crates/core/cgp-field/src/impls/chain.rs](../../../crates/core/cgp-field/src/impls/chain.rs). The `FieldGetter` and `FieldMapper` traits it builds on are in [crates/core/cgp-field/src/traits/has_field.rs](../../../crates/core/cgp-field/src/traits/has_field.rs) and [crates/core/cgp-field/src/traits/map_field.rs](../../../crates/core/cgp-field/src/traits/map_field.rs), and the `Cons`/`Nil` spine it recurses over is defined in [crates/core/cgp-base-types/src/types/](../../../crates/core/cgp-base-types/src/types/) (`cons.rs` and `nil.rs`). +- The `ChainGetters` struct and its two `FieldGetter` impls (the `Cons` recursion step and the `Nil` base case) are in [crates/core/cgp-field/src/impls/chain.rs](../../../crates/core/cgp-field/src/impls/chain.rs). +- The `FieldGetter` and `FieldMapper` traits it builds on are in [crates/core/cgp-field/src/traits/has_field.rs](../../../crates/core/cgp-field/src/traits/has_field.rs) and [crates/core/cgp-field/src/traits/map_field.rs](../../../crates/core/cgp-field/src/traits/map_field.rs). +- The `Cons`/`Nil` spine it recurses over is defined in [crates/core/cgp-base-types/src/types/](../../../crates/core/cgp-base-types/src/types/) (`cons.rs` and `nil.rs`). diff --git a/docs/reference/providers/dispatch_combinators.md b/docs/reference/providers/dispatch_combinators.md index dd165ecc..ddb834ec 100644 --- a/docs/reference/providers/dispatch_combinators.md +++ b/docs/reference/providers/dispatch_combinators.md @@ -266,4 +266,5 @@ The matchers stand on the enum-deconstruction traits in [`extract_field`](../tra ## Source -The provider structs live under [crates/extra/cgp-dispatch/src/providers/](../../../crates/extra/cgp-dispatch/src/providers/): the matchers in `with_handlers/` (`match_with_handlers.rs`, `match_with_handlers_ref.rs`, `match_with_handlers_mut.rs`, `match_first_with_handlers*.rs`, `build_with_handlers.rs`), the matcher loop alias in `dispatchers/dispatch_matchers.rs`, the field/variant adapters in `field_matchers/` (`extract_field.rs`, `extract_first_field.rs`, `extract_handle.rs`, `field_value.rs`, `first_field_value.rs`), the convenience matchers and the `ToFieldHandlers`/`HasFieldHandlers`/`MapFieldHandler` machinery in `matchers/` (`match_with_field_handlers.rs`, `match_first_with_field_handlers.rs`, `to_field_handlers.rs`), and the builders in `field_builders/` (`build_and_set_field.rs`, `build_and_merge.rs`) and `builders/build_and_merge_outputs.rs`. The prelude re-exports the value-handler matchers from [crates/main/cgp-extra/src/prelude.rs](../../../crates/main/cgp-extra/src/prelude.rs); the remaining structs are reached through `cgp::extra::dispatch`. +- The provider structs live under [crates/extra/cgp-dispatch/src/providers/](../../../crates/extra/cgp-dispatch/src/providers/): the matchers in `with_handlers/` (`match_with_handlers.rs`, `match_with_handlers_ref.rs`, `match_with_handlers_mut.rs`, `match_first_with_handlers*.rs`, `build_with_handlers.rs`), the matcher loop alias in `dispatchers/dispatch_matchers.rs`, the field/variant adapters in `field_matchers/` (`extract_field.rs`, `extract_first_field.rs`, `extract_handle.rs`, `field_value.rs`, `first_field_value.rs`), the convenience matchers and the `ToFieldHandlers`/`HasFieldHandlers`/`MapFieldHandler` machinery in `matchers/` (`match_with_field_handlers.rs`, `match_first_with_field_handlers.rs`, `to_field_handlers.rs`), and the builders in `field_builders/` (`build_and_set_field.rs`, `build_and_merge.rs`) and `builders/build_and_merge_outputs.rs`. +- The prelude re-exports the value-handler matchers from [crates/main/cgp-extra/src/prelude.rs](../../../crates/main/cgp-extra/src/prelude.rs); the remaining structs are reached through `cgp::extra::dispatch`. diff --git a/docs/reference/providers/error_providers.md b/docs/reference/providers/error_providers.md index 7202d856..847eb94e 100644 --- a/docs/reference/providers/error_providers.md +++ b/docs/reference/providers/error_providers.md @@ -189,4 +189,6 @@ These providers implement the [`CanRaiseError`](../components/can_raise_error.md ## Source -The providers are defined in `cgp-error-extra`: `RaiseFrom` in [crates/extra/cgp-error-extra/src/impls/raise_from.rs](../../../crates/extra/cgp-error-extra/src/impls/raise_from.rs), `ReturnError` in [return_error.rs](../../../crates/extra/cgp-error-extra/src/impls/return_error.rs), `RaiseInfallible` in [infallible.rs](../../../crates/extra/cgp-error-extra/src/impls/infallible.rs), `DiscardDetail` in [discard_detail.rs](../../../crates/extra/cgp-error-extra/src/impls/discard_detail.rs), `PanicOnError` in [panic_error.rs](../../../crates/extra/cgp-error-extra/src/impls/panic_error.rs), and `DebugError`/`DisplayError` (behind the `alloc` feature) in [impls/alloc/debug_error.rs](../../../crates/extra/cgp-error-extra/src/impls/alloc/debug_error.rs) and [display_error.rs](../../../crates/extra/cgp-error-extra/src/impls/alloc/display_error.rs). The `ErrorRaiser`/`ErrorWrapper` provider traits and the `CanRaiseError`/`CanWrapError`/`HasErrorType` consumer traits they build on are in [crates/core/cgp-error/src/](../../../crates/core/cgp-error/src/). The standalone backend counterparts are in [crates/standalone/error/](../../../crates/standalone/error/). +- The providers are defined in `cgp-error-extra`: `RaiseFrom` in [crates/extra/cgp-error-extra/src/impls/raise_from.rs](../../../crates/extra/cgp-error-extra/src/impls/raise_from.rs), `ReturnError` in [return_error.rs](../../../crates/extra/cgp-error-extra/src/impls/return_error.rs), `RaiseInfallible` in [infallible.rs](../../../crates/extra/cgp-error-extra/src/impls/infallible.rs), `DiscardDetail` in [discard_detail.rs](../../../crates/extra/cgp-error-extra/src/impls/discard_detail.rs), `PanicOnError` in [panic_error.rs](../../../crates/extra/cgp-error-extra/src/impls/panic_error.rs), and `DebugError`/`DisplayError` (behind the `alloc` feature) in [impls/alloc/debug_error.rs](../../../crates/extra/cgp-error-extra/src/impls/alloc/debug_error.rs) and [display_error.rs](../../../crates/extra/cgp-error-extra/src/impls/alloc/display_error.rs). +- The `ErrorRaiser`/`ErrorWrapper` provider traits and the `CanRaiseError`/`CanWrapError`/`HasErrorType` consumer traits they build on are in [crates/core/cgp-error/src/](../../../crates/core/cgp-error/src/). +- The standalone backend counterparts are in [crates/standalone/error/](../../../crates/standalone/error/). diff --git a/docs/reference/providers/handler_combinators.md b/docs/reference/providers/handler_combinators.md index 86cb7783..e3d5f108 100644 --- a/docs/reference/providers/handler_combinators.md +++ b/docs/reference/providers/handler_combinators.md @@ -217,4 +217,5 @@ The combinators are providers of the handler component traits: [`Computer`](../c ## Source -The combinators are defined in `cgp-handler` under [crates/extra/cgp-handler/src/providers/](../../../crates/extra/cgp-handler/src/providers/): `compose.rs` (`ComposeHandlers`), `pipe.rs` (`PipeHandlers` and the internal `ComposeProviders` fold), `return_input.rs` (`ReturnInput`), `promote.rs` (`Promote`), `promote_async.rs` (`PromoteAsync`), `promote_ref.rs` (`PromoteRef`), `try_promote.rs` (`TryPromote`), and `promote_all.rs` (the `PromoteComputer`, `PromoteTryComputer`, `PromoteProducer`, `PromoteAsyncComputer`, and `PromoteHandler` bundles). `UseInputDelegate` is defined in [crates/extra/cgp-handler/src/types.rs](../../../crates/extra/cgp-handler/src/types.rs), and its provider impls are generated from the `#[derive_delegate(UseInputDelegate)]` directive on the handler component traits in [crates/extra/cgp-handler/src/components/](../../../crates/extra/cgp-handler/src/components/). +- The combinators are defined in `cgp-handler` under [crates/extra/cgp-handler/src/providers/](../../../crates/extra/cgp-handler/src/providers/): `compose.rs` (`ComposeHandlers`), `pipe.rs` (`PipeHandlers` and the internal `ComposeProviders` fold), `return_input.rs` (`ReturnInput`), `promote.rs` (`Promote`), `promote_async.rs` (`PromoteAsync`), `promote_ref.rs` (`PromoteRef`), `try_promote.rs` (`TryPromote`), and `promote_all.rs` (the `PromoteComputer`, `PromoteTryComputer`, `PromoteProducer`, `PromoteAsyncComputer`, and `PromoteHandler` bundles). +- `UseInputDelegate` is defined in [crates/extra/cgp-handler/src/types.rs](../../../crates/extra/cgp-handler/src/types.rs), and its provider impls are generated from the `#[derive_delegate(UseInputDelegate)]` directive on the handler component traits in [crates/extra/cgp-handler/src/components/](../../../crates/extra/cgp-handler/src/components/). diff --git a/docs/reference/providers/monad_providers.md b/docs/reference/providers/monad_providers.md index b484250b..497fc613 100644 --- a/docs/reference/providers/monad_providers.md +++ b/docs/reference/providers/monad_providers.md @@ -101,4 +101,5 @@ PipeMonadic::::try_co ## Source -The pipeline provider, `TryPromoteProviders`, and the internal `BindProviders` fold are in [crates/extra/cgp-monad/src/providers/pipe_monadic.rs](../../../crates/extra/cgp-monad/src/providers/pipe_monadic.rs). The monad markers and bind providers are in [crates/extra/cgp-monad/src/monadic/](../../../crates/extra/cgp-monad/src/monadic/) — `ident.rs` for `IdentMonadic`, `ok.rs` for `OkMonadic` / `OkMonadicTrans` / `BindOk`, and `err.rs` for `ErrMonadic` / `ErrMonadicTrans` / `BindErr`. +- The pipeline provider, `TryPromoteProviders`, and the internal `BindProviders` fold are in [crates/extra/cgp-monad/src/providers/pipe_monadic.rs](../../../crates/extra/cgp-monad/src/providers/pipe_monadic.rs). +- The monad markers and bind providers are in [crates/extra/cgp-monad/src/monadic/](../../../crates/extra/cgp-monad/src/monadic/) — `ident.rs` for `IdentMonadic`, `ok.rs` for `OkMonadic` / `OkMonadicTrans` / `BindOk`, and `err.rs` for `ErrMonadic` / `ErrMonadicTrans` / `BindErr`. diff --git a/docs/reference/providers/redirect_lookup.md b/docs/reference/providers/redirect_lookup.md index 05eda12a..b71df410 100644 --- a/docs/reference/providers/redirect_lookup.md +++ b/docs/reference/providers/redirect_lookup.md @@ -78,4 +78,7 @@ This registers `TestProvider` under the path `bar`/`baz` in `App`'s default name ## Source -The struct is defined in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs), and the related `DefaultNamespace` trait in [crates/core/cgp-component/src/namespaces.rs](../../../crates/core/cgp-component/src/namespaces.rs). The `RedirectLookup` provider impl is generated by `to_redirect_lookup_impl` in [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs), which appends generic parameters through `ConcatPath`. The namespace delegates that target `RedirectLookup` are produced by the `#[prefix]` attribute in [crates/macros/cgp-macro-core/src/types/attributes/prefix.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/prefix.rs) and the redirect mapping in [crates/macros/cgp-macro-core/src/types/delegate_component/mapping/redirect.rs](../../../crates/macros/cgp-macro-core/src/types/delegate_component/mapping/redirect.rs). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_component](../../implementation/entrypoints/cgp_component.md). +- The struct is defined in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs), and the related `DefaultNamespace` trait in [crates/core/cgp-component/src/namespaces.rs](../../../crates/core/cgp-component/src/namespaces.rs). +- The `RedirectLookup` provider impl is generated by `to_redirect_lookup_impl` in [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_redirect_lookup_impl.rs), which appends generic parameters through `ConcatPath`. +- The namespace delegates that target `RedirectLookup` are produced by the `#[prefix]` attribute in [crates/macros/cgp-macro-core/src/types/attributes/prefix.rs](../../../crates/macros/cgp-macro-core/src/types/attributes/prefix.rs) and the redirect mapping in [crates/macros/cgp-macro-core/src/types/delegate_component/mapping/redirect.rs](../../../crates/macros/cgp-macro-core/src/types/delegate_component/mapping/redirect.rs). +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_component](../../implementation/entrypoints/cgp_component.md). diff --git a/docs/reference/providers/use_context.md b/docs/reference/providers/use_context.md index dedf0d6c..e0aa0541 100644 --- a/docs/reference/providers/use_context.md +++ b/docs/reference/providers/use_context.md @@ -85,4 +85,6 @@ Note that `UseContext` only acts as a default when a higher-order provider's str ## Source -The struct is defined in [crates/core/cgp-component/src/providers/use_context.rs](../../../crates/core/cgp-component/src/providers/use_context.rs), which also declares the `WithContext` alias. The `UseContext` provider impl is generated by `to_use_context_impl` in [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_use_context_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_use_context_impl.rs), which forwards each provider-trait method to the consumer trait via `trait_items_to_delegated_impl_items`. For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_component](../../implementation/entrypoints/cgp_component.md). +- The struct is defined in [crates/core/cgp-component/src/providers/use_context.rs](../../../crates/core/cgp-component/src/providers/use_context.rs), which also declares the `WithContext` alias. +- The `UseContext` provider impl is generated by `to_use_context_impl` in [crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_use_context_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_component/evaluated/to_use_context_impl.rs), which forwards each provider-trait method to the consumer trait via `trait_items_to_delegated_impl_items`. +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_component](../../implementation/entrypoints/cgp_component.md). diff --git a/docs/reference/providers/use_default.md b/docs/reference/providers/use_default.md index b20d7349..f30222f4 100644 --- a/docs/reference/providers/use_default.md +++ b/docs/reference/providers/use_default.md @@ -107,4 +107,5 @@ delegate_components! { ## Source -The struct is defined in [crates/core/cgp-component/src/providers/use_default.rs](../../../crates/core/cgp-component/src/providers/use_default.rs) and re-exported in [crates/core/cgp-component/src/providers/mod.rs](../../../crates/core/cgp-component/src/providers/mod.rs); the file contains only the bare struct, with no macro-generated impls. For how it is generated and the index of tests, see the implementation document [implementation/asts/attributes](../../implementation/asts/attributes.md). +- The struct is defined in [crates/core/cgp-component/src/providers/use_default.rs](../../../crates/core/cgp-component/src/providers/use_default.rs) and re-exported in [crates/core/cgp-component/src/providers/mod.rs](../../../crates/core/cgp-component/src/providers/mod.rs); the file contains only the bare struct, with no macro-generated impls. +- For how it is generated and the index of tests, see the implementation document [implementation/asts/attributes](../../implementation/asts/attributes.md). diff --git a/docs/reference/providers/use_delegate.md b/docs/reference/providers/use_delegate.md index f7fd5f04..cc6ea9a7 100644 --- a/docs/reference/providers/use_delegate.md +++ b/docs/reference/providers/use_delegate.md @@ -95,4 +95,7 @@ The wiring reads in two layers. `MyApp` delegates `AreaCalculatorComponent` to ` ## Source -The struct is defined in [crates/core/cgp-component/src/providers/use_delegate.rs](../../../crates/core/cgp-component/src/providers/use_delegate.rs). The `UseDelegate` provider impl is generated from the `#[derive_delegate]` directive parsed in [crates/macros/cgp-macro-core/src/types/attributes/](../../../crates/macros/cgp-macro-core/src/types/attributes/) and emitted by the `#[cgp_component]` pipeline in [crates/macros/cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/). The nested-table wiring is handled by `delegate_components!` in [crates/macros/cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/). For how it is generated and the index of tests, see the implementation document [implementation/asts/attributes](../../implementation/asts/attributes.md). +- The struct is defined in [crates/core/cgp-component/src/providers/use_delegate.rs](../../../crates/core/cgp-component/src/providers/use_delegate.rs). +- The `UseDelegate` provider impl is generated from the `#[derive_delegate]` directive parsed in [crates/macros/cgp-macro-core/src/types/attributes/](../../../crates/macros/cgp-macro-core/src/types/attributes/) and emitted by the `#[cgp_component]` pipeline in [crates/macros/cgp-macro-core/src/types/cgp_component/](../../../crates/macros/cgp-macro-core/src/types/cgp_component/). +- The nested-table wiring is handled by `delegate_components!` in [crates/macros/cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/). +- For how it is generated and the index of tests, see the implementation document [implementation/asts/attributes](../../implementation/asts/attributes.md). diff --git a/docs/reference/providers/use_delegated_type.md b/docs/reference/providers/use_delegated_type.md index 7d44ca41..60e66032 100644 --- a/docs/reference/providers/use_delegated_type.md +++ b/docs/reference/providers/use_delegated_type.md @@ -88,4 +88,5 @@ This is what makes `UseDelegatedType` valuable for bundling: the set of concrete ## Source -The `UseDelegatedType` struct, its `WithDelegatedType` alias, and the `TypeProvider` impl are in [crates/core/cgp-type/src/impls/use_delegated_type.rs](../../../crates/core/cgp-type/src/impls/use_delegated_type.rs). The `HasType` consumer trait and `TypeProvider` provider trait are in [crates/core/cgp-type/src/traits/has_type.rs](../../../crates/core/cgp-type/src/traits/has_type.rs), and `DelegateComponent` is in [crates/core/cgp-component/src/traits/delegate_component.rs](../../../crates/core/cgp-component/src/traits/delegate_component.rs). +- The `UseDelegatedType` struct, its `WithDelegatedType` alias, and the `TypeProvider` impl are in [crates/core/cgp-type/src/impls/use_delegated_type.rs](../../../crates/core/cgp-type/src/impls/use_delegated_type.rs). +- The `HasType` consumer trait and `TypeProvider` provider trait are in [crates/core/cgp-type/src/traits/has_type.rs](../../../crates/core/cgp-type/src/traits/has_type.rs), and `DelegateComponent` is in [crates/core/cgp-component/src/traits/delegate_component.rs](../../../crates/core/cgp-component/src/traits/delegate_component.rs). diff --git a/docs/reference/providers/use_field.md b/docs/reference/providers/use_field.md index f6777167..80467156 100644 --- a/docs/reference/providers/use_field.md +++ b/docs/reference/providers/use_field.md @@ -91,4 +91,7 @@ Both forms read `first_name`; `UseField` is the idiomatic choice for binding a g ## Source -The `UseField` struct, its `WithField` alias, and the `FieldGetter`, `MutFieldGetter`, and `TypeProvider` impls are in [crates/core/cgp-field/src/impls/use_field.rs](../../../crates/core/cgp-field/src/impls/use_field.rs). The `HasField`, `FieldGetter`, and (in `has_field_mut.rs`) `HasFieldMut`, `MutFieldGetter` traits are in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). The `#[cgp_getter]`-generated `UseField` impl is built in [crates/macros/cgp-macro-core/src/types/cgp_getter/use_field.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/use_field.rs). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_getter](../../implementation/entrypoints/cgp_getter.md). +- The `UseField` struct, its `WithField` alias, and the `FieldGetter`, `MutFieldGetter`, and `TypeProvider` impls are in [crates/core/cgp-field/src/impls/use_field.rs](../../../crates/core/cgp-field/src/impls/use_field.rs). +- The `HasField`, `FieldGetter`, and (in `has_field_mut.rs`) `HasFieldMut`, `MutFieldGetter` traits are in [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/). +- The `#[cgp_getter]`-generated `UseField` impl is built in [crates/macros/cgp-macro-core/src/types/cgp_getter/use_field.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/use_field.rs). +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_getter](../../implementation/entrypoints/cgp_getter.md). diff --git a/docs/reference/providers/use_field_ref.md b/docs/reference/providers/use_field_ref.md index fe0c00d2..9e58f947 100644 --- a/docs/reference/providers/use_field_ref.md +++ b/docs/reference/providers/use_field_ref.md @@ -84,4 +84,5 @@ delegate_components! { ## Source -The `UseFieldRef` struct, its `WithFieldRef` alias, and the `FieldGetter` and `MutFieldGetter` impls are in [crates/core/cgp-field/src/impls/use_ref.rs](../../../crates/core/cgp-field/src/impls/use_ref.rs). The `HasField` and `FieldGetter` traits are in [crates/core/cgp-field/src/traits/has_field.rs](../../../crates/core/cgp-field/src/traits/has_field.rs), and `HasFieldMut`/`MutFieldGetter` are in [crates/core/cgp-field/src/traits/has_field_mut.rs](../../../crates/core/cgp-field/src/traits/has_field_mut.rs). +- The `UseFieldRef` struct, its `WithFieldRef` alias, and the `FieldGetter` and `MutFieldGetter` impls are in [crates/core/cgp-field/src/impls/use_ref.rs](../../../crates/core/cgp-field/src/impls/use_ref.rs). +- The `HasField` and `FieldGetter` traits are in [crates/core/cgp-field/src/traits/has_field.rs](../../../crates/core/cgp-field/src/traits/has_field.rs), and `HasFieldMut`/`MutFieldGetter` are in [crates/core/cgp-field/src/traits/has_field_mut.rs](../../../crates/core/cgp-field/src/traits/has_field_mut.rs). diff --git a/docs/reference/providers/use_fields.md b/docs/reference/providers/use_fields.md index f96877cf..e7969c06 100644 --- a/docs/reference/providers/use_fields.md +++ b/docs/reference/providers/use_fields.md @@ -86,4 +86,6 @@ Because `App` wires `FooGetterComponent` to `UseFields`, the generated impl read ## Source -The struct is defined in [crates/core/cgp-component/src/providers/use_fields.rs](../../../crates/core/cgp-component/src/providers/use_fields.rs). The `UseFields` impl is built by `to_use_fields_impl` in [crates/macros/cgp-macro-core/src/types/cgp_getter/to_use_fields_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/to_use_fields_impl.rs), which keys each method on its name via `Symbol::from_ident` and emits a matching `HasField` bound. For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_getter](../../implementation/entrypoints/cgp_getter.md). +- The struct is defined in [crates/core/cgp-component/src/providers/use_fields.rs](../../../crates/core/cgp-component/src/providers/use_fields.rs). +- The `UseFields` impl is built by `to_use_fields_impl` in [crates/macros/cgp-macro-core/src/types/cgp_getter/to_use_fields_impl.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/to_use_fields_impl.rs), which keys each method on its name via `Symbol::from_ident` and emits a matching `HasField` bound. +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_getter](../../implementation/entrypoints/cgp_getter.md). diff --git a/docs/reference/providers/use_type.md b/docs/reference/providers/use_type.md index ade70ee1..6c3570cf 100644 --- a/docs/reference/providers/use_type.md +++ b/docs/reference/providers/use_type.md @@ -96,4 +96,7 @@ Both forms produce the same result — `App::Scalar` is `f64` — which is why ` ## Source -The `UseType` struct, its `WithType` alias, and the built-in `TypeProvider` impl are in [crates/core/cgp-type/src/impls/use_type.rs](../../../crates/core/cgp-type/src/impls/use_type.rs). The `HasType` consumer trait, the `TypeProvider` provider trait, and the `TypeOf` alias are in [crates/core/cgp-type/src/traits/has_type.rs](../../../crates/core/cgp-type/src/traits/has_type.rs). The `#[cgp_type]`-generated `UseType` impl is built in [crates/macros/cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_type](../../implementation/entrypoints/cgp_type.md). +- The `UseType` struct, its `WithType` alias, and the built-in `TypeProvider` impl are in [crates/core/cgp-type/src/impls/use_type.rs](../../../crates/core/cgp-type/src/impls/use_type.rs). +- The `HasType` consumer trait, the `TypeProvider` provider trait, and the `TypeOf` alias are in [crates/core/cgp-type/src/traits/has_type.rs](../../../crates/core/cgp-type/src/traits/has_type.rs). +- The `#[cgp_type]`-generated `UseType` impl is built in [crates/macros/cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs). +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_type](../../implementation/entrypoints/cgp_type.md). diff --git a/docs/reference/providers/with_provider.md b/docs/reference/providers/with_provider.md index e462c4d7..89b3e7a6 100644 --- a/docs/reference/providers/with_provider.md +++ b/docs/reference/providers/with_provider.md @@ -93,4 +93,7 @@ delegate_components! { ## Source -The struct is defined in [crates/core/cgp-component/src/providers/with_provider.rs](../../../crates/core/cgp-component/src/providers/with_provider.rs), and the `WithContext` alias in [crates/core/cgp-component/src/providers/use_context.rs](../../../crates/core/cgp-component/src/providers/use_context.rs). The remaining aliases are defined beside their inner providers: `WithType` and `WithDelegatedType` in [crates/core/cgp-type/src/impls/use_type.rs](../../../crates/core/cgp-type/src/impls/use_type.rs) and [use_delegated_type.rs](../../../crates/core/cgp-type/src/impls/use_delegated_type.rs), and `WithField` and `WithFieldRef` in [crates/core/cgp-field/src/impls/use_field.rs](../../../crates/core/cgp-field/src/impls/use_field.rs) and [use_ref.rs](../../../crates/core/cgp-field/src/impls/use_ref.rs). The component `WithProvider` impls are generated by `#[cgp_type]` in [crates/macros/cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs) and by `#[cgp_getter]` in [crates/macros/cgp-macro-core/src/types/cgp_getter/with_provider.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/with_provider.rs). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_getter](../../implementation/entrypoints/cgp_getter.md). +- The struct is defined in [crates/core/cgp-component/src/providers/with_provider.rs](../../../crates/core/cgp-component/src/providers/with_provider.rs), and the `WithContext` alias in [crates/core/cgp-component/src/providers/use_context.rs](../../../crates/core/cgp-component/src/providers/use_context.rs). +- The remaining aliases are defined beside their inner providers: `WithType` and `WithDelegatedType` in [crates/core/cgp-type/src/impls/use_type.rs](../../../crates/core/cgp-type/src/impls/use_type.rs) and [use_delegated_type.rs](../../../crates/core/cgp-type/src/impls/use_delegated_type.rs), and `WithField` and `WithFieldRef` in [crates/core/cgp-field/src/impls/use_field.rs](../../../crates/core/cgp-field/src/impls/use_field.rs) and [use_ref.rs](../../../crates/core/cgp-field/src/impls/use_ref.rs). +- The component `WithProvider` impls are generated by `#[cgp_type]` in [crates/macros/cgp-macro-core/src/types/cgp_type/item.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_type/item.rs) and by `#[cgp_getter]` in [crates/macros/cgp-macro-core/src/types/cgp_getter/with_provider.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_getter/with_provider.rs). +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_getter](../../implementation/entrypoints/cgp_getter.md). diff --git a/docs/reference/traits/can_use_component.md b/docs/reference/traits/can_use_component.md index 8511e250..06384733 100644 --- a/docs/reference/traits/can_use_component.md +++ b/docs/reference/traits/can_use_component.md @@ -95,4 +95,6 @@ where ## Source -The trait and its sole blanket impl are defined in [crates/core/cgp-component/src/traits/can_use_component.rs](../../../crates/core/cgp-component/src/traits/can_use_component.rs) and re-exported through [crates/core/cgp-component/src/macro_prelude.rs](../../../crates/core/cgp-component/src/macro_prelude.rs). The checks that assert it are generated by `check_components!`, whose codegen lives in [crates/macros/cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/) — `table.rs` chooses `CanUseComponent` versus `IsProviderFor` as the check trait's supertrait. For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/check_components.md](../../implementation/entrypoints/check_components.md). +- The trait and its sole blanket impl are defined in [crates/core/cgp-component/src/traits/can_use_component.rs](../../../crates/core/cgp-component/src/traits/can_use_component.rs) and re-exported through [crates/core/cgp-component/src/macro_prelude.rs](../../../crates/core/cgp-component/src/macro_prelude.rs). +- The checks that assert it are generated by `check_components!`, whose codegen lives in [crates/macros/cgp-macro-core/src/types/check_components/](../../../crates/macros/cgp-macro-core/src/types/check_components/) — `table.rs` chooses `CanUseComponent` versus `IsProviderFor` as the check trait's supertrait. +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/check_components.md](../../implementation/entrypoints/check_components.md). diff --git a/docs/reference/traits/cast.md b/docs/reference/traits/cast.md index 818deac4..63fe3c18 100644 --- a/docs/reference/traits/cast.md +++ b/docs/reference/traits/cast.md @@ -105,4 +105,6 @@ The casting traits sit on top of the extensible-data primitives: variant casts r ## Source -`CanUpcast`, `CanDowncast`, and `CanDowncastFields`, together with the internal `FieldsExtractor` recursion that drives them, are defined in [crates/core/cgp-field/src/impls/cast.rs](../../../crates/core/cgp-field/src/impls/cast.rs). `CanBuildFrom` and its internal `FieldsBuilder` recursion are in [crates/core/cgp-field/src/impls/build_from.rs](../../../crates/core/cgp-field/src/impls/build_from.rs). The underlying extractor and builder traits are under [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/) (`extract_field.rs`, `from_variant.rs`, `has_builder.rs`). +- `CanUpcast`, `CanDowncast`, and `CanDowncastFields`, together with the internal `FieldsExtractor` recursion that drives them, are defined in [crates/core/cgp-field/src/impls/cast.rs](../../../crates/core/cgp-field/src/impls/cast.rs). +- `CanBuildFrom` and its internal `FieldsBuilder` recursion are in [crates/core/cgp-field/src/impls/build_from.rs](../../../crates/core/cgp-field/src/impls/build_from.rs). +- The underlying extractor and builder traits are under [crates/core/cgp-field/src/traits/](../../../crates/core/cgp-field/src/traits/) (`extract_field.rs`, `from_variant.rs`, `has_builder.rs`). diff --git a/docs/reference/traits/default_namespace.md b/docs/reference/traits/default_namespace.md index a294bdec..90bc5dd5 100644 --- a/docs/reference/traits/default_namespace.md +++ b/docs/reference/traits/default_namespace.md @@ -98,4 +98,7 @@ Pointing a `for in DefaultShowComponents { … }` loop at this nam ## Source -The three traits are defined in [crates/core/cgp-component/src/namespaces.rs](../../../crates/core/cgp-component/src/namespaces.rs), with `DefaultNamespace` re-exported through [crates/core/cgp-component/src/macro_prelude.rs](../../../crates/core/cgp-component/src/macro_prelude.rs). The namespace macro that builds the namespace trait and its inheritance impl lives in [crates/macros/cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/); the `#[default_impl(... in DefaultImpls1<...>)]` attribute that registers a per-type default is parsed and lowered in [crates/macros/cgp-macro-core/src/types/attributes/default_impl/](../../../crates/macros/cgp-macro-core/src/types/attributes/default_impl/). The `namespace` header and `for … in` loop are handled by the `delegate_components!` codegen in [crates/macros/cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_namespace.md](../../implementation/entrypoints/cgp_namespace.md). +- The three traits are defined in [crates/core/cgp-component/src/namespaces.rs](../../../crates/core/cgp-component/src/namespaces.rs), with `DefaultNamespace` re-exported through [crates/core/cgp-component/src/macro_prelude.rs](../../../crates/core/cgp-component/src/macro_prelude.rs). +- The namespace macro that builds the namespace trait and its inheritance impl lives in [crates/macros/cgp-macro-core/src/types/namespace/](../../../crates/macros/cgp-macro-core/src/types/namespace/); the `#[default_impl(... in DefaultImpls1<...>)]` attribute that registers a per-type default is parsed and lowered in [crates/macros/cgp-macro-core/src/types/attributes/default_impl/](../../../crates/macros/cgp-macro-core/src/types/attributes/default_impl/). +- The `namespace` header and `for … in` loop are handled by the `delegate_components!` codegen in [crates/macros/cgp-macro-core/src/types/delegate_component/](../../../crates/macros/cgp-macro-core/src/types/delegate_component/). +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/cgp_namespace.md](../../implementation/entrypoints/cgp_namespace.md). diff --git a/docs/reference/traits/delegate_component.md b/docs/reference/traits/delegate_component.md index fd80712c..bdd2c7b4 100644 --- a/docs/reference/traits/delegate_component.md +++ b/docs/reference/traits/delegate_component.md @@ -108,4 +108,7 @@ The bound `AreaComponents: DelegateComponent` is the "get", and `>::Output; ## Source -`StaticFormat` and its `Chars`/`Nil` impls are defined in [crates/core/cgp-base-types/src/traits/static_format.rs](../../../crates/core/cgp-base-types/src/traits/static_format.rs); the `Display` impls that delegate to it are on the [`Chars`](../types/chars.md) and [`Symbol`](../macros/symbol.md) types in [crates/core/cgp-base-types/src/types/](../../../crates/core/cgp-base-types/src/types/). `StaticString`, with its const-evaluated UTF-8 decoding, is in [crates/core/cgp-field/src/traits/static_string.rs](../../../crates/core/cgp-field/src/traits/static_string.rs). `ConcatPath` is in [crates/core/cgp-base-types/src/traits/concat_path.rs](../../../crates/core/cgp-base-types/src/traits/concat_path.rs), and `PathCons` in [crates/core/cgp-base-types/src/types/path.rs](../../../crates/core/cgp-base-types/src/types/path.rs). +- `StaticFormat` and its `Chars`/`Nil` impls are defined in [crates/core/cgp-base-types/src/traits/static_format.rs](../../../crates/core/cgp-base-types/src/traits/static_format.rs); the `Display` impls that delegate to it are on the [`Chars`](../types/chars.md) and [`Symbol`](../macros/symbol.md) types in [crates/core/cgp-base-types/src/types/](../../../crates/core/cgp-base-types/src/types/). +- `StaticString`, with its const-evaluated UTF-8 decoding, is in [crates/core/cgp-field/src/traits/static_string.rs](../../../crates/core/cgp-field/src/traits/static_string.rs). +- `ConcatPath` is in [crates/core/cgp-base-types/src/traits/concat_path.rs](../../../crates/core/cgp-base-types/src/traits/concat_path.rs), and `PathCons` in [crates/core/cgp-base-types/src/types/path.rs](../../../crates/core/cgp-base-types/src/types/path.rs). diff --git a/docs/reference/types/chars.md b/docs/reference/types/chars.md index 25b82559..1e15be52 100644 --- a/docs/reference/types/chars.md +++ b/docs/reference/types/chars.md @@ -71,4 +71,7 @@ Because the encoding is a list, an empty string is `Symbol<0, Nil>` — a `Symbo ## Source -The runtime types are defined in [crates/core/cgp-base-types/src/types/chars.rs](../../../crates/core/cgp-base-types/src/types/chars.rs) (`Chars`) and [crates/core/cgp-base-types/src/types/symbol.rs](../../../crates/core/cgp-base-types/src/types/symbol.rs) (`Symbol`), with `Nil` in [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs). The `StaticFormat` impls that drive `Display` are in [crates/core/cgp-base-types/src/traits/static_format.rs](../../../crates/core/cgp-base-types/src/traits/static_format.rs), and the const-decoding `StaticString` impl that consumes `LEN` is in [crates/core/cgp-field/src/traits/static_string.rs](../../../crates/core/cgp-field/src/traits/static_string.rs). The constructing macro is [`Symbol!`](../macros/symbol.md). For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/symbol.md](../../implementation/entrypoints/symbol.md). +- The runtime types are defined in [crates/core/cgp-base-types/src/types/chars.rs](../../../crates/core/cgp-base-types/src/types/chars.rs) (`Chars`) and [crates/core/cgp-base-types/src/types/symbol.rs](../../../crates/core/cgp-base-types/src/types/symbol.rs) (`Symbol`), with `Nil` in [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs). +- The `StaticFormat` impls that drive `Display` are in [crates/core/cgp-base-types/src/traits/static_format.rs](../../../crates/core/cgp-base-types/src/traits/static_format.rs), and the const-decoding `StaticString` impl that consumes `LEN` is in [crates/core/cgp-field/src/traits/static_string.rs](../../../crates/core/cgp-field/src/traits/static_string.rs). +- The constructing macro is [`Symbol!`](../macros/symbol.md). +- For how it is generated and the index of tests, see the implementation document [implementation/entrypoints/symbol.md](../../implementation/entrypoints/symbol.md). diff --git a/docs/reference/types/cons.md b/docs/reference/types/cons.md index 3691e24f..8c228daf 100644 --- a/docs/reference/types/cons.md +++ b/docs/reference/types/cons.md @@ -71,4 +71,5 @@ let row: Row = product![1, "hi".to_string(), true]; ## Source -`Cons` is defined in [crates/core/cgp-base-types/src/types/cons.rs](../../../crates/core/cgp-base-types/src/types/cons.rs) and `Nil` in [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs). The `Product!`/`product!` macros that fold elements onto this spine are driven by the constructs under [crates/macros/cgp-macro-core/src/types/product/](../../../crates/macros/cgp-macro-core/src/types/product/), and the `HasFields` machinery that recurses over it lives in [crates/core/cgp-field/src/traits/has_fields.rs](../../../crates/core/cgp-field/src/traits/has_fields.rs). +- `Cons` is defined in [crates/core/cgp-base-types/src/types/cons.rs](../../../crates/core/cgp-base-types/src/types/cons.rs) and `Nil` in [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs). +- The `Product!`/`product!` macros that fold elements onto this spine are driven by the constructs under [crates/macros/cgp-macro-core/src/types/product/](../../../crates/macros/cgp-macro-core/src/types/product/), and the `HasFields` machinery that recurses over it lives in [crates/core/cgp-field/src/traits/has_fields.rs](../../../crates/core/cgp-field/src/traits/has_fields.rs). diff --git a/docs/reference/types/either.md b/docs/reference/types/either.md index 744f4fa5..38236734 100644 --- a/docs/reference/types/either.md +++ b/docs/reference/types/either.md @@ -79,4 +79,6 @@ let t: Token = Either::Right(Either::Left("hi".to_string())); // the String bran ## Source -`Either` and `Void` are both defined in [crates/core/cgp-field/src/types/sum.rs](../../../crates/core/cgp-field/src/types/sum.rs). The `Sum!` macro that folds element types onto this spine is the `SumType` construct in [crates/macros/cgp-macro-core/src/types/sum.rs](../../../crates/macros/cgp-macro-core/src/types/sum.rs). `FinalizeExtract for Void`, which discharges the uninhabited remainder of a variant extraction, lives in [crates/core/cgp-field/src/traits/extract_field.rs](../../../crates/core/cgp-field/src/traits/extract_field.rs), and the enum `HasFields` derive that emits a `Sum!` of `Field` branches is under [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs). +- `Either` and `Void` are both defined in [crates/core/cgp-field/src/types/sum.rs](../../../crates/core/cgp-field/src/types/sum.rs). +- The `Sum!` macro that folds element types onto this spine is the `SumType` construct in [crates/macros/cgp-macro-core/src/types/sum.rs](../../../crates/macros/cgp-macro-core/src/types/sum.rs). +- `FinalizeExtract for Void`, which discharges the uninhabited remainder of a variant extraction, lives in [crates/core/cgp-field/src/traits/extract_field.rs](../../../crates/core/cgp-field/src/traits/extract_field.rs), and the enum `HasFields` derive that emits a `Sum!` of `Field` branches is under [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs). diff --git a/docs/reference/types/field.md b/docs/reference/types/field.md index f63f6eca..b79e8c6b 100644 --- a/docs/reference/types/field.md +++ b/docs/reference/types/field.md @@ -70,4 +70,6 @@ For a tuple-struct field, the tag is an [`Index`](index.md) rather than a `Symbo ## Source -`Field` and its `From`, `Debug`, `PartialEq`, and `Eq` impls are defined in [crates/core/cgp-field/src/types/field.rs](../../../crates/core/cgp-field/src/types/field.rs). It is consumed by the field machinery: [`HasFields`](../traits/has_fields.md) in [crates/core/cgp-field/src/traits/has_fields.rs](../../../crates/core/cgp-field/src/traits/has_fields.rs), with the record/variant rebuilding traits in [crates/core/cgp-field/src/traits/from_fields.rs](../../../crates/core/cgp-field/src/traits/from_fields.rs) and [crates/core/cgp-field/src/traits/to_fields.rs](../../../crates/core/cgp-field/src/traits/to_fields.rs). The derive that emits `Product!`/`Sum!` lists of `Field` entries lives under [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/). +- `Field` and its `From`, `Debug`, `PartialEq`, and `Eq` impls are defined in [crates/core/cgp-field/src/types/field.rs](../../../crates/core/cgp-field/src/types/field.rs). +- It is consumed by the field machinery: [`HasFields`](../traits/has_fields.md) in [crates/core/cgp-field/src/traits/has_fields.rs](../../../crates/core/cgp-field/src/traits/has_fields.rs), with the record/variant rebuilding traits in [crates/core/cgp-field/src/traits/from_fields.rs](../../../crates/core/cgp-field/src/traits/from_fields.rs) and [crates/core/cgp-field/src/traits/to_fields.rs](../../../crates/core/cgp-field/src/traits/to_fields.rs). +- The derive that emits `Product!`/`Sum!` lists of `Field` entries lives under [crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/). diff --git a/docs/reference/types/index.md b/docs/reference/types/index.md index 7a5a3160..f9beb54c 100644 --- a/docs/reference/types/index.md +++ b/docs/reference/types/index.md @@ -68,4 +68,5 @@ assert_eq!(Index::<2>.to_string(), "2"); ## Source -`Index` and its `Display` and `Debug` impls are defined in [crates/core/cgp-field/src/types/index.rs](../../../crates/core/cgp-field/src/types/index.rs). The `#[derive(HasField)]` codegen that tags tuple-struct fields with `Index` lives under [crates/macros/cgp-macro-core/src/types/cgp_data/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/), and the `HasField` trait it targets is in [crates/core/cgp-field/src/traits/has_field.rs](../../../crates/core/cgp-field/src/traits/has_field.rs). +- `Index` and its `Display` and `Debug` impls are defined in [crates/core/cgp-field/src/types/index.rs](../../../crates/core/cgp-field/src/types/index.rs). +- The `#[derive(HasField)]` codegen that tags tuple-struct fields with `Index` lives under [crates/macros/cgp-macro-core/src/types/cgp_data/](../../../crates/macros/cgp-macro-core/src/types/cgp_data/), and the `HasField` trait it targets is in [crates/core/cgp-field/src/traits/has_field.rs](../../../crates/core/cgp-field/src/traits/has_field.rs). diff --git a/docs/reference/types/life.md b/docs/reference/types/life.md index c23156a1..0bf348aa 100644 --- a/docs/reference/types/life.md +++ b/docs/reference/types/life.md @@ -54,4 +54,6 @@ Every impl that wires this component — whether through `UseContext`, a `UseFie ## Source -The type is defined in [crates/core/cgp-field/src/types/life.rs](../../../crates/core/cgp-field/src/types/life.rs). The macro logic that wraps a trait's lifetime parameters in `Life` when building the `IsProviderFor` argument tuple is in [crates/macros/cgp-macro-core/src/functions/is_provider_params.rs](../../../crates/macros/cgp-macro-core/src/functions/is_provider_params.rs), with related placement in [crates/macros/cgp-macro-core/src/types/empty_struct.rs](../../../crates/macros/cgp-macro-core/src/types/empty_struct.rs) and [crates/macros/cgp-macro-core/src/types/cgp_provider/provider_impl_args.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/provider_impl_args.rs). For how it is generated and the index of tests, see the implementation document [implementation/functions/parse/is_provider_params.md](../../implementation/functions/parse/is_provider_params.md). +- The type is defined in [crates/core/cgp-field/src/types/life.rs](../../../crates/core/cgp-field/src/types/life.rs). +- The macro logic that wraps a trait's lifetime parameters in `Life` when building the `IsProviderFor` argument tuple is in [crates/macros/cgp-macro-core/src/functions/is_provider_params.rs](../../../crates/macros/cgp-macro-core/src/functions/is_provider_params.rs), with related placement in [crates/macros/cgp-macro-core/src/types/empty_struct.rs](../../../crates/macros/cgp-macro-core/src/types/empty_struct.rs) and [crates/macros/cgp-macro-core/src/types/cgp_provider/provider_impl_args.rs](../../../crates/macros/cgp-macro-core/src/types/cgp_provider/provider_impl_args.rs). +- For how it is generated and the index of tests, see the implementation document [implementation/functions/parse/is_provider_params.md](../../implementation/functions/parse/is_provider_params.md). diff --git a/docs/reference/types/mref.md b/docs/reference/types/mref.md index ce830f65..0ac4304c 100644 --- a/docs/reference/types/mref.md +++ b/docs/reference/types/mref.md @@ -57,4 +57,5 @@ Both `borrowed` and `made` have the same type and are consumed the same way; onl ## Source -The type is defined in [crates/core/cgp-field/src/types/mref.rs](../../../crates/core/cgp-field/src/types/mref.rs), including its `Deref`, `AsRef`, the two `From` impls, and `get_or_clone`. The macro logic that recognizes an `MRef<'a, T>` getter return type and emits an `MRef::Ref(...)` body is in [crates/macros/cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs) (the `MRef` field mode) and [crates/macros/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs](../../../crates/macros/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs). +- The type is defined in [crates/core/cgp-field/src/types/mref.rs](../../../crates/core/cgp-field/src/types/mref.rs), including its `Deref`, `AsRef`, the two `From` impls, and `get_or_clone`. +- The macro logic that recognizes an `MRef<'a, T>` getter return type and emits an `MRef::Ref(...)` body is in [crates/macros/cgp-macro-core/src/functions/field/parse.rs](../../../crates/macros/cgp-macro-core/src/functions/field/parse.rs) (the `MRef` field mode) and [crates/macros/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs](../../../crates/macros/cgp-macro-core/src/types/getter/get_field_with_mode_expr.rs). diff --git a/docs/reference/types/path_cons.md b/docs/reference/types/path_cons.md index 795b2715..3cf68113 100644 --- a/docs/reference/types/path_cons.md +++ b/docs/reference/types/path_cons.md @@ -78,4 +78,7 @@ Here the lookup steps first through `MyBarComponent` and then through `BarProvid ## Source -The runtime type is defined in [crates/core/cgp-base-types/src/types/path.rs](../../../crates/core/cgp-base-types/src/types/path.rs) (`PathCons`), with `Nil` in [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs). The `ConcatPath` trait and its impls are in [crates/core/cgp-base-types/src/traits/concat_path.rs](../../../crates/core/cgp-base-types/src/traits/concat_path.rs). The constructing macro is [`Path!`](../macros/path.md) ([crates/macros/cgp-macro-lib/src/path.rs](../../../crates/macros/cgp-macro-lib/src/path.rs)), whose fold over the segments lives in [crates/macros/cgp-macro-core/src/types/path/unipath.rs](../../../crates/macros/cgp-macro-core/src/types/path/unipath.rs). `RedirectLookup`, which consumes a path at resolution time, is in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs). +- The runtime type is defined in [crates/core/cgp-base-types/src/types/path.rs](../../../crates/core/cgp-base-types/src/types/path.rs) (`PathCons`), with `Nil` in [crates/core/cgp-base-types/src/types/nil.rs](../../../crates/core/cgp-base-types/src/types/nil.rs). +- The `ConcatPath` trait and its impls are in [crates/core/cgp-base-types/src/traits/concat_path.rs](../../../crates/core/cgp-base-types/src/traits/concat_path.rs). +- The constructing macro is [`Path!`](../macros/path.md) ([crates/macros/cgp-macro-lib/src/path.rs](../../../crates/macros/cgp-macro-lib/src/path.rs)), whose fold over the segments lives in [crates/macros/cgp-macro-core/src/types/path/unipath.rs](../../../crates/macros/cgp-macro-core/src/types/path/unipath.rs). +- `RedirectLookup`, which consumes a path at resolution time, is in [crates/core/cgp-component/src/providers/redirect_lookup.rs](../../../crates/core/cgp-component/src/providers/redirect_lookup.rs).