--- name: cgp description: >- Read, write, debug, and explain Context-Generic Programming (CGP) code in Rust. Use this skill whenever you encounter or are asked to work with CGP: any code that uses `cgp::prelude::*`, the `#[cgp_component]`, `#[cgp_impl]`, `#[cgp_provider]`, `#[cgp_fn]`, `#[cgp_type]`, `#[cgp_getter]`, `#[cgp_auto_getter]`, `#[cgp_computer]`, `#[cgp_producer]`, or `cgp_namespace!` macros, the `delegate_components!`, `check_components!`, or `delegate_and_check_components!` macros, the `Symbol!`, `Product!`, `Sum!`, or `Path!` type-level macros, the `HasField`/`HasFields` traits or their derives, providers such as `UseContext`/`UseDelegate`/`UseField`/`UseType`, the handler family (`Computer`/`Producer`/`Handler`), or terms like consumer trait, provider trait, provider, wiring, impl-side dependency, or context-generic. Trigger it even when the user does not say "CGP" by name but is clearly working with these constructs, when a Rust trait error mentions `IsProviderFor`/`DelegateComponent`, or when someone wants modular, dependency-injected, multiple-implementation Rust traits. --- # Context-Generic Programming (CGP) in Rust CGP is a modular programming paradigm for Rust that works around the language's coherence restrictions. It lets you write many overlapping or "orphan" trait implementations and then choose which one applies by **wiring** them onto a concrete context type. This file is a self-contained primer. Read it top to bottom and you hold the whole mental model: every core term, the shape of every construct, and enough of each expansion to read, write, and debug most CGP code. It is longer than a typical skill on purpose, because CGP's surface is broad and an agent who stops here should still be competent. **This primer is the map, not the territory. Load the sub-skill before you act on any construct it covers.** The primer gives you the shape of each construct. The `references/` sub-skills give you the exact grammar, the full expansion, the corner cases, and the worked examples. Mistakes live in the gap between the two. The primer tells you `#[cgp_impl]` writes a provider, but [components](references/components.md) tells you what `self` rewrites to, and [macro-grammar](references/macro-grammar.md) tells you which attribute forms parse. Without them you can emit an impl that fails to compile in a way the error message will not explain. So before you write, modify, review, or debug code that uses a construct, even a simple one, **open the sub-skill that owns it.** Each entry in [the sub-skill index](#sub-skills-load-the-one-that-owns-your-task) says what it adds beyond this primer, so you can tell what you would be guessing at without it. CGP is implemented almost entirely as procedural macros. Every macro desugars to ordinary Rust traits and impls, so the reliable way to understand any construct is to know the code it expands to. This primer shows those expansions where they matter and leaves them out where they do not. ## Tooling: use cargo-cgp for readable errors and expansions **Before debugging any CGP compile error, use `cargo-cgp` if it is available.** Its `check` command reshapes the errors, and its [`expand`](#reading-what-a-macro-generated-cargo-cgp-expand) command shows the code the macros generated. `cargo-cgp` is CGP's first-class toolchain: a cargo subcommand that stands in for `cargo check` and rewrites CGP's compiler errors into a compact, root-cause-first form, tagging each rewritten message with a `[CGP-Exxx]` code. A raw CGP error is often a wall of generated types with the real cause buried or hidden entirely. `cargo-cgp` names the cause and renders the dependency chain that leads to it. Recommend it to the user for building and checking CGP code, and prefer it over plain `cargo check` whenever a wiring failure needs diagnosing. **Check whether it is installed** with `cargo cgp --version`, or run `cargo cgp check` in a CGP project. If the subcommand is missing, it is not installed. **If it is not installed, recommend installing it.** Tell the user it makes CGP errors far more readable, and **install it on their behalf only with their approval**, because it provisions a nightly toolchain and builds a compiler-linked driver, which is heavy. **Prefer the cargo path**, which is the default for almost every machine: run `cargo install cargo-cgp`, then `cargo cgp setup`. The install puts the small front-end on whatever toolchain is present, and `setup` provisions the pinned nightly and builds the matching driver in lockstep. It needs rustup. **Reach for Nix only if the host has it**, shown by a `nix` command on `PATH` or a `flake.nix` in the project, or if the user asks for it. Otherwise do not bring Nix up. When Nix is present but cargo-cgp is not installed, the lightest move is to **not install** and instead run the tool through the flake from the project directory: `nix run github:contextgeneric/cargo-cgp/v0.1.0-alpha -- check` (arguments after `--` go to `cargo check`). To install into a Nix profile instead, use `nix profile install github:contextgeneric/cargo-cgp/v0.1.0-alpha`. cargo-cgp requires a specific pinned Rust nightly, installed by `cargo cgp setup` or built by the Nix flake. It forces that nightly only for its own check, so the user's project keeps its own toolchain. Full instructions: . **Using it:** run it wherever you would run `cargo check`, with arguments after `check` forwarded: `cargo cgp check`, `cargo cgp check --workspace`. It keeps rustc's own error code and adds a `[CGP-Exxx]` tag, leading with the root cause over a `cargo tree`-style dependency chain. The codes are catalogued at . ### Reading what a macro generated: `cargo cgp expand` **When a CGP error stops making sense, read the code the macros produced rather than reasoning about what you think they produce.** A wiring failure always means the emitted impls do not resolve, and the impls are generated, so the fastest way past a confusing diagnostic is often to look at them. `cargo cgp expand` prints the crate after macro expansion, with CGP's type-level constructs **resugared**. A field tag reads `Symbol!("width")`, not the raw `Symbol<5, Chars<'w', …>>` list the compiler prints. A pipeline reads `Product![StepOne, StepTwo]`, and a namespace key reads `Path!(@app.GreeterComponent)`. So the generated code is legible in the same vocabulary as the source. Reach for it when the answer is in the generated code rather than in the message: - **A diagnostic names a type you did not write** (`IsProviderFor<…>`, a `PathCons<…>` key, a `__Context__` parameter) and you need to see the impl it came from. - **A wiring table does not resolve** and you want the real `DelegateComponent` keys and `Delegate` values it produced, rather than inferring them from the table's syntax. - **You are unsure what a construct emits**, such as the exact `where` clauses of a provider impl, or whether a getter's blanket impl requires the field you think it does. Reading the expansion beats guessing, and beats trusting a remembered expansion. - **Two forms differ and only one compiles.** Expand both and diff them. The delta is the bug. Run it on one target, narrowed to what you care about: ```sh cargo cgp expand --lib # the whole library target cargo cgp expand --lib --item contexts::MockApp # one module, type, or trait ``` **Target selection is required when a package has several targets.** Pass `--lib` or `--bin NAME`, or cargo declines with "extra arguments to `rustc` can only be passed to one target". Other arguments (`-p`, `--features`) forward to `cargo rustc`. The expansion goes to stdout, so redirect it to a file when it is long and read that instead of flooding your context. **`--item ` makes the output manageable.** The path is `::`-separated, may carry a leading `crate::`, and names something inside the crate being expanded. What it names decides what you get: - a **module** gives its contents (`--item contexts`); - a **type** gives its declaration and every impl written *for* it. For a context struct that means the `HasField`/`HasFieldMut` impls the derive generated, and its `DelegateComponent` wiring entries with the real key and provider types (`--item Rectangle`); - a **trait** gives its definition and every impl *of* it, which is usually the rule you want. Naming a component's *provider* trait (`--item AreaCalculator`) gives the provider trait, the delegation blanket impl, the `UseContext` and `RedirectLookup` impls, and each wired provider's impl. Naming the *consumer* trait (`--item CanCalculateArea`) gives just the consumer trait and its routing blanket. Keep its limits in mind when you read the output. **`expand` is not a check.** It stops once the macros are expanded, so it reports nothing about wiring. Use `cargo cgp check` for that, and expect `expand` to succeed even on a crate that does not type-check, which makes it useful mid-debugging. **The output is for reading, not compiling.** The `cgp::macro_prelude::` qualifier is stripped, and an `open` statement's per-key entry keeps its raw `PathCons<…>` key. `expand` is newer than cargo-cgp v0.1.0-alpha, so a crates.io install does not carry it yet. Until the next release it comes from the Nix flake without a tag (`nix run github:contextgeneric/cargo-cgp -- expand --lib`) or from a source checkout. See . **Scope:** cargo-cgp is optional and adds only `check` and `expand`. It does not provide `cargo cgp build`, `run`, or `test`, so build, run, and test the project with plain cargo. CGP itself compiles on any **stable Rust ≥ 1.89**, so plain `cargo check` works on a CGP project too. Reach for `cargo cgp check` when you hit or expect a wiring error and want it made readable. `cargo-cgp` can also be Rust Analyzer's on-save check backend, via `rust-analyzer.check.overrideCommand` set to `["cargo","cgp","check","--workspace","--all-targets","--message-format=json"]`. But **never modify the user's Rust Analyzer settings implicitly.** Mention this option and let them opt in. Edit their editor configuration only when they ask you to. **When cargo-cgp is not available, or leaves an error largely unrewritten**, read the raw compiler output by hand. Only then load the [error-extraction sub-skill](references/error-extraction.md), the technique for reducing a raw CGP cascade to its root cause. When cargo-cgp has reshaped the error, its `[CGP-Exxx]` headline and root-cause tree are already the compact summary that sub-skill would produce, so you do not need it. ### Versions and keeping this skill current This skill is written for **CGP v0.8.0** and **cargo-cgp v0.1.0-alpha**. Check both on the host and act on a mismatch: - Read the user's `cgp` version from its `Cargo.toml` or `Cargo.lock` entry, and run `cargo cgp --version` for the tool. - **If either is older than recorded here**, recommend updating it so its behavior matches this skill: `cargo update -p cgp` for the library, and `cargo cgp update` (or a Nix flake refresh) for the tool. - **If the host's `cgp` is newer than v0.8.0**, this skill is behind the library. Tell the user the **skill should be upgraded** to match their `cgp`, rather than changing their code to fit an older skill. Treat the newer `cgp` as authoritative and flag the gap instead of guessing. ## The problem CGP solves Rust's coherence rules permit at most one implementation of a trait for a given type, and the orphan rule forbids implementing a foreign trait for a foreign type. This makes it hard to offer several interchangeable implementations of one interface, or to let a downstream crate choose an implementation for a type it does not own. CGP sidesteps both limits with a two-trait split. An implementation is written against a **provider trait** whose `Self` is a dummy marker type the crate owns, so coherence never blocks it. A concrete **context** type later picks which provider it uses through a small type-level table. The choice is local to the context, so two different contexts can wire the same interface to different implementations. ## Blanket traits and impl-side dependencies CGP grows out of blanket trait implementations (extension traits). The single most important idea to internalize is the **impl-side dependency**: a blanket impl can require constraints in its `where` clause that are *not* part of the trait interface. Those hidden requirements are the paradigm's form of dependency injection. For example: ```rust pub trait CanGreet { fn greet(&self); } pub trait HasName { fn name(&self) -> &str; } impl CanGreet for Context where Context: HasName, { fn greet(&self) { println!("Hello, {}!", self.name()); } } ``` `CanGreet` hides its `HasName` dependency inside the blanket impl, so a caller that is itself generic does not have to forward `HasName` the way it would with a free generic function. In CGP you typically start by writing generic logic as a blanket trait like this, and promote it to a full CGP component only when you need more than one implementation. Blanket traits are not themselves CGP components, but the technique recurs throughout CGP. ## The core vocabulary CGP code is readable once you hold a few terms in mind. A **consumer trait** is the ordinary, `self`-style trait you call (`CanGreet`, `CanCalculateArea`). It reads as a verb (`CanDoX`). A **provider trait**, generated by `#[cgp_component]`, is the same interface with `Self` moved to an explicit `Context` generic parameter (`Greeter`, `AreaCalculator`). It reads as a noun (`SomethingDoer`, or `…Provider` when a noun does not fit). A **provider** is a zero-sized marker struct (`GreetHello`, `RectangleArea`) that implements a provider trait. It is never instantiated and exists only as a name at the type level. **Wiring** tells a context which provider implements each component, recorded in a type-level table. An **impl-side dependency** is a `where`-clause constraint a provider needs but the consumer trait does not expose. A **component** is the whole bundle a macro generates: consumer trait, provider trait, and a `…Component` marker type that keys the wiring table. The duality is the crux. You *use* a consumer trait and *implement* a provider trait. The macro-generated blanket impls connect them, so wiring a context to a provider makes the context implement the consumer trait. When a provider trait method takes `context: &Context` where the consumer took `&self`, that is the same method with `self` renamed to `context`. **"Context" covers situations that look alike and behave differently, and this is where a reader's model of CGP most often breaks.** A **value context** *is* the data the capability operates on: the `String` in `String: CanEncode`, the `Rectangle` in `Rectangle: CanCalculateArea`. An **environmental context** exists to supply choices and capabilities rather than to be operated on: an application, a test harness, a service. It is by far the more common kind in real CGP code, and it often lacks fields entirely. `struct App;` is a complete context, because its whole job is to be a name the wiring table hangs off. Both sit in the `Self` position and both carry a wiring table, so nothing in a signature distinguishes them. Another, independent distinction describes the **component** rather than its context. A component is **self-targeted** when the capability is about the `Self` type (`CanGreet`, `HasErrorType`, every getter), and **parameter-targeted** when it is about a type parameter while `Self` only decides (`CanEncodeValue`, `CanCalculateArea`). A parameter alone does not settle it. In `CanCompute` the target is `Input`, while `Code` is a *selector* the wiring dispatches on, and a component may carry both. The pairing decides how many independent choices are available. A self-targeted component wired on a foreign value type gets one provider program-wide, while an environmental context can be defined as many times as needed. [modularity-hierarchy](references/modularity-hierarchy.md) works out which to reach for. **When you explain CGP to a user, say which arrangement the example is in.** Moving from a value context to an environmental one does not change a signature, so readers otherwise lose track of what a context is. One confusion to avoid: inside a provider, `self`/`Self` (in `#[cgp_impl]`) or the `context`/`Context` parameter (in the raw provider-trait form) always refer to the **context**, never to the provider struct. The provider struct is a pure type-level name with neither fields nor a runtime value. You cannot store state in it, and any attempt to read a "field" of a provider at runtime is a mistake. ## Reading CGP code on sight Most CGP code is readable once you recognize a handful of shapes: - `#[cgp_component(Greeter)] trait CanGreet { fn greet(&self); }` defines a component. `CanGreet` is the consumer trait you call, `Greeter` is the provider trait implementations target, and `GreeterComponent` is the wiring key. - `#[cgp_impl(new GreetHello)] #[uses(HasName)] impl Greeter { fn greet(&self) { … } }` writes a provider named `GreetHello` for the `Greeter` component. Inside, `self`/`Self` mean the *context*, and `#[uses]` lists the impl-side dependencies. It desugars to `where Self: HasName`, the form you read in older code. - `#[cgp_fn] fn rectangle_area(&self, #[implicit] width: f64, #[implicit] height: f64) -> f64 { … }` defines a single-implementation capability as a blanket-impl trait, pulling `width`/`height` from the context's fields automatically. - `delegate_components! { Person { GreeterComponent: GreetHello } }` wires the `Person` context. It says "for the `Greeter` component, `Person` uses the `GreetHello` provider." After this, `Person` implements `CanGreet`. - `check_components! { Person { GreeterComponent } }` is a compile-time assertion that the wiring is complete and all transitive dependencies are satisfied. A consumer trait can also be implemented directly on a context like any normal Rust trait (`impl CanGreet for Person { … }`). CGP traits are a superset of vanilla traits, and the macros only save boilerplate. ## Which construct to use: prefer this, not that When two constructs can express the same thing, CGP has a preferred one. Choosing wrong produces code that compiles but reads as dated or misuses an advanced tool. This table is the quick answer, so you pick the right pattern even without reading further. Each preference is a default with narrow exceptions, spelled out under [Writing providers](#writing-providers) and, with full before/after examples, in [modern-idioms](references/modern-idioms.md). The "avoid" column is not wrong. You *read* it in generated code and legacy wiring, but you do not *write* it anew. | To… | Prefer | Not (legacy / advanced / read-only) | |---|---|---| | write a provider | `#[cgp_impl]`, header `impl Trait` (omit `for Context`) | raw `#[cgp_provider]` / `#[cgp_new_provider]` | | read a field from your own context | an `#[implicit]` argument | `#[cgp_auto_getter]` / any getter trait declared just to read it | | declare a getter (field on *another* type, or a named shared capability) | `#[cgp_auto_getter]`, used sparingly | `#[cgp_getter]` (only for per-context field choice) | | require a capability | `#[uses(Trait)]` | `where Self: Trait` | | require an inner provider | `#[use_provider(P: Trait)]` | `where P: Trait` | | name an abstract type (e.g. `Error`) | `#[use_type(Trait.Type)]` + the bare alias | `: Trait` supertrait + `Self::Type` | | pass several args to `#[uses]` / `#[use_type]` | one attribute, comma-separated | repeating the same attribute | | bind several inner providers with `#[use_provider]` | one attribute per provider | a comma-separated list of pairs (it does not parse) | | add a capability supertrait | `#[extend(Trait)]` | native `pub trait …: Supertrait` | | dispatch a component per type | the `open` statement (or a namespace) | `#[derive_delegate]` + `UseDelegate` tables | | verify a context is fully wired | separate `check_components!` (or `delegate_and_check_components!` for a basic starter context) | leaving a context's wiring unchecked | | build a field/list/string/path type | `Symbol!` / `Product!` / `Sum!` / `Path!` sugar | hand-written `Cons`/`Nil`/`Chars`/`Either`/`PathCons` | Some names are gone entirely, not merely dated. Never write `#[cgp_context]`, which was removed (assemble a context with `delegate_components!` and the derives instead), or `ProvideType`, which was renamed to `TypeProvider`. One caveat carries across the whole table: a construct's *own* local associated type stays qualified as `Self::Output`. Only an *imported* abstract type is written bare via `#[use_type]`. ## The prelude and version Almost everything CGP exports comes through one import, which belongs at the top of every module that uses CGP: ```rust use cgp::prelude::*; ``` **A substantial minority of CGP's public traits and markers are *not* in the prelude, and a missing import is the likeliest reason agent-written CGP fails to compile.** The prelude carries the constructs everyday code uses. The rest are imported from the homes below, and knowing the list is faster than guessing: | Import from | What lives there | |---|---| | `cgp::core::field::traits` | `TakeField`, `FinalizeExtractResult`, `StaticString`, `AppendProduct`, `ConcatProduct`, `MapFields`, `TransformMap`, `TransformMapFields`, `MapField`, `FieldMapper` | | `cgp::core::field::impls` | the casts `CanUpcast`, `CanDowncast`, `CanDowncastFields`, `CanBuildFrom`, and the markers `IsOptional` and `IsOwned` | | `cgp::core::base::traits` | `StaticFormat` (and `cgp::core::base::types` for `Chars`, `Cons`, `Nil`, `PathCons`, `Symbol`) | | `cgp::core::component` | `DefaultImpls1`, `DefaultImpls2` | | `cgp::core::error` / `cgp::extra::error` | the error wiring keys, and the backend providers | | `cgp::extra::monad::traits` | `MonadicBind`, `ContainsValue`, `LiftValue`, `MonadicTrans` | | `cgp::extra::field::impls` | the whole optional-field layer: `HasOptionalBuilder`, `ToOptional`, `SetOptional`, `FinalizeOptional`, `CanFinalizeWithDefault`, `CanBuildWithDefault` | Memorize the casts and the optional-field layer, because both read as core vocabulary and neither is in the prelude. Also memorize the neighbouring pairs that disagree: `ConcatPath` is in the prelude while `StaticString` and `StaticFormat` are not, `DefaultNamespace` is while `DefaultImpls1`/`DefaultImpls2` are not, and every builder trait is except `TakeField`. This skill describes CGP **v0.8.0** and cargo-cgp **v0.1.0-alpha**. See [Tooling](#tooling-use-cargo-cgp-for-readable-errors-and-expansions) for checking both versions on the host and reconciling a mismatch. Inside documentation code blocks you may omit the prelude import for brevity. --- ## Components: the heart of CGP A component is the bundle `#[cgp_component]` builds from one trait, so that *using* a capability and *implementing* it become separate, swappable things. Applying it to a consumer trait: ```rust #[cgp_component(Greeter)] pub trait CanGreet { fn greet(&self); } ``` generates the items below, of which you write or call only the consumer trait. The **consumer trait** `CanGreet` is emitted unchanged, so callers write `person.greet()`. The **provider trait** is the same interface with `Self` moved to a leading `Context` parameter and `self` rewritten to `context`: ```rust pub trait Greeter: IsProviderFor { fn greet(context: &Context); } ``` The **component marker** `pub struct GreeterComponent;` is the zero-sized key into the wiring table. The **blanket impls** connect the sides. One makes any context that implements the provider trait *for itself* implement the consumer trait. The other lets a context that delegates this component (via `DelegateComponent`) inherit the provider trait from whatever provider it delegates to. You never write these blanket impls. They are the routing machinery, and it is enough to think of wiring as a table lookup. That lookup is resolved **entirely at compile time**. The table is a set of trait impls, so the compiler picks the provider during type resolution and monomorphizes the call to a direct, statically dispatched one. CGP wiring is therefore zero-cost. "Table lookup" is a useful mental model, but the generated code involves neither a runtime table nor dynamic dispatch nor a vtable. In real generated code the context parameter is named `__Context__` and the provider parameter `__Provider__`, reserved identifiers chosen so they never clash with your types. The names `Context`/`Provider` here are for readability. The attribute's argument sets the generated names. The bare `#[cgp_component(Greeter)]` form names only the provider trait. The component marker defaults to that name plus `Component` (`GreeterComponent`) and the context to `__Context__`. A key/value form with brace delimiters overrides any of them, as in `#[cgp_component { name: GreeterComponent, provider: Greeter, context: Context }]`, where only `provider` is required. One limitation to know: a **const generic parameter** on the trait is rejected, because a component's extra parameters are recorded as a tuple of *types* in `IsProviderFor`, and a const value has nowhere to live there. An associated `const` *item* on the trait is fine, and a const-generic provider struct supplies it as usual. See [macro-grammar](references/macro-grammar.md) for the full argument grammar and [components](references/components.md) for the complete expansion. **A component trait may declare as many items as any Rust trait. Group the items that one provider choice decides together.** Everything in one component is answered by one provider, so items settled by one decision belong together and items settled by different decisions do not. Most application capabilities are one decision and so one method, which is why single-method components dominate. But a method plus the associated type it produces is one decision too, which is why CGP's own `CanCompute` and `CanHandle` declare `type Output` beside their method. A getter component groups several field reads because one `UseFields` provider answers them all by name. Grouping *different* decisions costs reuse, as an entity trait does (`Shape` with `area`, `perimeter`, `scale`, `rotate`). Each provider then carries the union of every method's dependencies, a higher-order provider must forward the methods it does not change, and a context that needs part of the surface must still answer all of it with placeholder types and `unimplemented!()` bodies. A consumer trait named after a noun rather than a verb is the usual sign. When you write or review one, check that a second context could plausibly reuse one of its providers *whole*. If not, implement the trait directly on the concrete context and skip the machinery. [components](references/components.md) carries the multi-item cases, the costs, and the procedure for splitting a trait that has grown past one decision. ### `IsProviderFor` and error messages `IsProviderFor` is an empty marker trait that rides as a supertrait on every provider trait. Its only purpose is good error messages. A provider lists its dependencies in a `where` clause, and the macros implement `IsProviderFor` for the provider under the *same* bounds. So when a dependency is unmet, the compiler can name the missing bound instead of vaguely saying "the trait is not implemented." When you see an error that some provider does not implement `IsProviderFor<…>`, read it as "the provider trait is not implemented, because the named dependency is missing." You never write `IsProviderFor` yourself. The provider macros generate it. ### Writing providers A provider can be written at several levels of sugar over the same machinery. **Prefer `#[cgp_impl]`.** It lets you write the provider in consumer-style syntax, keeping `self`, `Self`, and the consumer method signatures, and the macro rewrites it into the provider-trait shape: ```rust #[cgp_impl(new GreetHello)] #[uses(HasName)] impl Greeter { fn greet(&self) { println!("Hello, {}!", self.name()); } } ``` The provider name goes in the attribute argument, and a leading `new` keyword also declares the `struct GreetHello;`. The dependency is declared with [`#[uses]`](#uses-extend-extend_where) rather than a hand-written `where Self: HasName` clause. `#[uses]` is the preferred form and desugars to exactly that bound. **Prefer the unqualified `impl Greeter` form and let the macro insert the context parameter.** Omitting `for Context` makes a provider read like an ordinary trait impl. Write the explicit `impl Greeter for Context` only when you must bound or name the context readably, for example for a lifetime or HRTB the sugar cannot express. It must then be declared in the impl generics. Remember that `self`/`Self` here mean the context. `#[cgp_impl]` desugars to: ```rust #[cgp_new_provider] impl Greeter for GreetHello where Context: HasName, { fn greet(context: &Context) { println!("Hello, {}!", context.name()); } } ``` You mostly *read* the lower forms rather than write them. `#[cgp_provider]` is applied to a provider-trait impl written directly on an existing provider struct. It passes the impl through and generates the matching `IsProviderFor` impl from the same `where` clause. `#[cgp_new_provider]` does the same but also declares the provider struct. A generic provider gets a `PhantomData` field over its parameters, such as `pub struct Multiply(PhantomData);`. The attribute argument can override the component name, which otherwise defaults to the provider trait's name plus `Component`. One special form, `#[cgp_impl(Self)]`, bypasses the provider rewrite entirely and emits the block as a *direct* consumer-trait impl on the concrete context. The `for Context` clause is then required. This is useful when you want to implement a consumer trait by hand while still applying companion attributes such as `#[use_provider]`. **Strongly prefer the modern, vanilla-looking idioms when you write CGP, and reach for the explicit forms only when a construct cannot express the case.** Each idiom below trades a piece of visible machinery for syntax that reads like ordinary Rust: - **Write providers with `#[cgp_impl]`**, not `#[cgp_provider]` or `#[cgp_new_provider]`, and omit `for Context` so the header reads `impl Greeter`. - **Declare dependencies with attributes, not hand-written bounds.** Capability dependencies go in [`#[uses(...)]`](references/functions-and-getters.md), and inner-provider dependencies in [`#[use_provider(...)]`](references/higher-order-providers.md), instead of raw `Self:` / `Provider: …` `where` clauses. When one of these attributes, or [`#[use_type]`](references/abstract-types.md), carries several arguments, put them all in one attribute separated by commas (`#[uses(A, B)]`, `#[use_type(T.X, U.Y)]`) rather than stacking the same attribute repeatedly. One attribute reads as a single dependency list. - **Read context fields with [`#[implicit]`](references/functions-and-getters.md) arguments** rather than a getter trait. This is the default for *any* field a provider reads from its own context, including one that several providers each read. An implicit argument reads only from `self` and takes a plain `&T` by reference without cloning. Use `#[cgp_auto_getter]` sparingly, only where an implicit argument cannot reach: a getter for a field on *another* type, which takes that type as the getter's first argument in place of `self` (`fn foo_bar(foo: &Self::Foo) -> &Self::Bar`) or is required as a `where` bound on it (`Request: HasBasicAuthHeader`); an accessor other code depends on as a named capability; or a getter carrying an associated type inferred from the field. Reserve `#[cgp_getter]` for the advanced case of choosing the source field per context. - **Add non-type capability supertraits with [`#[extend(...)]`](references/functions-and-getters.md)** rather than native `: Supertrait` syntax, which reads as OOP-style inheritance rather than a capability import. - **Import abstract types with [`#[use_type]`](references/abstract-types.md)**, writing the bare alias (`Scalar`, `Error`) instead of a hand-written `: HasScalarType` supertrait and a qualified `Self::Scalar` at every use. This holds even in `#[cgp_component]` definitions: prefer `#[use_type(HasErrorType.Error)]` over `: HasErrorType` + `Self::Error`. When a provider *pins* an abstract type to a concrete one (a `where Self: HasErrorType` clause), use the equality form `#[use_type(HasErrorType.{Error = AppError})]`, which emits the same bound. The equality form is a `#[cgp_impl]`/`#[cgp_fn]` tool and is rejected on `#[cgp_component]`. [abstract-types](references/abstract-types.md) covers how the right-hand side of `=` is itself substituted, so one abstract type can be pinned in terms of another. - **Dispatch a generic-parameter component with the `open` statement or a namespace**, skipping `#[derive_delegate]`/`UseDelegate` when defining a new component. The explicit forms remain correct, and you *read* them in generated code and desugaring. The exceptions that still need them are narrow. An associated-type-equality bound on a trait you would never `#[use_type]` from (`Iterator`, `From`) stays an explicit `where` clause. A lifetime or HRTB forces a named context. A **local** associated type such as `Self::Output` stays qualified because it is the trait's own type, not an imported abstract one. An equality bound on an **abstract-type** trait is not an exception: `#[use_type(HasErrorType.{Error = AppError})]` replaces the hand-written `where Self: HasErrorType`. For the full legacy-to-modern before/after mapping of each idiom, see [modern-idioms](references/modern-idioms.md), the reference to load whenever you read or modernize existing CGP. The provider's `where` clause is where **impl-side dependencies** live, whether you write it by hand or let `#[uses]` generate it. `GreetHello` requires `Self: HasName`, but `CanGreet` does not expose that bound, so a caller bounding on `CanGreet` never sees `HasName`. The wiring satisfies each dependency by resolving it through the same context. A consumer trait is still an ordinary trait. When you do not need multiple implementations, write `impl CanGreet for Person { … }` directly and skip the provider machinery. --- ## Wiring: connecting a context to providers Wiring records, on a context type, which provider supplies each component. The underlying mechanism is the `DelegateComponent` trait, a type-level table whose key is the `…Component` marker and whose `Delegate` associated type is the chosen provider. You almost always write it through `delegate_components!`: ```rust #[derive(HasField)] pub struct Person { pub name: String, } delegate_components! { Person { GreeterComponent: GreetHello, } } ``` After this, `Person` implements `CanGreet`, and `person.greet()` resolves through the table to `GreetHello`. Swapping the table entry is the only change needed to swap behavior. The macro has a few shorthands. An **array key** maps several components to one provider: `[FooComponent, BarComponent]: FooBarProvider`. A leading **`new`** keyword (`delegate_components! { new MyComponents { … } }`) also defines `struct MyComponents;`. This is how you build an **aggregate provider**, a zero-sized provider that holds a table dispatching each component to a sub-provider, so other contexts can delegate a whole group of components to it as one reusable unit. A leading **generic list** (`delegate_components! { MyContext { … } }`) wires a whole family of contexts at once. Further **operators** stand where the `:` does, and you will meet them when reading real wiring. `Key -> OtherTable` forwards the key to *that table's* own entry for the same key instead of naming a provider. `Key => @path` redirects the lookup along a type-level path, and the `open` statement below is its sugared special case. Those operators, the `@`-path key forms, and the `namespace` and `for` statements belong to one shared body grammar that `cgp_namespace!` and `delegate_and_check_components!` reuse in full. [wiring](references/wiring.md) and [macro-grammar](references/macro-grammar.md) carry it, and all of the forms combine inside a single block. The target of `delegate_components!` is therefore not always a context. It is either a concrete context (as `Person` is above) or an aggregate provider (as `MyComponents` is). This distinction governs checking. An aggregate provider is dispatched *to* by contexts and is never its own context, so it must be wired with plain `delegate_components!` and never `delegate_and_check_components!`. The next section explains why. To understand what wiring *does*, picture the explicit version. `delegate_components!` is equivalent to implementing the consumer trait by hand and forwarding to the provider: `impl CanGreet for Person { fn greet(&self) { >::greet(self) } }`. The macro generates that plumbing, plus the `IsProviderFor` propagation, for you. ### `UseContext` `UseContext` is a provider that implements a provider trait by routing back through the context's *own* consumer-trait impl, the dual of the consumer blanket impl. Wiring a component to `UseContext` means "use whatever this context already does for this trait," which is mainly useful as the default inner provider of a higher-order provider (below). Delegating a component directly to `UseContext` when the context's only implementation of that component *is* that delegation creates a circular dependency and fails to compile. ### Dispatching a generic-parameter component per type with `open` When a component is generic over a type parameter, you often want a different provider per value of that parameter. The modern, preferred way is the **`open` statement** inside `delegate_components!`. Given a component `CanCalculateArea` (provider `AreaCalculator`), a context dispatches per shape like this: ```rust delegate_components! { MyApp { open AreaCalculatorComponent; @AreaCalculatorComponent.Rectangle: RectangleArea, @AreaCalculatorComponent.Circle: CircleArea, } } ``` The `open … ;` header opens one or more components for per-value wiring and **must lead** the block. It comes before any plain `Component: Provider` mappings, or the macro fails to parse. The braces are optional when opening a single component (`open AreaCalculatorComponent;`), and the braced list `open { A, B };` opens several at once. Each `@Component.Key: Provider` entry then assigns a provider for one value of the dispatch parameter. Grouping forms share one provider across several values, and they are **not** interchangeable. A braced group holds whole path *tails* and ends the path (`@AreaCalculatorComponent.{u32, u64, bool}: SomeProvider`). A bracketed group holds alternatives for *one segment* and may be followed by more path (`@app.[FooComponent, BarComponent].[u64, String]: P` writes every combination). A key may also carry generics (`@SomeComponent.<'a, T> &'a T: SomeProvider`). `open` works through the `RedirectLookup` impl that every `#[cgp_component]` already generates, so it does not need an extra attribute on the component. It does not combine with a joined namespace (`#[prefix(...)]`), which is the full namespace feature. **Legacy form (read but don't write):** older code dispatches the same way by wrapping a nested table in the `UseDelegate` provider, as in `AreaCalculatorComponent: UseDelegate`, generated by a `#[derive_delegate(UseDelegate)]` attribute on the component. This still works and is common in existing code, but it is slated for deprecation, so prefer `open` for new code. Some CGP-shipped components (the error and handler families) are still *defined* with `#[derive_delegate]` in the library, so you will see `UseDelegate` tables wiring them. --- ## Checking: verifying wiring at compile time CGP wiring is **lazy**. Defining a `delegate_components!` entry does not itself check that the provider's transitive dependencies are satisfied. A missing dependency therefore surfaces only when the consumer trait is finally used, often as a confusing error. To catch it early and clearly, assert the wiring with a check: ```rust check_components! { Person { GreeterComponent, } } ``` This generates a check trait whose supertrait is `CanUseComponent` for `Person`. If `Person` cannot use the component, the compiler reports the missing dependency at this site, walking through `IsProviderFor` so the real cause (such as a missing `HasField`) is named rather than hidden. For a component with generic parameters, list the parameter after the component (`GreeterComponent: Rectangle`), group multiple parameters as a tuple (`(Rectangle, f64)`), and use array syntax to check several at once. `delegate_and_check_components!` fuses wiring and checking in one step, so every delegation is verified the moment it is written: ```rust delegate_and_check_components! { Person { GreeterComponent: GreetHello, } } ``` Its check trait is named `__CanUse{Context}` (versus `__Check{Context}` for `check_components!`), so both macros can appear once per module without clashing. Override the name with `#[check_trait(Name)]`. When the delegated component has generic parameters, add `#[check_params(...)]` on the entry. Skip a single entry's check with `#[skip_check]`. **This fused macro is a convenience for basic wiring and for getting started, not the default for advanced code.** It exists so a newcomer cannot forget to write a separate `check_components!` and then hit confusing lazy-wiring errors, and it derives a check only for the plain `Component: Provider` delegation form. It cannot easily derive checks for advanced mappings: generic-parameter dispatch (the `open` statement and `@`-path keys), namespaces, or per-layer higher-order checks. **In larger, more advanced codebases, keep `delegate_components!` and `check_components!` separate.** That gives full control over what is checked: `#[check_providers(...)]` per provider layer, concrete parameters for generic keys, and checks over opened or namespaced wiring. The one non-negotiable is that a context's wiring *is* checked somehow. Which macro you use scales with the wiring's complexity. One case makes `delegate_and_check_components!` wrong, not just unnecessary: an **aggregate provider** (the `new MyComponents { … }` table above). That target is a provider other contexts delegate to, not a context itself. So the check's `CanUseComponent` assertion asks whether the bundle can use each component *as a context*, a role it never plays, and the answer is uninformative either way. It passes vacuously when the bundled providers need nothing from their context, and it fails blaming the bundle when any of them needs a field or a type the real context would have supplied. Wire an aggregate provider with plain `delegate_components!`. It is verified indirectly when a real context that delegates to it is checked, or directly with a `#[check_providers(...)]` block that asserts `IsProviderFor` on it. Not every unsatisfied bound is a CGP component. Some are ordinary or blanket traits that `check_components!` cannot verify, and those must be satisfied by ordinary Rust means. For a nested [higher-order provider](references/higher-order-providers.md), checking the context tells you a layer is broken but not which one. The `#[check_providers(...)]` attribute on a `check_components!` table changes the assertion from `CanUseComponent` on the context to `IsProviderFor` on each named provider. A dependency missing only from the outer wrapper then errors on its line alone, while one missing from the inner provider errors on both, which pinpoints the layer. See [checking](references/checking.md) for the debugging playbook. --- ## Functions and getters: the ergonomic surface Most basic CGP reads and writes values from the context, and the constructs here make that look like plain Rust. ### `HasField` and `#[derive(HasField)]` `HasField` is tag-keyed field access. The `Tag` is a type-level name: `Symbol!("width")` for a named field or `Index<0>` for a tuple field. `#[derive(HasField)]` generates one impl per field: ```rust #[derive(HasField)] pub struct Rectangle { pub width: f64, pub height: f64, } // generates HasField and HasField ``` Field values are read with `self.get_field(PhantomData::)`. The `PhantomData` carries the tag so type inference knows which field is meant. ### `#[cgp_fn]` and `#[implicit]` arguments `#[cgp_fn]` turns one function into a single-implementation blanket-impl trait, the simplest entry point to CGP. Arguments marked `#[implicit]` are removed from the signature and pulled from context fields via `HasField`: ```rust #[cgp_fn] fn rectangle_area(&self, #[implicit] width: f64, #[implicit] height: f64) -> f64 { width * height } ``` This generates a `RectangleArea` trait (named from the function in PascalCase, or `#[cgp_fn(MyName)]` to override) with a blanket impl for any context that has `width: f64` and `height: f64` fields. Implicit arguments get `.clone()` added for owned values and `.as_str()` for `&str`. Generic parameters on the function move to the trait and impl, and the `where` clause becomes impl-side dependencies on the impl only. Generic *method* parameters are intentionally unsupported. Prefer implicit arguments for basic code, because they make CGP look like ordinary functions. ### `#[uses]`, `#[extend]`, `#[extend_where]` `#[uses(TraitA, TraitB)]` (on `#[cgp_fn]` or `#[cgp_impl]`) imports `Self` trait bounds, read like a `use` statement. The simple `Trait` form is idiomatic, but any `where`-clause bound is accepted, including associated-type equality (`HasErrorType`). For abstract-type pins, prefer `#[use_type]`'s equality form: ```rust #[cgp_fn] #[uses(RectangleArea)] fn scaled_rectangle_area(&self, #[implicit] scale_factor: f64) -> f64 { self.rectangle_area() * scale_factor * scale_factor } ``` `#[extend(Trait)]` adds *supertrait* bounds to the generated trait. It is the only way to add supertraits in `#[cgp_fn]`, whose `where` clauses are impl-side dependencies, and the **preferred** way to add a *non-type capability* supertrait on `#[cgp_component]` too. `#[extend(HasName)]` reads as importing a capability, whereas the native `pub trait CanGreet: HasName` syntax reads as OOP-style inheritance from a parent class, which a CGP supertrait is not. When the supertrait is an abstract-type component whose associated type the signatures name, prefer `#[use_type]` instead. It adds the supertrait *and* rewrites the type, and it is the recommended form for abstract-type components. `#[extend_where(Bound)]` adds `where` clauses to the generated trait definition (`#[cgp_fn]` only), and accepts arbitrary predicates including associated-type equality, unlike `#[uses]`/`#[extend]`. Another `#[cgp_fn]`-only attribute, `#[impl_generics(Param: Bound)]`, adds a bounded generic parameter to the generated *impl* alone, not the trait. This is how a `#[cgp_fn]` body borrows a generic value it does not want to expose as a trait parameter, for example `#[impl_generics(Name: Display)]` over an `#[implicit] name: &Name`. ### Getters: `#[cgp_auto_getter]`, `#[cgp_getter]`, `UseField` An `#[implicit]` argument (above) is the default way to read a context field, so use a getter trait *sparingly*, only where an implicit argument cannot reach. Because an implicit argument reads only from the provider's own `self` (and takes a plain `&T` by reference without a clone), it covers every same-context read, even a field several providers each consume. A getter trait earns its keep only in the cases an implicit argument cannot handle: a field that lives on a type *other* than the provider's context, an accessor other code depends on as a *named* capability through `#[uses(HasName)]` or a supertrait, and a getter carrying an *associated type inferred from the field*, so the type stays abstract for callers. For the field on another type, a getter reaches it either by taking that type as its first argument instead of `self` (`fn foo_bar(foo: &Self::Foo) -> &Self::Bar`, called as `App::foo_bar(&foo)`) or by being required as a `where` bound on it (`Request: HasBasicAuthHeader`), since either way it lacks a `self` field to read. `#[cgp_auto_getter]` generates a blanket getter impl over `HasField`, with the field name taken from the method name. It is the getter form to prefer for those cases: ```rust #[cgp_auto_getter] pub trait HasName { fn name(&self) -> &str; } // blanket impl for any context with a `name` field; &str/&String shorthands handled ``` A single-getter trait may instead declare a local associated type used as the return type, inferred from the field: `trait HasName { type Name; fn name(&self) -> &Self::Name; }`. `#[cgp_getter]` is an **advanced** tool, reserved for when a context needs full control over which field a getter reads from. Most getters should use `#[cgp_auto_getter]` or an implicit argument instead. It is like `#[cgp_component]` but also provides a `UseField` blanket impl, so the getter's source field can be chosen by *wiring* rather than fixed to the method name. The `UseField` provider implements a getter by reading the field named `Tag`, which may differ from the method name: ```rust delegate_components! { Person { NameGetterComponent: UseField, } } // Person::name() now returns the `first_name` field ``` `UseFieldRef` is the `AsRef`/`AsMut`-based variant. Any getter can also be implemented by hand. The macros only save boilerplate. --- ## Abstract types CGP abstracts over types with associated types in components. `#[cgp_type]` is the dedicated macro, so use it instead of `#[cgp_component]` for an abstract-type trait: ```rust #[cgp_type] pub trait HasNameType { type Name; } ``` This defaults the provider name to the type name plus `TypeProvider` (here `NameTypeProvider`, marker `NameTypeProviderComponent`) and also generates a `UseType` blanket impl. A context fixes the type by wiring the component to `UseType`: ```rust delegate_components! { Person { NameTypeProviderComponent: UseType, } } // or directly: impl HasNameType for Person { type Name = String; } ``` The direct impl is just as valid, and it shows that abstract types are ordinary associated-type traits. The `#[use_type(HasScalarType.Scalar)]` attribute is the recommended way to *use* an abstract type inside `#[cgp_fn]`, `#[cgp_impl]`, or `#[cgp_component]`. It rewrites bare `Scalar` to the fully qualified `::Scalar` everywhere and adds the supertrait or `where` bound, removing `Self::` boilerplate and ambiguity. CGP's built-in abstract-type component is `HasType` (provider `TypeProvider`). --- ## Higher-order providers A **higher-order provider** takes another provider as a generic parameter and constrains it with a provider-trait bound, so its inner behavior is chosen by wiring rather than fixed: ```rust #[cgp_impl(new ScaledAreaCalculator)] #[use_provider(InnerCalculator: AreaCalculator)] impl AreaCalculator { fn area(&self, #[implicit] scale_factor: f64) -> f64 { let base_area = InnerCalculator::area(self); base_area * scale_factor * scale_factor } } ``` `#[use_provider(InnerCalculator: AreaCalculator)]` completes the inner provider's bound by adding the `Self` parameter for you (you write `: AreaCalculator`, and it means `AreaCalculator`) and moves it into the `where` clause. That is the *only* thing the attribute does. Inside the body you still call the provider explicitly with the associated-function form `InnerCalculator::area(self)`. The attribute does not rewrite the call site. A context then chooses the inner provider when wiring, for example `AreaCalculatorComponent: ScaledAreaCalculator`. A higher-order provider often defaults its inner parameter to `UseContext` (`pub struct IterSumArea(PhantomData);`), so that when an inner provider is not named, the inner step falls back to the context's own wiring. Not every provider with a generic parameter is higher-order. A provider like `GetName` that uses `Tag` only as a `HasField` key, without a provider-trait bound, is not. When a component itself is generic (`#[cgp_component(AreaCalculator)] trait CanCalculateArea`), the provider trait appends the parameters after the context (`AreaCalculator`), `IsProviderFor` groups them into its `Params` tuple, and lifetimes are lifted into the `Life<'a>` type. Such a component is most useful for **cross-context dependencies**. When the main target is a generic parameter (`CanCalculateArea: HasScalarType`), individual shape types need not implement shared capabilities. The common context supplies the shared abstract type, value-level injection (a global scale factor via a getter), and lazy per-context provider binding, so two apps can wire the same shape to different providers. --- ## Error handling CGP makes the error type abstract, so generic code can fail without naming a concrete error. `HasErrorType` (an abstract-type component, `type Error: Debug`) gives a context one shared error type. `CanRaiseError` constructs it from a concrete source error (`Context::raise_error(source)`), and `CanWrapError` attaches detail. Both build on `HasErrorType` and are associated-function (without `self`) components that dispatch per source or detail type. An error-aware trait imports the error type with `#[use_type(HasErrorType.Error)]`, so it names the error as the bare `Error` instead of writing `: HasErrorType` and `Self::Error` by hand: ```rust #[cgp_component(Loader)] #[use_type(HasErrorType.Error)] pub trait CanLoad { fn load(&self, path: &str) -> Result; } #[cgp_impl(new LoadOrFail)] #[uses(CanRaiseError)] #[use_type(HasErrorType.Error)] impl Loader { fn load(&self, path: &str) -> Result { if path.is_empty() { return Err(Self::raise_error("empty path".to_owned())); } Ok(format!("contents of {path}")) } } ``` A context wires its error type and the raise/wrap behavior. The backend providers plug in per source type, modern-style with `open`. They are `RaiseFrom` (convert via `From`), `ReturnError`, `RaiseInfallible`, `PanicOnError`, `DebugError`/`DisplayError` (format into a `String` and forward), and `DiscardDetail`: ```rust delegate_components! { App { open ErrorRaiserComponent; ErrorTypeProviderComponent: UseType, @ErrorRaiserComponent.String: RaiseFrom, @ErrorRaiserComponent.ParseError: DebugError, } } ``` **Imports:** `HasErrorType`, `CanRaiseError`, and `CanWrapError` come from the prelude. The wiring keys (`ErrorTypeProviderComponent`, `ErrorRaiserComponent`, `ErrorWrapperComponent`) live under `cgp::core::error`, and the backend providers (`RaiseFrom`, `DebugError`, …) under `cgp::extra::error`, so import the specific names you wire. Standalone backends (`cgp-error-anyhow`, `cgp-error-eyre`, `cgp-error-std`) provide ready error types. --- ## Handlers: the computation family CGP models computation as a family of components along the axes of synchronous versus async, infallible versus fallible, and input-taking versus input-free: - **`Computer` / `CanCompute`** is a synchronous, infallible transform `compute(&self, PhantomData, input) -> Output`. By-reference (`ComputerRef`) and async (`AsyncComputer`) variants exist. - **`TryComputer` / `CanTryCompute`** is the fallible computer. - **`Producer` / `CanProduce`** is input-free production (only a context and a `Code` tag). - **`Handler` / `CanHandle`** is the general **async, fallible, error-aware** computation, and the workhorse for I/O and pipelines. It supertraits `HasErrorType`. - **`CanRun` / `CanSendRun`** are task runners. Any CGP trait with async methods, whether a handler, a runner, or one you define, declares them under the `#[async_trait]` attribute. The attribute rewrites each `async fn` to `-> impl Future`, the lint-clean, allocation-free form. The generated future does not carry a `Send` bound, so spawning it on a work-stealing executor needs the `Send`-recovery pattern in [handlers](references/handlers.md). `#[cgp_computer]` and `#[cgp_producer]` define a `Computer`/`Producer` provider from a function. Providers compose through combinators. `PipeHandlers` chains handlers left to right, `ComposeHandlers` nests them, `ReturnInput` passes input through, and the `Promote*` adapters lift a simpler handler (such as a sync `Computer`) into a more capable one (an async `Handler`). For example, a context wires a pipeline of field-reading computers: ```rust delegate_components! { MyContext { ComputerComponent: PipeHandlers, Add, Multiply, ]>, } } // context.compute(PhantomData::<()>, 5) runs ((5*foo)+bar)*baz ``` Dispatch routes an extensible-data input to per-variant handlers. `#[cgp_auto_dispatch]` generates a handler from a trait, and the combinators `MatchWithHandlers`, `MatchWithValueHandlers`, and `ExtractFieldAndHandle` match an enum's variants to sub-handlers, proving exhaustiveness without a wildcard. Monadic handlers (`PipeMonadic`, `BindOk`, `BindErr`, the identity/ok/err monads) compose handlers through a monad. The handler family is broad, so read [handlers](references/handlers.md) for the full set, including `Send`-bound recovery for async trait methods. --- ## Extensible data CGP can build and read structs and enums generically, by their named fields and variants. The `#[derive(HasFields)]` derive exposes a type's whole field list. `#[derive(CgpData)]`, and the record- or variant-specific `CgpRecord`/`CgpVariant`, derive the full extensible-data machinery: ```rust #[derive(CgpData)] pub struct Person { pub first_name: String, pub last_name: String, } ``` Records are built field by field through the builder family (`HasBuilder`, `BuildField`). This **extensible builder pattern** assembles a context from independent per-field outputs. Variants are constructed with `FromVariant` and deconstructed with the `ExtractField` extractor family, and the **extensible visitor pattern** handles each variant. The type-level lists underneath are the product list (`Product![A, B, C]` over `Cons`/`Nil`) for records and the sum list (`Sum![A, B]` over `Either`/`Void`) for variants. Structural **casts** convert between shapes: `CanUpcast` widens a smaller enum into a larger one, `CanDowncast` narrows, and `CanBuildFrom` rebuilds a record from a superset. Dispatching extensible-data inputs to handlers uses the dispatch combinators above. --- ## Namespaces Namespaces are reusable, inheritable wiring tables (a preset mechanism) that keep top-level wiring short as component counts grow. `cgp_namespace! { new MyNs: ParentNs { … } }` defines a namespace, optionally inheriting a parent after the colon. A context then **joins** it inside `delegate_components!` with a `namespace MyNs;` statement. After that, every lookup the context does not wire directly forwards through the namespace, so any direct entry overrides just that key. A component **registers into** a namespace with the `#[prefix(@path in MyNs)]` attribute on its `#[cgp_component]` trait. A `#[cgp_impl]` provider registers as a per-type default with `#[default_impl(T in DefaultImpls1)]`, which a context pulls in with a `for in Table { … }` loop. The underlying mechanism is the `RedirectLookup` provider, which re-routes a component lookup along a type-level `Path!`. The `open` statement above is a lightweight special case of it. `DefaultNamespace` resolves a default provider when a context does not override one. Read [namespaces](references/namespaces.md) for the preset and inheritance syntax. --- ## Type-level primitives: a decoder ring CGP encodes lists, strings, and numbers as types. You mostly use the sugared macros and only need to *recognize* the expanded forms in errors: - **`Symbol!("name")`** is a type-level string (field-name tag). It expands to `Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>`. The leading length works around missing const-generics. - **`Product![A, B, C]`** is a type-level list. It expands to `Cons>>`. `product![…]` is the value-level form. Used for field lists and handler pipelines. - **`Sum![A, B]`** is a type-level sum (the dual of `Product!`), over the `Either`/`Void` list. Used for enum variant lists. - **`Index`** is a type-level natural number, and tags tuple-struct fields. - **`Field`** is a value paired with its type-level name tag. - **`Path!`** / `PathCons` is a type-level path, used by namespaces and `RedirectLookup`. - **`Life<'a>`** is a lifetime lifted into a type, used when a component has lifetime parameters. - **`MRef`** is an owned-or-borrowed value. Prefer the sugar (`Symbol!`, `Product!`) and the readable names (`Cons`/`Nil`) in anything you write. --- ## Sub-skills: load the one that owns your task The primer gave you the shape of every construct. Each sub-skill below is the ground truth for one area: the exact grammar, the full expansion, the corner cases, and worked examples. **Loading the relevant sub-skill is not optional polish. It is the step that turns a plausible guess into correct code.** Every entry names what it adds beyond this primer *and* what you would be guessing at without it, so you can see the risk of skipping it. Load a sub-skill whenever your task touches its area, whether reading it, writing it, reviewing it, or debugging an error that mentions it, and re-load it when you move into an unfamiliar corner. When a task spans several areas, load each one. They cross-link, and following those links is expected. Some sub-skills are cross-cutting rather than construct-specific, and one applies to almost every task. Start with **[references/macro-grammar.md](references/macro-grammar.md)** for any task that writes, edits, or debugs CGP syntax. It is the single reference for the formal grammar of every macro, the invariant each expansion preserves, and a decoder for the compiler errors CGP produces. *Without it* you are guessing which attribute forms parse, what a macro emits, and what an `IsProviderFor` or `DelegateComponent` error is telling you. Reach for **[references/modern-idioms.md](references/modern-idioms.md)** whenever you read or modernize existing CGP. It maps every legacy, explicit form to the modern idiom you should prefer, both to write vanilla-looking code and to decode the inside-out provider impls, hand-written `where` bounds, `Self::Type` paths, and `UseDelegate` tables you meet in older code. *Without it* you will either propagate outdated syntax or fail to recognize that legacy code and modern code mean the same thing. The remaining sub-skills each own one construct family: - **[references/components.md](references/components.md)** covers `#[cgp_component]` and the full expansion (consumer/provider traits, the blanket impls, the `…Component` marker), why `IsProviderFor` exists, the provider-writing macros (`#[cgp_impl]`, `#[cgp_provider]`, `#[cgp_new_provider]`), and how many methods a component should carry, with the costs a monolithic entity trait pays and how to split one. *Without it* you will misjudge what `self`/`Self` mean inside a provider, how the blanket impls route a call, and how coarse a component can get before its providers stop being reusable. Load it before writing any component or provider. - **[references/wiring.md](references/wiring.md)** covers `DelegateComponent`, every `delegate_components!` form (arrays, `new`, generic tables), `open` per-type dispatch, direct consumer-trait impls, `UseContext` and its circular-dependency trap, the legacy `UseDelegate` tables, and the other providers you see in tables (`WithProvider` and its `WithField`/`WithType`/`WithContext` aliases, `UseDefault`). *Without it* you will not know when a hand-written impl collides with the table, why `UseContext` overflows, or what a `WithField<…>` entry means. Load it before wiring any context. - **[references/checking.md](references/checking.md)** covers why wiring is lazy, how check traits and `CanUseComponent` force readable errors, every `check_components!` / `delegate_and_check_components!` option (`#[check_trait]`, `#[check_providers]`, `#[check_params]`, `#[skip_check]`), and a debugging playbook. *Without it* you cannot localize a broken wiring or read the error it throws. Load it whenever a wiring fails to compile. - **[references/error-extraction.md](references/error-extraction.md)** is the **fallback for when `cargo-cgp` is not available, or leaves an error largely unrewritten**. See [Tooling](#tooling-use-cargo-cgp-for-readable-errors-and-expansions) first: `cargo-cgp`'s `[CGP-Exxx]` headline and root-cause tree already are the compact summary this sub-skill produces, so reach for the sub-skill only when the tool is absent or passes the error through. It covers how to reduce a long raw CGP compile error to a compact, root-cause-first summary, the hidden-versus-surfaced distinction that decides whether the root cause is even present in the output, how to confirm a suspected cause by grepping for one signature line, and how to delegate the reading to a sub-agent so a wall of generated-type errors does not consume your context. *Without it* you will read a cascade inline, chase a cause a hidden error does not contain, or hand back raw output instead of the few facts that matter. - **[references/functions-and-getters.md](references/functions-and-getters.md)** covers `HasField`/`#[derive(HasField)]`, `#[cgp_fn]`, `#[implicit]` and its access rules, `#[uses]`/`#[extend]`/`#[extend_where]`/`#[impl_generics]`, the getters `#[cgp_auto_getter]`/`#[cgp_getter]`/`UseField`/`WithField`, and `ChainGetters` for nested-context fields. *Without it* you will reach for a getter trait where an implicit argument is idiomatic, or misapply the `.clone()`/`.as_str()`/`&mut` field-access rules. Load it for the ergonomic day-to-day surface. - **[references/abstract-types.md](references/abstract-types.md)** covers `#[cgp_type]`, the built-in `HasType`/`TypeProvider`, wiring with `UseType` (and `UseDelegatedType` for table-chosen types), importing types with the `#[use_type]` attribute (distinct from the `UseType` provider), and the `WithType`/`WithDelegatedType` adapters. *Without it* you will confuse the provider and the attribute and write `Self::` paths by hand. Load it for any associated-type abstraction. - **[references/higher-order-providers.md](references/higher-order-providers.md)** covers providers parameterized by other providers, the stray `` on the inner bound, `#[use_provider]`, `UseContext` defaults, generic-parameter components, and cross-context dependencies. *Without it* you will call the inner provider as a method instead of `Provider::method(self)` and misplace the context slot. Load it before composing providers. - **[references/error-handling.md](references/error-handling.md)** covers `HasErrorType`, `CanRaiseError`/`CanWrapError`, the backend providers (`RaiseFrom`, `DebugError`, …), and, critically, which names come from the prelude versus `cgp::core::error` / `cgp::extra::error`. *Without it* you will fail to import the wiring keys and backends. Load it for any fallible CGP code. - **[references/handlers.md](references/handlers.md)** covers the `Computer`/`TryComputer`/`Producer`/`Handler`/runner family across its axes, `#[cgp_computer]`/`#[cgp_producer]`/`#[cgp_auto_dispatch]`, the combinators (`PipeHandlers`, `Promote*`, dispatch matchers), monadic handlers, the `HasRuntime`/`HasRuntimeType` runtime components, and the `Send`-recovery pattern. *Without it* you will pick the wrong family member or miswire a pipeline. Load it for computation and I/O pipelines. - **[references/extensible-data.md](references/extensible-data.md)** covers the `CgpData`/`CgpRecord`/`CgpVariant` derives, the builder and extractor families (with the optional/defaulted-field extension), `Product!`/`Sum!` lists and their `AppendProduct`/`ConcatProduct`/`MapFields` algebra, structural casts (`CanUpcast`/`CanDowncast`/`CanBuildFrom`), and the builder/visitor patterns. *Without it* you will miss the compile-time exhaustiveness guarantees and the single-payload variant rule. Load it for generic struct/enum manipulation. - **[references/namespaces.md](references/namespaces.md)** covers `cgp_namespace!`, the `namespace`/`for … in` statements that join a namespace, the `#[prefix]`/`#[default_impl]` attributes that register into one, `RedirectLookup`, `Path!`, and the `DefaultNamespace` family. *Without it* you cannot read or write preset/inheritance wiring. Load it whenever wiring is grouped or inherited. - **[references/type-level-primitives.md](references/type-level-primitives.md)** covers `Symbol!`/`Chars`, `Product!`/`Cons`/`Nil`, `Sum!`/`Either`/`Void`, `Index`, `Field`, `Path!`/`PathCons`, `Life`, `MRef`, and the `StaticFormat` recovery traits. *Without it* you cannot decode the long nested types in error messages and expansions. Load it as the decoder ring. - **[references/modularity-hierarchy.md](references/modularity-hierarchy.md)** covers the tiered hierarchy from a plain blanket trait to per-provider wiring, and which coherence rule each tier escapes. *Without it* you will reach for more CGP machinery than a problem needs. Load it when deciding *how much* CGP to apply. ### Exhaustive online reference For the exact macro expansion of any construct, every accepted syntax form, corner cases, or the implementing source, consult the online knowledge base at **https://github.com/contextgeneric/cgp-knowledge-base**. CGP's own section is [`cgp/`](https://github.com/contextgeneric/cgp-knowledge-base/tree/main/cgp), whose `reference/`, `concepts/`, `guides/`, and `errors/` directories are the authoritative, exhaustive record, and the worked [`examples/`](https://github.com/contextgeneric/cgp-knowledge-base/tree/main/examples) sit at the base's top level beside it. The base also documents `cargo-cgp`, under [`cargo-cgp/`](https://github.com/contextgeneric/cgp-knowledge-base/tree/main/cargo-cgp). Fetch the relevant page when a detail is not covered here. Do not assume a local copy exists, because this skill is deployed on its own. --- ## Instructions for explaining CGP to users Assume by default that the user has only basic Rust experience and is new to CGP, but do not over-explain. When code merely uses CGP concepts, write or modify it without lecturing, and add explanation only when asked. When you do explain, assume unfamiliarity with advanced Rust (generics, traits, blanket impls, coherence) and with functional or type-level programming. Describe type-level tables, lists, and strings through familiar analogies such as a map or a lookup table, and expand on advanced Rust as needed. Keep the simplified picture front and center. Present wiring as choosing a table entry, and keep `IsProviderFor`, `DelegateComponent`, and generated blanket impls out of the explanation unless the user asks about the internals. One caveat when you reach for an analogy: the "table lookup" is resolved at compile time and compiles down to direct static calls. If you use a runtime-flavored analogy like a vtable, say explicitly that CGP's resolution, unlike a real vtable, is static and zero-cost, without a runtime table or dynamic dispatch. Never leave a reader thinking CGP wiring has runtime lookup overhead. **Never leave a reader thinking a CGP trait is limited to one item, either.** Because single-decision components dominate idiomatic CGP, an explanation built only from one-method traits reads as a restriction the macros impose. A reader who believes their traits are being capped pushes back on the whole paradigm rather than on the guidance. So say plainly, whenever the subject comes up, that a component trait is an ordinary trait taking as many methods, associated types, and consts as any other. CGP's own `CanCompute` and `CanHandle` carry an associated `Output` beside their method. Present the grouping guidance the way [components](references/components.md) frames it: a trade-off about how much reuse a provider can collect, decided by the author, never a rule about item counts. When asked to explain a specific piece of code, look up the definitions it depends on before answering. To explain a `delegate_components!` entry, find the consumer and provider traits behind the component key and the body of the provider it maps to. To explain a provider, read its own definition and the definitions of every capability in its `where` clause. To explain how a context implements something, follow its wiring to see which providers are chosen and trace a method call through them. For instance, if `NameGetterComponent` is wired to `UseField`, then a `self.name()` call inside another provider returns the context's `first_name` field.