Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 120 additions & 45 deletions README.md

Large diffs are not rendered by default.

24 changes: 13 additions & 11 deletions crates/macros/cgp-macro-test-util/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# `cgp-macro-test-util`
# cgp-macro-test-util: snapshot-testing macros for the CGP macros

Snapshot-testing macros for the CGP procedural macros.
**The macros that pin the code the CGP procedural macros generate, as inline `insta` snapshots.**

**[Website](https://contextgeneric.dev/) · [Reference](https://contextgeneric.dev/docs/reference/) · [Implementation record](https://github.com/contextgeneric/cgp-knowledge-base/blob/main/cgp/implementation/entrypoints/snapshot_macros.md)**

This crate exposes a family of `snapshot_*!` procedural macros that pin the code the
core CGP macros generate. Each one does **two** things at once: it emits the real
generated code into the surrounding module, exactly as the underlying CGP macro
would — so the traits, structs, and impls stay live and the rest of the module can
still wire them up and assert their runtime behavior — and it generates a `#[test]`
would, so the traits, structs, and impls stay live and the rest of the module can
still wire them up and assert their runtime behavior, and it generates a `#[test]`
that asserts a pretty-printed string of that same code against an inline
[`insta`](https://insta.rs) snapshot. Adding or removing a snapshot therefore
changes only the golden assertion, never the compile-time or runtime coverage.
Expand All @@ -15,7 +17,7 @@ Two documents carry what this README does not. The
[implementation document](https://github.com/contextgeneric/cgp-knowledge-base/blob/main/cgp/implementation/entrypoints/snapshot_macros.md)
in the knowledge base explains how the macros are built and what an invocation
expands to; [crates/tests/AGENTS.md](../../tests/AGENTS.md) sets the convention for
*when* to snapshot — a macro's expansion is pinned only in the concept target that
*when* to snapshot: a macro's expansion is pinned only in the concept target that
owns that macro's feature, and written plainly everywhere else.

## Crate layout
Expand Down Expand Up @@ -63,9 +65,9 @@ so a snapshot is guaranteed to show what the production macros generate.
| `snapshot_cgp_producer!` | `#[cgp_producer]` |
| `snapshot_cgp_auto_dispatch!` | `#[cgp_auto_dispatch]` |

Each accepts the same argument forms as the macro it wraps — `snapshot_cgp_component!`
takes both `#[cgp_component(Greeter)]` and the brace form, for instance — precisely
because it drives the production entry function.
Each accepts the same argument forms as the macro it wraps, because it drives the
production entry function; `snapshot_cgp_component!` takes both
`#[cgp_component(Greeter)]` and the brace form, for instance.

## Anatomy of an invocation

Expand All @@ -90,9 +92,9 @@ snapshot_cgp_getter! {
}
```

That emits the real `#[cgp_getter]` expansion — the consumer trait and its blanket
impl, the provider trait, the marker struct, and the `UseField`/`UseFields`/
`RedirectLookup` provider impls — and then a `fn expand_has_name()` holding the same
That emits the real `#[cgp_getter]` expansion, which is the consumer trait and its
blanket impl, the provider trait, the marker struct, and the `UseField`/`UseFields`/
`RedirectLookup` provider impls, and then a `fn expand_has_name()` holding the same
code as a string. The test-function name must be unique within its module, so give
each snapshot in a file a distinct one.

Expand Down
42 changes: 35 additions & 7 deletions crates/main/cgp/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,41 @@
# `cgp` — Context-Generic Programming in Rust
# `cgp`: Context-Generic Programming in Rust

## Overview
**A language extension for Rust, with pluggable trait implementations at compile-time.**

Context-Generic Programming (CGP) is a language extension for Rust, with pluggable trait implementations at compile-time. In ordinary Rust a trait has one implementation per type; CGP lets one trait have many interchangeable implementations and lets each *context* choose which one it uses, through a small wiring table the compiler resolves statically — so the flexibility costs nothing at runtime. The `cgp` crate is the facade over a collection of micro crates that provide it, and it re-exports everything through `cgp::prelude`.
The `cgp` crate is the facade over the collection of crates that provide CGP, and it re-exports
everything through `cgp::prelude`. In ordinary Rust a trait has one implementation per type; CGP lets
one trait have many interchangeable implementations and lets each *context* choose which one it uses,
through a small wiring table the compiler resolves statically, so provider selection adds nothing at
runtime.

To learn more, see the website [contextgeneric.dev](https://contextgeneric.dev/) and the book [Context-Generic Programming Patterns](https://patterns.contextgeneric.dev/).
## Learn CGP

<div class="warning">
The documentation lives on the website, [contextgeneric.dev](https://contextgeneric.dev/):

The `cgp` constructs are still mostly undocumented within Rustdoc. The best way to learn CGP today is the book [Context-Generic Programming Patterns](https://patterns.contextgeneric.dev/); for the exhaustive per-construct semantics, see the [CGP knowledge base](https://github.com/contextgeneric/cgp-knowledge-base).
- [Quickstart](https://contextgeneric.dev/docs/quickstart): install it and run a first program.
- [Tutorials](https://contextgeneric.dev/docs/tutorials/hello): learn by building.
- [Concepts](https://contextgeneric.dev/docs/concepts/): why CGP works the way it does.
- [Reference](https://contextgeneric.dev/docs/reference/): one page per construct.

</div>
The API documentation here covers the items themselves; the website explains how to use them. For the
exhaustive per-construct semantics, the
[CGP knowledge base](https://github.com/contextgeneric/cgp-knowledge-base) is written for agents and
records the internals.

## Install

```bash
cargo add cgp
```

```rust
use cgp::prelude::*;
```

CGP requires Rust 1.89+ and runs on the stable toolchain. When you start with CGP, install
[`cargo-cgp`](https://github.com/contextgeneric/cargo-cgp) alongside it: `cargo cgp check` leads with
the root cause for the classes it recognizes, and the tool does not yet reshape every class.

## License

Licensed under the [Apache License, Version 2.0](https://github.com/contextgeneric/cgp/blob/main/LICENSE).
12 changes: 11 additions & 1 deletion crates/standalone/error/cgp-error-anyhow/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# cgp-error-anyhow
[![Crates.io](https://img.shields.io/crates/v/cgp-error-anyhow.svg)](https://crates.io/crates/cgp-error-anyhow)
[![Docs.rs](https://docs.rs/cgp-error-anyhow/badge.svg)](https://docs.rs/cgp-error-anyhow)
![License](https://img.shields.io/badge/license-Apache_2.0-blue.svg)

# cgp-error-anyhow: anyhow as a context's error type

`cgp-error-anyhow` makes [`anyhow::Error`](https://docs.rs/anyhow) the abstract error type of a
[CGP](https://contextgeneric.dev) context, and supplies the providers that raise errors into it and
add context to it. Code written against `HasErrorType`, `CanRaiseError`, and `CanWrapError` stays
generic; only the context's wiring names anyhow.

**[Website](https://contextgeneric.dev/) · [Modular error handling](https://contextgeneric.dev/docs/concepts/modular-error-handling) · [The error components](https://contextgeneric.dev/docs/reference/components/has_error_type) · [Project record](https://github.com/contextgeneric/cgp-knowledge-base/blob/main/projects/error/README.md)**

| Provider | Wire it to | What it does |
|---|---|---|
| `UseAnyhowError` | `ErrorTypeProviderComponent` | sets the context's `Error` to `anyhow::Error` |
Expand Down Expand Up @@ -43,3 +49,7 @@ feature. Enabling that feature elsewhere in the dependency graph turns on the pa
need `std`, such as backtrace capture.

The crate re-exports `anyhow::Error` as `cgp_error_anyhow::Error`.

## License

Licensed under the [Apache License, Version 2.0](https://github.com/contextgeneric/cgp/blob/main/LICENSE).
12 changes: 11 additions & 1 deletion crates/standalone/error/cgp-error-eyre/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# cgp-error-eyre
[![Crates.io](https://img.shields.io/crates/v/cgp-error-eyre.svg)](https://crates.io/crates/cgp-error-eyre)
[![Docs.rs](https://docs.rs/cgp-error-eyre/badge.svg)](https://docs.rs/cgp-error-eyre)
![License](https://img.shields.io/badge/license-Apache_2.0-blue.svg)

# cgp-error-eyre: eyre as a context's error type

`cgp-error-eyre` makes [`eyre::Report`](https://docs.rs/eyre) the abstract error type of a
[CGP](https://contextgeneric.dev) context, and supplies the providers that raise errors into it and
add context to it. Code written against `HasErrorType`, `CanRaiseError`, and `CanWrapError` stays
generic; only the context's wiring names eyre.

**[Website](https://contextgeneric.dev/) · [Modular error handling](https://contextgeneric.dev/docs/concepts/modular-error-handling) · [The error components](https://contextgeneric.dev/docs/reference/components/has_error_type) · [Project record](https://github.com/contextgeneric/cgp-knowledge-base/blob/main/projects/error/README.md)**

| Provider | Wire it to | What it does |
|---|---|---|
| `UseEyreError` | `ErrorTypeProviderComponent` | sets the context's `Error` to `eyre::Report` |
Expand Down Expand Up @@ -48,3 +54,7 @@ error. The crate also enables eyre's `track-caller` feature, and CGP's `raise_er
`std`, so this crate does too.

The crate re-exports `eyre::Error`, eyre's alias for `Report`, as `cgp_error_eyre::Error`.

## License

Licensed under the [Apache License, Version 2.0](https://github.com/contextgeneric/cgp/blob/main/LICENSE).
12 changes: 11 additions & 1 deletion crates/standalone/error/cgp-error-std/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# cgp-error-std
[![Crates.io](https://img.shields.io/crates/v/cgp-error-std.svg)](https://crates.io/crates/cgp-error-std)
[![Docs.rs](https://docs.rs/cgp-error-std/badge.svg)](https://docs.rs/cgp-error-std)
![License](https://img.shields.io/badge/license-Apache_2.0-blue.svg)

# cgp-error-std: a boxed standard error as a context's error type

`cgp-error-std` makes a boxed standard error, `Box<dyn core::error::Error + Send + Sync>`, the
abstract error type of a [CGP](https://contextgeneric.dev) context, and supplies the providers that
raise errors into it and add context to it. It depends only on `cgp` and `alloc`, so it suits a
`no_std` context that still wants an open-ended error type.

**[Website](https://contextgeneric.dev/) · [Modular error handling](https://contextgeneric.dev/docs/concepts/modular-error-handling) · [The error components](https://contextgeneric.dev/docs/reference/components/has_error_type) · [Project record](https://github.com/contextgeneric/cgp-knowledge-base/blob/main/projects/error/README.md)**

| Item | Wire it to | What it does |
|---|---|---|
| `UseBoxedStdError` | `ErrorTypeProviderComponent` | sets the context's `Error` to `cgp_error_std::Error` |
Expand Down Expand Up @@ -45,3 +51,7 @@ A `WrapError` prints its detail alone with `{}`, so a reporter that walks `sourc
message once, and prints the whole chain with `{:#}` or `{:?}`. A `String` needs
`DisplayBoxedStdError` or `DebugBoxedStdError`, because it is not a standard error, and
`DebugBoxedStdError` prints it with quotes.

## License

Licensed under the [Apache License, Version 2.0](https://github.com/contextgeneric/cgp/blob/main/LICENSE).
16 changes: 9 additions & 7 deletions crates/tests/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# CGP test suite
# CGP test suite: the tests organized by CGP concept

This directory holds the test suite for Context-Generic Programming, organized **by
CGP concept** — basic delegation, abstract types, implicit arguments, namespaces,
and so on — rather than by the macro that implements each concept, because a single
CGP concept**, such as basic delegation, abstract types, implicit arguments, or namespaces,
rather than by the macro that implements each concept, because a single
macro such as `delegate_components!` serves many concepts at once. This README is
the map of what is here and how to run it; [AGENTS.md](AGENTS.md) is the
authoritative guide to the conventions, and you should read it before adding,
moving, or refactoring a test.

**[Website](https://contextgeneric.dev/) · [Reference](https://contextgeneric.dev/docs/reference/) · [Implementation record](https://github.com/contextgeneric/cgp-knowledge-base/blob/main/cgp/implementation/README.md)**

## The crates

The suite is split into two crates, each with a distinct job.
Expand All @@ -18,8 +20,8 @@ by compiling. It is also where the user-facing macros are exercised end-to-end a
where the canonical macro-expansion snapshots live.

**`cgp-macro-tests`** tests the macro internals directly against `cgp-macro-core`
(the parsers and AST types), and is the home for **rejection cases** — inputs CGP
refuses during expansion — and for pinning the invalid tokens a macro currently
(the parsers and AST types), and is the home for **rejection cases**, the inputs CGP
refuses during expansion, and for pinning the invalid tokens a macro currently
emits.

A third category lives in another repository: the cases where a macro *accepts*
Expand All @@ -31,7 +33,7 @@ so each is pinned as the readable error the tool renders for it. AGENTS.md's
## How the tests are laid out

Inside `cgp-tests`, each concept is one **integration test target**, which Cargo
compiles as its own crate — and therefore its own coherence scope. A target is an
compiles as its own crate, and therefore its own coherence scope. A target is an
entrypoint file `tests/<concept>_tests.rs` plus a module directory
`tests/<concept>/` holding one `.rs` file per unit test, each self-contained so the
type-level wiring of one test never leaks into another. `tests/basic_delegation/`
Expand Down Expand Up @@ -62,6 +64,6 @@ cargo insta test -p cgp-tests --accept # accept intended snapshot chang
Many tests assert the exact code a macro generates, through the `snapshot_*!`
macros from `cgp-macro-test-util`: each emits the real generated code into the
module *and* generates a `#[test]` asserting a pretty-printed inline `insta`
snapshot of it. So a failing snapshot prints a diff of the generated code — accept
snapshot of it. A failing snapshot prints a diff of the generated code, so accept
it with `cargo insta` only after confirming the change is intended. Which target
owns a given macro's snapshot is a convention AGENTS.md sets out.
3 changes: 3 additions & 0 deletions sibling-projects.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ and the worked examples sit at the knowledge base's top level.
| `cgp-skills` | <https://github.com/contextgeneric/cgp-skills> | `main` | The agent skills for CGP, deployed on their own, the `/cgp` skill among them. |
| `cgp-knowledge-base` | <https://github.com/contextgeneric/cgp-knowledge-base> | `main` | The consolidated documentation for every CGP project, written by and for AI agents. |

The knowledge base's [sibling-projects.md](https://github.com/contextgeneric/cgp-knowledge-base/blob/main/sibling-projects.md) is the authoritative list of the whole ecosystem,
including the projects that are not part of the core.

## Finding a sibling

Look for a sibling in the parent directory first, at `../<project>`. Every project in this list,
Expand Down
Loading