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
5 changes: 3 additions & 2 deletions crates/core/cgp-error/src/traits/can_raise_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::traits::has_error_type::HasErrorType;
#[cgp_component(ErrorRaiser)]
#[prefix(@cgp.core.error in DefaultNamespace)]
#[derive_delegate(UseDelegate<SourceError>)]
pub trait CanRaiseError<SourceError>: HasErrorType {
fn raise_error(error: SourceError) -> Self::Error;
#[use_type(HasErrorType::Error)]
pub trait CanRaiseError<SourceError> {
fn raise_error(error: SourceError) -> Error;
}
5 changes: 3 additions & 2 deletions crates/core/cgp-error/src/traits/can_wrap_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::traits::HasErrorType;
#[cgp_component(ErrorWrapper)]
#[prefix(@cgp.core.error in DefaultNamespace)]
#[derive_delegate(UseDelegate<Detail>)]
pub trait CanWrapError<Detail>: HasErrorType {
fn wrap_error(error: Self::Error, detail: Detail) -> Self::Error;
#[use_type(HasErrorType::Error)]
pub trait CanWrapError<Detail> {
fn wrap_error(error: Error, detail: Detail) -> Error;
}
14 changes: 6 additions & 8 deletions crates/extra/cgp-handler/src/components/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,25 @@ use crate::UseInputDelegate;
#[prefix(@cgp.extra.handler in DefaultNamespace)]
#[derive_delegate(UseDelegate<Code>)]
#[derive_delegate(UseInputDelegate<Input>)]
pub trait CanHandle<Code, Input>: HasErrorType {
#[use_type(HasErrorType::Error)]
pub trait CanHandle<Code, Input> {
type Output;

async fn handle(
&self,
_tag: PhantomData<Code>,
input: Input,
) -> Result<Self::Output, Self::Error>;
async fn handle(&self, _tag: PhantomData<Code>, input: Input) -> Result<Self::Output, Error>;
}

#[async_trait]
#[cgp_component(HandlerRef)]
#[prefix(@cgp.extra.handler in DefaultNamespace)]
#[derive_delegate(UseDelegate<Code>)]
#[derive_delegate(UseInputDelegate<Input>)]
pub trait CanHandleRef<Code, Input>: HasErrorType {
#[use_type(HasErrorType::Error)]
pub trait CanHandleRef<Code, Input> {
type Output;

async fn handle_ref(
&self,
_tag: PhantomData<Code>,
input: &Input,
) -> Result<Self::Output, Self::Error>;
) -> Result<Self::Output, Error>;
}
14 changes: 6 additions & 8 deletions crates/extra/cgp-handler/src/components/try_compute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,24 @@ use crate::UseInputDelegate;
#[prefix(@cgp.extra.handler in DefaultNamespace)]
#[derive_delegate(UseDelegate<Code>)]
#[derive_delegate(UseInputDelegate<Input>)]
pub trait CanTryCompute<Code, Input>: HasErrorType {
#[use_type(HasErrorType::Error)]
pub trait CanTryCompute<Code, Input> {
type Output;

fn try_compute(
&self,
_code: PhantomData<Code>,
input: Input,
) -> Result<Self::Output, Self::Error>;
fn try_compute(&self, _code: PhantomData<Code>, input: Input) -> Result<Self::Output, Error>;
}

#[cgp_component(TryComputerRef)]
#[prefix(@cgp.extra.handler in DefaultNamespace)]
#[derive_delegate(UseDelegate<Code>)]
#[derive_delegate(UseInputDelegate<Input>)]
pub trait CanTryComputeRef<Code, Input>: HasErrorType {
#[use_type(HasErrorType::Error)]
pub trait CanTryComputeRef<Code, Input> {
type Output;

fn try_compute_ref(
&self,
_code: PhantomData<Code>,
input: &Input,
) -> Result<Self::Output, Self::Error>;
) -> Result<Self::Output, Error>;
}
13 changes: 6 additions & 7 deletions crates/extra/cgp-run/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@ use cgp::prelude::*;
#[cgp_component(Runner)]
#[async_trait]
#[derive_delegate(UseDelegate<Code>)]
pub trait CanRun<Code>: HasErrorType {
async fn run(&self, _code: PhantomData<Code>) -> Result<(), Self::Error>;
#[use_type(HasErrorType::Error)]
pub trait CanRun<Code> {
async fn run(&self, _code: PhantomData<Code>) -> Result<(), Error>;
}

#[cgp_component(SendRunner)]
#[async_trait]
#[derive_delegate(UseDelegate<Code>)]
pub trait CanSendRun<Code>: HasErrorType {
fn send_run(
&self,
_code: PhantomData<Code>,
) -> impl Future<Output = Result<(), Self::Error>> + Send;
#[use_type(HasErrorType::Error)]
pub trait CanSendRun<Code> {
fn send_run(&self, _code: PhantomData<Code>) -> impl Future<Output = Result<(), Error>> + Send;
}
5 changes: 3 additions & 2 deletions crates/extra/cgp-runtime/src/traits/has_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use cgp::prelude::*;
use crate::HasRuntimeType;

#[cgp_getter]
pub trait HasRuntime: HasRuntimeType {
fn runtime(&self) -> &Self::Runtime;
#[use_type(HasRuntimeType::Runtime)]
pub trait HasRuntime {
fn runtime(&self) -> &Runtime;
}
1 change: 1 addition & 0 deletions docs/concepts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The authoring rules for concept documents, including when a cross-cutting idea e

- [Bypassing coherence](coherence.md) — what Rust's coherence rules forbid, and the incoherent-impl-plus-local-wiring strategy CGP uses to work around them.
- [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.
- [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.
- [Consumer and provider traits](consumer-and-provider-traits.md) — the trait duality at the heart of CGP and how it sidesteps coherence.
- [Impl-side dependencies](impl-side-dependencies.md) — dependency injection through the `where` clause of blanket impls.
- [Implicit arguments](implicit-arguments.md) — writing providers as ordinary functions whose arguments come from context fields.
Expand Down
5 changes: 3 additions & 2 deletions docs/concepts/abstract-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ pub trait HasScalarType {
}

#[cgp_component(AreaOfShapeCalculator)]
pub trait CanCalculateAreaOfShape<Shape>: HasScalarType {
fn area(&self, shape: &Shape) -> Self::Scalar;
#[use_type(HasScalarType::Scalar)]
pub trait CanCalculateAreaOfShape<Shape> {
fn area(&self, shape: &Shape) -> Scalar;
}
```

Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/higher-order-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Here `Tag` is a type-level field name, used only as a `HasField` key, with no pr

## Related constructs

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.
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.

## Source

Expand Down
6 changes: 3 additions & 3 deletions docs/concepts/implicit-arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ These same rules govern getter access in [`#[cgp_auto_getter]`](../reference/mac

## When to use which

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.
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.

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.
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.

## Related constructs

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).

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.
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.
Loading
Loading