Skip to content

Commit d0e3044

Browse files
authored
Add modern idioms documentation and other minor docs updates (#245)
* Add modern idioms to concepts * Add more modern idioms * Fix formatting
1 parent 87390e2 commit d0e3044

37 files changed

Lines changed: 522 additions & 240 deletions

crates/core/cgp-error/src/traits/can_raise_error.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::traits::has_error_type::HasErrorType;
1010
#[cgp_component(ErrorRaiser)]
1111
#[prefix(@cgp.core.error in DefaultNamespace)]
1212
#[derive_delegate(UseDelegate<SourceError>)]
13-
pub trait CanRaiseError<SourceError>: HasErrorType {
14-
fn raise_error(error: SourceError) -> Self::Error;
13+
#[use_type(HasErrorType::Error)]
14+
pub trait CanRaiseError<SourceError> {
15+
fn raise_error(error: SourceError) -> Error;
1516
}

crates/core/cgp-error/src/traits/can_wrap_error.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::traits::HasErrorType;
66
#[cgp_component(ErrorWrapper)]
77
#[prefix(@cgp.core.error in DefaultNamespace)]
88
#[derive_delegate(UseDelegate<Detail>)]
9-
pub trait CanWrapError<Detail>: HasErrorType {
10-
fn wrap_error(error: Self::Error, detail: Detail) -> Self::Error;
9+
#[use_type(HasErrorType::Error)]
10+
pub trait CanWrapError<Detail> {
11+
fn wrap_error(error: Error, detail: Detail) -> Error;
1112
}

crates/extra/cgp-handler/src/components/handler.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,25 @@ use crate::UseInputDelegate;
1010
#[prefix(@cgp.extra.handler in DefaultNamespace)]
1111
#[derive_delegate(UseDelegate<Code>)]
1212
#[derive_delegate(UseInputDelegate<Input>)]
13-
pub trait CanHandle<Code, Input>: HasErrorType {
13+
#[use_type(HasErrorType::Error)]
14+
pub trait CanHandle<Code, Input> {
1415
type Output;
1516

16-
async fn handle(
17-
&self,
18-
_tag: PhantomData<Code>,
19-
input: Input,
20-
) -> Result<Self::Output, Self::Error>;
17+
async fn handle(&self, _tag: PhantomData<Code>, input: Input) -> Result<Self::Output, Error>;
2118
}
2219

2320
#[async_trait]
2421
#[cgp_component(HandlerRef)]
2522
#[prefix(@cgp.extra.handler in DefaultNamespace)]
2623
#[derive_delegate(UseDelegate<Code>)]
2724
#[derive_delegate(UseInputDelegate<Input>)]
28-
pub trait CanHandleRef<Code, Input>: HasErrorType {
25+
#[use_type(HasErrorType::Error)]
26+
pub trait CanHandleRef<Code, Input> {
2927
type Output;
3028

3129
async fn handle_ref(
3230
&self,
3331
_tag: PhantomData<Code>,
3432
input: &Input,
35-
) -> Result<Self::Output, Self::Error>;
33+
) -> Result<Self::Output, Error>;
3634
}

crates/extra/cgp-handler/src/components/try_compute.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,24 @@ use crate::UseInputDelegate;
99
#[prefix(@cgp.extra.handler in DefaultNamespace)]
1010
#[derive_delegate(UseDelegate<Code>)]
1111
#[derive_delegate(UseInputDelegate<Input>)]
12-
pub trait CanTryCompute<Code, Input>: HasErrorType {
12+
#[use_type(HasErrorType::Error)]
13+
pub trait CanTryCompute<Code, Input> {
1314
type Output;
1415

15-
fn try_compute(
16-
&self,
17-
_code: PhantomData<Code>,
18-
input: Input,
19-
) -> Result<Self::Output, Self::Error>;
16+
fn try_compute(&self, _code: PhantomData<Code>, input: Input) -> Result<Self::Output, Error>;
2017
}
2118

2219
#[cgp_component(TryComputerRef)]
2320
#[prefix(@cgp.extra.handler in DefaultNamespace)]
2421
#[derive_delegate(UseDelegate<Code>)]
2522
#[derive_delegate(UseInputDelegate<Input>)]
26-
pub trait CanTryComputeRef<Code, Input>: HasErrorType {
23+
#[use_type(HasErrorType::Error)]
24+
pub trait CanTryComputeRef<Code, Input> {
2725
type Output;
2826

2927
fn try_compute_ref(
3028
&self,
3129
_code: PhantomData<Code>,
3230
input: &Input,
33-
) -> Result<Self::Output, Self::Error>;
31+
) -> Result<Self::Output, Error>;
3432
}

crates/extra/cgp-run/src/lib.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,15 @@ use cgp::prelude::*;
88
#[cgp_component(Runner)]
99
#[async_trait]
1010
#[derive_delegate(UseDelegate<Code>)]
11-
pub trait CanRun<Code>: HasErrorType {
12-
async fn run(&self, _code: PhantomData<Code>) -> Result<(), Self::Error>;
11+
#[use_type(HasErrorType::Error)]
12+
pub trait CanRun<Code> {
13+
async fn run(&self, _code: PhantomData<Code>) -> Result<(), Error>;
1314
}
1415

1516
#[cgp_component(SendRunner)]
1617
#[async_trait]
1718
#[derive_delegate(UseDelegate<Code>)]
18-
pub trait CanSendRun<Code>: HasErrorType {
19-
fn send_run(
20-
&self,
21-
_code: PhantomData<Code>,
22-
) -> impl Future<Output = Result<(), Self::Error>> + Send;
19+
#[use_type(HasErrorType::Error)]
20+
pub trait CanSendRun<Code> {
21+
fn send_run(&self, _code: PhantomData<Code>) -> impl Future<Output = Result<(), Error>> + Send;
2322
}

crates/extra/cgp-runtime/src/traits/has_runtime.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use cgp::prelude::*;
33
use crate::HasRuntimeType;
44

55
#[cgp_getter]
6-
pub trait HasRuntime: HasRuntimeType {
7-
fn runtime(&self) -> &Self::Runtime;
6+
#[use_type(HasRuntimeType::Runtime)]
7+
pub trait HasRuntime {
8+
fn runtime(&self) -> &Runtime;
89
}

docs/concepts/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The authoring rules for concept documents, including when a cross-cutting idea e
1212

1313
- [Bypassing coherence](coherence.md) — what Rust's coherence rules forbid, and the incoherent-impl-plus-local-wiring strategy CGP uses to work around them.
1414
- [Modularity hierarchy](modularity-hierarchy.md) — the ladder from a single blanket impl to per-type-per-provider wiring, and how to pick the lowest rung a use case needs.
15+
- [Modern idioms: a migration guide](modern-idioms.md) — the preferred higher-level forms for providers, dependencies, abstract types, and dispatch, mapped from the explicit forms they replace.
1516
- [Consumer and provider traits](consumer-and-provider-traits.md) — the trait duality at the heart of CGP and how it sidesteps coherence.
1617
- [Impl-side dependencies](impl-side-dependencies.md) — dependency injection through the `where` clause of blanket impls.
1718
- [Implicit arguments](implicit-arguments.md) — writing providers as ordinary functions whose arguments come from context fields.

docs/concepts/abstract-types.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ pub trait HasScalarType {
5555
}
5656

5757
#[cgp_component(AreaOfShapeCalculator)]
58-
pub trait CanCalculateAreaOfShape<Shape>: HasScalarType {
59-
fn area(&self, shape: &Shape) -> Self::Scalar;
58+
#[use_type(HasScalarType::Scalar)]
59+
pub trait CanCalculateAreaOfShape<Shape> {
60+
fn area(&self, shape: &Shape) -> Scalar;
6061
}
6162
```
6263

docs/concepts/higher-order-providers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ Here `Tag` is a type-level field name, used only as a `HasField` key, with no pr
7575

7676
## Related constructs
7777

78-
Higher-order providers are written with [`#[cgp_impl]`](../reference/macros/cgp_impl.md) (or `#[cgp_fn]`), giving the inner provider as a generic parameter in the provider's `Self` position. The [`#[use_provider]`](../reference/attributes/use_provider.md) attribute is the idiomatic tool for them: it supplies the hidden `<Self>` on the inner bound, leaving the body to invoke the inner provider as the associated-function call the provider trait actually requires. [`UseContext`](../reference/providers/use_context.md) serves as the default inner provider when the higher-order provider is given an explicit struct with a defaulted parameter, letting it fall back to the context's own wiring. For dispatching to different inner providers based on a generic type rather than naming one statically, [`UseDelegate`](../reference/providers/use_delegate.md) pairs naturally with higher-order providers — a nested delegation table can map each shape to a different `ScaledArea<...>`. Each layer of a nested provider can be verified independently with the `#[check_providers]` form of [`check_components!`](../reference/macros/check_components.md), which is what makes higher-order wiring debuggable.
78+
Higher-order providers are written with [`#[cgp_impl]`](../reference/macros/cgp_impl.md) (or `#[cgp_fn]`), giving the inner provider as a generic parameter in the provider's `Self` position. The [`#[use_provider]`](../reference/attributes/use_provider.md) attribute is the idiomatic tool for them: it supplies the hidden `<Self>` on the inner bound, leaving the body to invoke the inner provider as the associated-function call the provider trait actually requires. [`UseContext`](../reference/providers/use_context.md) serves as the default inner provider when the higher-order provider is given an explicit struct with a defaulted parameter, letting it fall back to the context's own wiring. For dispatching to different inner providers based on a generic type rather than naming one statically, prefer the [`open` statement](../reference/macros/delegate_components.md) of `delegate_components!`, which maps each shape to a different `ScaledArea<...>` through the `RedirectLookup` impl every component carries; the legacy [`UseDelegate`](../reference/providers/use_delegate.md) nested table does the same job for older code. Each layer of a nested provider can be verified independently with the `#[check_providers]` form of [`check_components!`](../reference/macros/check_components.md), which is what makes higher-order wiring debuggable.
7979

8080
## Source
8181

docs/concepts/implicit-arguments.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ These same rules govern getter access in [`#[cgp_auto_getter]`](../reference/mac
3333

3434
## When to use which
3535

36-
Implicit arguments and getter traits both read context fields through `HasField`, and the choice between them is about where the value is needed. An implicit argument is the right tool when a value is consumed once, at the start of a method, as if it were a parameter — it keeps the field access local to the one function that uses it. A getter trait written with [`#[cgp_auto_getter]`](../reference/macros/cgp_auto_getter.md) is better when the same field is read across many methods, or part-way through a body rather than up front, because it exposes the field as a reusable `self.name()` accessor instead of re-declaring an implicit argument in every function.
36+
An implicit argument is the default way to read a context field, and a getter trait is the exception reserved for publishing a reusable capability. Both read fields through `HasField` and share the same access rules, so the choice is not about mechanics but about what the value *is*. An implicit argument treats the value as a private input to one provider: it is bound as a local at the top of the method and used freely from there, which covers reading a field once, using it throughout a body, or declaring it on each of several methods that need it. This is the form to reach for whenever a provider simply needs a value from its context.
3737

38-
The two are complementary rather than competing, and a provider commonly uses both. Reach for an implicit argument to inject the inputs a single computation consumes, and for a getter trait to expose a field that several computations share; the underlying `HasField` machinery and access rules are identical, so mixing them carries no conceptual overhead.
38+
A getter trait written with [`#[cgp_auto_getter]`](../reference/macros/cgp_auto_getter.md) is worth defining only when the value is a *published capability* rather than a private input — a named `self.name()` accessor that other providers depend on through `#[uses(HasName)]`, or a getter whose associated type is inferred from the field so the type stays abstract. Declaring such a trait promotes the field to part of the context's capability surface. When all a provider wants is to read a field for its own computation, an implicit argument says exactly that with less ceremony, so prefer it and treat the getter trait as the deliberate step of exposing a shared capability. The full wireable getter, [`#[cgp_getter]`](../reference/macros/cgp_getter.md), is a further step still, reserved for the advanced case of choosing the source field per context at wiring time.
3939

4040
## Related constructs
4141

4242
The [`#[implicit]`](../reference/attributes/implicit.md) attribute is the construct itself, usable inside [`#[cgp_fn]`](../reference/macros/cgp_fn.md) and [`#[cgp_impl]`](../reference/macros/cgp_impl.md) — the former producing a single-implementation capability with no wiring, the latter a provider for a [`#[cgp_component]`](../reference/macros/cgp_component.md). All of them desugar implicit arguments into [`HasField`](../reference/traits/has_field.md) bounds, which a context supplies by deriving [`#[derive(HasField)]`](../reference/derives/derive_has_field.md).
4343

44-
For repeated or mid-body field access, [`#[cgp_auto_getter]`](../reference/macros/cgp_auto_getter.md) is the getter-trait counterpart that shares the same `.clone()`/`.as_str()` access rules. The whole model is value-level [impl-side dependencies](impl-side-dependencies.md): an implicit argument is a context dependency injected through a `where`-clause `HasField` bound and dressed as a function parameter.
44+
For publishing a field as a shared, reusable accessor, [`#[cgp_auto_getter]`](../reference/macros/cgp_auto_getter.md) is the getter-trait counterpart that shares the same `.clone()`/`.as_str()` access rules — but a provider reading a field for its own use should prefer an implicit argument. The whole model is value-level [impl-side dependencies](impl-side-dependencies.md): an implicit argument is a context dependency injected through a `where`-clause `HasField` bound and dressed as a function parameter.

0 commit comments

Comments
 (0)