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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,8 @@ the concepts, the construct reference, the comparisons, and the project pages. T
documentation on [docs.rs](https://docs.rs/cgp) is the place to look up an item.

> [!NOTE]
> Each crate's `docs.rs` page says what that crate provides and links the reference page for its
> constructs. The per-item documentation is still being filled in, so the website remains the place
> Each crate's `docs.rs` page says what that crate provides, and every public item carries a short
> doc. Each construct's doc links the reference page that explains it. The website remains the place
> to start.

Contributors and coding agents have a second, deeper source: the
Expand Down
5 changes: 5 additions & 0 deletions crates/core/cgp-base-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
//!
//! See [`Symbol!`](https://contextgeneric.dev/docs/reference/macros/symbol), [`Cons`](https://contextgeneric.dev/docs/reference/types/cons), [`Nil`](https://contextgeneric.dev/docs/reference/types/nil), [`Chars`](https://contextgeneric.dev/docs/reference/types/chars), [`PathCons`](https://contextgeneric.dev/docs/reference/types/path_cons), [`StaticFormat`](https://contextgeneric.dev/docs/reference/traits/formatting/static_format), and [`ConcatPath`](https://contextgeneric.dev/docs/reference/traits/formatting/concat_path).
#![no_std]
#![warn(missing_docs)]

/// Re-exports the type-level primitives that the macros expand to.
pub mod macro_prelude;
/// The type-level traits: [`traits::StaticFormat`] and [`traits::ConcatPath`].
pub mod traits;
/// The type-level types: [`types::Symbol`], [`types::Chars`], [`types::Cons`], [`types::Nil`], and
/// [`types::PathCons`].
pub mod types;
5 changes: 5 additions & 0 deletions crates/core/cgp-base-types/src/traits/concat_path.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
use crate::types::{Nil, PathCons};

/// Join two type-level paths, as the generated lookup behind namespaces and open does to append a
/// component's type parameters to its route.
///
/// See [`ConcatPath`](https://contextgeneric.dev/docs/reference/traits/formatting/concat_path).
pub trait ConcatPath<Other: ?Sized> {
/// The concatenated path.
type Output: ?Sized;
}

Expand Down
5 changes: 5 additions & 0 deletions crates/core/cgp-base-types/src/traits/static_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ use core::fmt::{self, Formatter};

use crate::types::{Chars, Nil};

/// Write a type-level string's characters into a formatter without a value to format; the trait
/// behind Display on Symbol and Chars.
///
/// See [`StaticFormat`](https://contextgeneric.dev/docs/reference/traits/formatting/static_format).
pub trait StaticFormat {
/// Writes the string to the formatter.
fn fmt(f: &mut Formatter<'_>) -> Result<(), fmt::Error>;
}

Expand Down
37 changes: 4 additions & 33 deletions crates/core/cgp-base-types/src/types/chars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,10 @@ use core::marker::PhantomData;

use crate::traits::StaticFormat;

/**
The `Chars` type is used to represent _type-level_ list of
`Chars`s, which are equivalent to type-level strings.

`Chars` is a specialized version of [`Cons`](crate::types::Cons), with the
`Head` type being fixed to a _const-generic_ value of type `Chars`.
Similar to `Cons`, `Chars` is also parameterized by a `Tail` type, which is
expected to be either the next `Chars`, or [`Nil`](crate::types::Nil) to
represent the end of the string.

We represent type-level strings as list of `Chars`s, because it is currently
not possible to use types like `String` or `&str` as const-generic parameters.
On the other hand, a single `Chars` can be used as a const-generic parameter,
and so we can workaround the limitation by combining a type-level list of
`Chars`s to represent a type-level string.

`Chars` is most often not used directly, but rather through the `Symbol!` macro,
which accepts a string literal and converts it into a list of `Chars`s.

## Example

Given the following symbol definition:

```rust,ignore
type Hello = Symbol!("hello");
```

The following type would be generated:

```rust,ignore
type Hello = Chars<'h', Chars<'e', Chars<'l', Chars<'l', Chars<'o', Nil>>>>>;
```
*/
/// The character list behind Symbol!, which spells a field name out one character at a time so the
/// name can be a type in trait resolution.
///
/// See [`Chars`](https://contextgeneric.dev/docs/reference/types/chars).
#[derive(Eq, PartialEq, Clone, Copy, Default)]
pub struct Chars<const CHAR: char, Tail>(pub PhantomData<Tail>);

Expand Down
25 changes: 4 additions & 21 deletions crates/core/cgp-base-types/src/types/cons.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,6 @@
/**
The `Cons` type is used to represent the head of a _type-level list_,
also known as an _anonymous product type_.

`Cons` is used together with [`Nil`](crate::types::Nil) to produce a type-level list using
the `Product!` macro.

## Example

Given the following product type definition:

```rust,ignore
type MyTypes = Product![u32, String, bool];
```

The following type would be generated:

```rust,ignore
type MyTypes = Cons<u32, Cons<String, Cons<bool, Nil>>>;
```
*/
/// The head-and-tail cell of the type-level product list, which describes a record one field at a
/// time so generic code can walk any struct's fields.
///
/// See [`Cons`](https://contextgeneric.dev/docs/reference/types/cons).
#[derive(Eq, PartialEq, Clone, Default, Debug)]
pub struct Cons<Head, Tail>(pub Head, pub Tail);
13 changes: 4 additions & 9 deletions crates/core/cgp-base-types/src/types/nil.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
/**
The `Nil` type is used to represent the end of a _type-level list_,
or an empty type-level list.

`Nil` is commonly used as the `Tail` of a [`Cons`](crate::types::Cons) type, to terminate the list.
When used on its own, it represents an empty type-level list.

Read more about type-level lists, a.k.a. the product types, in [`Cons`](crate::types::Cons).
*/
/// The end marker of the product, string, and path lists: an empty, constructible list that is also
/// the shape of a unit struct.
///
/// See [`Nil`](https://contextgeneric.dev/docs/reference/types/nil).
#[derive(Eq, PartialEq, Clone, Default, Debug)]
pub struct Nil;
4 changes: 4 additions & 0 deletions crates/core/cgp-base-types/src/types/path.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
use core::marker::PhantomData;

/// The cell of a type-level path, the list of segments that names a route through nested delegation
/// tables so a lookup can reach an entry behind a prefix.
///
/// See [`PathCons`](https://contextgeneric.dev/docs/reference/types/path_cons).
pub struct PathCons<Head: ?Sized, Tail: ?Sized>(pub PhantomData<Head>, pub PhantomData<Tail>);
3 changes: 3 additions & 0 deletions crates/core/cgp-base-types/src/types/symbol.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use core::fmt::Display;
use core::marker::PhantomData;

/// A type-level string, used as the tag that names a struct field in CGP's field-access traits.
///
/// See [`Symbol!`](https://contextgeneric.dev/docs/reference/macros/symbol).
pub struct Symbol<const LEN: usize, Chars>(pub PhantomData<Chars>);

use crate::traits::StaticFormat;
Expand Down
2 changes: 2 additions & 0 deletions crates/core/cgp-component/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
//! providers.
//!
//! See [`DelegateComponent`](https://contextgeneric.dev/docs/reference/traits/wiring/delegate_component), [`IsProviderFor`](https://contextgeneric.dev/docs/reference/traits/wiring/is_provider_for), [`CanUseComponent`](https://contextgeneric.dev/docs/reference/traits/wiring/can_use_component), [`UseContext`](https://contextgeneric.dev/docs/reference/providers/use_context), [`UseDefault`](https://contextgeneric.dev/docs/reference/providers/use_default), [`UseDelegate`](https://contextgeneric.dev/docs/reference/providers/use_delegate), and [`RedirectLookup`](https://contextgeneric.dev/docs/reference/providers/redirect_lookup).
#![warn(missing_docs)]

/// Re-exports the component machinery that the macros expand to.
pub mod macro_prelude;

mod namespaces;
Expand Down
19 changes: 19 additions & 0 deletions crates/core/cgp-component/src/namespaces.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
/// The namespace trait a context joins with a namespace header, resolving each component's default
/// route; prefix registers components into it.
///
/// See
/// [`DefaultNamespace`](https://contextgeneric.dev/docs/reference/traits/namespace/default_namespace)
/// .
pub trait DefaultNamespace<Components> {
/// The provider the namespace delegates to.
type Delegate;
}

/// The lookup trait for a namespace default keyed on a component and one type, which default_impl
/// registers into and a for loop reads back.
///
/// See [`DefaultImpls1`](https://contextgeneric.dev/docs/reference/traits/namespace/default_impls1)
/// .
pub trait DefaultImpls1<T, Components> {
/// The provider the default delegates to.
type Delegate;
}

/// The lookup trait for a namespace default keyed on a component and a pair of types, reachable
/// through default_impl and a for loop.
///
/// See [`DefaultImpls2`](https://contextgeneric.dev/docs/reference/traits/namespace/default_impls2)
/// .
pub trait DefaultImpls2<T1, T2, Components> {
/// The provider the default delegates to.
type Delegate;
}
4 changes: 4 additions & 0 deletions crates/core/cgp-component/src/providers/redirect_lookup.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
use core::marker::PhantomData;

/// The generated provider that answers a component by looking a type-level path up in a table, the
/// mechanism behind namespaces and the open statement.
///
/// See [`RedirectLookup`](https://contextgeneric.dev/docs/reference/providers/redirect_lookup).
pub struct RedirectLookup<Key, Components>(pub PhantomData<(Key, Components)>);
51 changes: 8 additions & 43 deletions crates/core/cgp-component/src/providers/use_context.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,13 @@
use crate::WithProvider;

/**
The `UseContext` pattern is used to define a trivial implementation of
a provider trait, by forwarding the implementation to the consumer trait
implementation of the context.

This pattern is the _dual_ of the blanket implementation of a consumer trait,
which forwards the implementation to its provider through the `CgpProvider` trait.

The main use case for `UseContext` is to be used as a _higher-order provider_
in the argument to a different provider implementation. This decouples the
dependencies between different CGP traits, and allows non-default providers
to be used within another provider implementation.

For obvious reasons, `UseContext` should not be used as the delegation target
from the context provider, as it would result in a cyclic dependency error.

The `UseContext` provider is automatically implemented for all CPG traits that
are generated from `#[cgp_component]`.

## Example

Given the following component definition:

```rust,ignore
#[cgp_component(Greeter)]
pub trait CanGreet {
fn greet(&self);
}
```

The following `UseContext` implementation would be generated:

```rust,ignore
impl<Context> Greeter<Context> for UseContext
where
Context: CanGreet,
{
fn greet(context: &Context) {
context.greet()
}
}
```
*/
/// The provider that implements a provider trait by calling the context's own consumer trait,
/// usually as a higher-order provider's default inner provider.
///
/// See [`UseContext`](https://contextgeneric.dev/docs/reference/providers/use_context).
pub struct UseContext;

/// The alias WithProvider`<UseContext>`: a named type or getter component answered by the context's
/// own HasType or HasField entry, keyed by the component.
///
/// See [`WithContext`](https://contextgeneric.dev/docs/reference/providers/with_context).
pub type WithContext = WithProvider<UseContext>;
4 changes: 4 additions & 0 deletions crates/core/cgp-component/src/providers/use_default.rs
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
/// The marker provider for a component whose implementation is the consumer trait's own default
/// method bodies, given meaning by an empty `#[cgp_impl]` block.
///
/// See [`UseDefault`](https://contextgeneric.dev/docs/reference/providers/use_default).
pub struct UseDefault;
58 changes: 4 additions & 54 deletions crates/core/cgp-component/src/providers/use_delegate.rs
Original file line number Diff line number Diff line change
@@ -1,57 +1,7 @@
use core::marker::PhantomData;

/**
The `UseDelegate` pattern is used as the _default dispatcher_ for CGP
components that contain additional generic parameters in their traits.

When a provider trait contains additional generic parameters in addition
to the `Context` type, CGP can generate a `UseDelegate` implementation
that uses `Components` as a _type-level lookup table_ to dispatch the
implementation to different providers based on the generic types.

The implementation of `UseDelegate` follows the same pattern as the
blanket implementation of a provider trait. However, instead of using
the component name type as the key, it uses the specified generic
parameters as the key to lookup the provider through `DelegateComponent`.

`UseDelegate` is very commonly used to perform ad hoc dispatch of
concrete types to different context-generic providers. This allows the
providers to remain generic, even when they may have implementations
that overlaps on the generic parameters.

The implementation of `UseDelegate` can be automatically generated through
the `#[derive_delegate]` attribute in `#[cgp_component]`. It is also possible to
implement the dispatcher pattern on types other than `UseDelegate`, especially
when there are multiple generic parameters that could be dispatched differently.
We mainly use `UseDelegate` as the default dispatcher, so that users don't need
to remember the different provider types to be used with each component.

## Example

Given the following component definition:

```rust,ignore
#[cgp_component(ErrorRaiser)]
#[derive_delegate(UseDelegate<SourceError>)]
pub trait CanRaiseError<SourceError>: HasErrorType {
fn raise_error(error: SourceError) -> Self::Error;
}
```

The following `UseDelegate` implementation would be generated:

```rust,ignore
impl<Context, SourceError, Components, Delegate> ErrorRaiser<Context, SourceError>
for UseDelegate<Components>
where
Context: HasErrorType,
Components: DelegateComponent<(SourceError), Delegate = Delegate>,
Delegate: ErrorRaiser<Context, SourceError>,
{
fn raise_error(error: SourceError) -> Context::Error {
Delegate::raise_error(error)
}
}
```
*/
/// The legacy provider that routes a component to a different inner provider per generic-parameter
/// type through a nested table; open replaces it.
///
/// See [`UseDelegate`](https://contextgeneric.dev/docs/reference/providers/use_delegate).
pub struct UseDelegate<Components>(pub PhantomData<Components>);
4 changes: 4 additions & 0 deletions crates/core/cgp-component/src/providers/use_fields.rs
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
/// The provider that implements every method of a getter component by reading the context field
/// named after the method, for any number of methods.
///
/// See [`UseFields`](https://contextgeneric.dev/docs/reference/providers/use_fields).
pub struct UseFields;
4 changes: 4 additions & 0 deletions crates/core/cgp-component/src/providers/with_provider.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
use core::marker::PhantomData;

/// The adapter that turns a TypeProvider or FieldGetter into a named component's provider, spelled
/// in wiring through the With… aliases.
///
/// See [`WithProvider`](https://contextgeneric.dev/docs/reference/providers/with_provider).
pub struct WithProvider<Provider>(pub PhantomData<Provider>);
18 changes: 5 additions & 13 deletions crates/core/cgp-component/src/traits/can_use_component.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
use crate::{DelegateComponent, IsProviderFor};

/**
This is a convenient type alias that is used in the same way as [`IsProviderFor`],
but with the `Self` type being the `Context` type rather than the `Provider` type
that implements the provider trait.

The `CanUseComponent` trait is automatically implemented for any CGP `Context` type
that implements the `DelegateComponent<Component>` trait, and when `Contex::Delegate`
implements `IsProviderFor<Component, Context, Params>`.

This trait is used by `check_components!` to check whether a `Context` implements
a given `Component` through its provider. When there are unsatisfied constraints,
Rust would show the error messages from the `IsProviderFor` implementation.
*/
/// The check a check_components! entry asserts: the context wires the component, and the provider
/// it chose has every dependency met for that context.
///
/// See
/// [`CanUseComponent`](https://contextgeneric.dev/docs/reference/traits/wiring/can_use_component) .
pub trait CanUseComponent<Component, Params: ?Sized = ()> {}

impl<Context, Component, Params: ?Sized> CanUseComponent<Component, Params> for Context
Expand Down
Loading
Loading