CGP v0.4.1 Release
Posted on 2025-06-14
Authored by Soares Chen

We are excited to announce the release of CGP v0.4.1! This release brings several new features, quality-of-life improvements for macro usages, and a new crate cgp-handler.

Here are some of the highlights:

  • New cgp-handler crate: Provides abstract interfaces for defining components with common method signatures.
  • cgp_preset! macro improvement: Now supports wrapping of Preset::Provider.
  • #[cgp_component] macro improvement: Now supports automated derivation of UseDelegate.
  • Improved Documentation: Added inline Rust documentation for common CGP constructs.

Below we will go through some of the most significant changes in this release.

New cgp-handler Crate

This release introduces a new cgp-handler crate, which offers abstract interfaces for defining components with common method signatures. This helps in creating reusable and composable handlers for various tasks.

As a semi-stable and non-essential crate, the cgp-handler crate is re-exported by cgp-extra, and is available from cgp::extra::handler.

The introduction of cgp-handler is mainly to support the development of Hypershell, which makes heavy use of the Handler component to design and implement its DSL providers.

The crate introduces three main components: Handler, Computer, and Producer.

Handler

The Handler component provides the most commonly used interface for performing asynchronous operations that may fail:

#[cgp_component(Handler)]
#[async_trait]
pub trait CanHandle<Code: Send, Input: Send>: HasAsyncErrorType {
    type Output: Send;

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

Computer

The Computer component mirrors a pure function that takes some input, performs some computation, and produces an output.

#[cgp_component(Computer)]
pub trait CanCompute<Code, Input> {
    type Output;

    fn compute(&self, _tag: PhantomData<Code>, input: Input) -> Self::Output;
}

Producer

The Producer component mirrors a global singleton function to produce an output value. It is useful to emulate global values that cannot be constructed through the const context in Rust, such as String.

#[cgp_component(Producer)]
pub trait CanProduce<Code> {
    type Output;

    fn produce(&self, _tag: PhantomData<Code>) -> Self::Output;
}

Code Parameter

All the traits in cgp-handler contain a phantom Code parameter that can be used for building type-level DSLs such as Hypershell. They can also be used as type-level identifiers for dispatching, such as in API handlers.

cgp_preset! Macro Improvements

This release also brings minor improvements to our cgp_preset! macro, supporting the definition of CGP presets for more diverse use cases.

Support for Wrapping Preset::Provider in cgp_preset!

The cgp_preset! macro now allows users to specify a #[wrap_provider] attribute to wrap the Preset::Provider type. This is particularly useful when using CGP presets to define extensible mappings for generic dispatch through the UseDelegate pattern.

Wrapping the provider makes it easier to extend non-provider mappings across multiple levels of preset inheritance. The wrapped Preset::Provider type will implement the expected provider trait, making it a valid delegation target.

Example

Given the following preset definition:

cgp_preset! {
    #[wrap_provider(UseDelegate)]
    MyHandlerPreset {
        String: HandleString,
        u64: HandleU64,
        ...
    }
}

The macro generates the following implementation:

pub mod MyHandlerPreset {
    ...

    pub type Provider = UseDelegate<Components>;

    delegate_components! {
        new Components {
            String: HandleString,
            u64: HandleU64,
            ...
        }
    }

    ...
}

Automated UseDelegate Derivation in #[cgp_component]

The #[cgp_component] family of macros now includes a derive_delegate field, which allows for the automated implementation of UseDelegate for CGP components. This reduces boilerplate code that was previously required to be implemented manually.

Example

The updated ErrorRaiser component can now be defined as:

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

This will automatically derive the UseDelegate implementation:

#[cgp_provider(ErrorRaiserComponent)]
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(e: SourceError) -> Context::Error {
        Delegate::raise_error(e)
    }
}

Other Improvements

This release also includes several other minor improvements and fixes:

  • Improved Documentation: We have added inline Rust documentation for many common CGP constructs, making it easier for developers to understand and use them. This is part of our ongoing effort to improve the developer experience.
  • Static Char Formatting: The Char type can now be formatted statically without requiring self, which allows type-level strings to be formatted without constructing any value.
  • Use __Self__ instead of T when deriving Preset::IsPreset to avoid identifier conflicts when users use T in their generic parameters.
  • Included trait bound identifiers in Preset::components re-export.

We hope you enjoy the new features and improvements in this release. As always, we welcome feedback and contributions from the community. Check out the project on GitHub and the full changelog for more details.