|
| 1 | ++++ |
| 2 | + |
| 3 | +title = "CGP v0.4.1 Release" |
| 4 | + |
| 5 | +description = "Announcing the release of CGP v0.4.1, with new features like the cgp-handler crate, improved preset macros, and more." |
| 6 | + |
| 7 | +authors = ["Soares Chen"] |
| 8 | + |
| 9 | ++++ |
| 10 | + |
| 11 | +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`. |
| 12 | + |
| 13 | +Here are some of the highlights: |
| 14 | + |
| 15 | +- **New `cgp-handler` crate**: Provides abstract interfaces for defining components with common method signatures. |
| 16 | +- **`cgp_preset!` macro improvement**: Now supports wrapping of `Preset::Provider`. |
| 17 | +- **`#[cgp_component]` macro improvement**: Now supports automated derivation of `UseDelegate`. |
| 18 | +- **Improved Documentation**: Added inline Rust documentation for common CGP constructs. |
| 19 | + |
| 20 | +Below we will go through some of the most significant changes in this release. |
| 21 | + |
| 22 | +# New `cgp-handler` Crate |
| 23 | + |
| 24 | +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. |
| 25 | + |
| 26 | +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`. |
| 27 | + |
| 28 | +The introduction of `cgp-handler` is mainly to support the development of [Hypershell](/blog/hypershell-release), which makes heavy use of the `Handler` component to design and implement its DSL providers. |
| 29 | + |
| 30 | +The crate introduces three main components: `Handler`, `Computer`, and `Producer`. |
| 31 | + |
| 32 | +## `Handler` |
| 33 | + |
| 34 | +The `Handler` component provides the most commonly used interface for performing asynchronous operations that may fail: |
| 35 | + |
| 36 | +```rust |
| 37 | +#[cgp_component(Handler)] |
| 38 | +#[async_trait] |
| 39 | +pub trait CanHandle<Code: Send, Input: Send>: HasAsyncErrorType { |
| 40 | + type Output: Send; |
| 41 | + |
| 42 | + async fn handle( |
| 43 | + &self, |
| 44 | + _tag: PhantomData<Code>, |
| 45 | + input: Input, |
| 46 | + ) -> Result<Self::Output, Self::Error>; |
| 47 | +} |
| 48 | +``` |
| 49 | + |
| 50 | +## `Computer` |
| 51 | + |
| 52 | +The `Computer` component mirrors a pure function that takes some input, performs some computation, and produces an output. |
| 53 | + |
| 54 | +```rust |
| 55 | +#[cgp_component(Computer)] |
| 56 | +pub trait CanCompute<Code, Input> { |
| 57 | + type Output; |
| 58 | + |
| 59 | + fn compute(&self, _tag: PhantomData<Code>, input: Input) -> Self::Output; |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | +## `Producer` |
| 64 | + |
| 65 | +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`. |
| 66 | + |
| 67 | +```rust |
| 68 | +#[cgp_component(Producer)] |
| 69 | +pub trait CanProduce<Code> { |
| 70 | + type Output; |
| 71 | + |
| 72 | + fn produce(&self, _tag: PhantomData<Code>) -> Self::Output; |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | +## `Code` Parameter |
| 77 | + |
| 78 | +All the traits in `cgp-handler` contain a phantom `Code` parameter that can be used for building type-level DSLs such as [Hypershell](https://github.com/contextgeneric/hypershell). They can also be used as type-level identifiers for dispatching, such as in API handlers. |
| 79 | + |
| 80 | +# `cgp_preset!` Macro Improvements |
| 81 | + |
| 82 | +This release also brings minor improvements to our `cgp_preset!` macro, supporting the definition of CGP presets for more diverse use cases. |
| 83 | + |
| 84 | +## Support for Wrapping `Preset::Provider` in `cgp_preset!` |
| 85 | + |
| 86 | +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. |
| 87 | + |
| 88 | +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. |
| 89 | + |
| 90 | +### Example |
| 91 | + |
| 92 | +Given the following preset definition: |
| 93 | + |
| 94 | +```rust |
| 95 | +cgp_preset! { |
| 96 | + #[wrap_provider(UseDelegate)] |
| 97 | + MyHandlerPreset { |
| 98 | + String: HandleString, |
| 99 | + u64: HandleU64, |
| 100 | + ... |
| 101 | + } |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +The macro generates the following implementation: |
| 106 | + |
| 107 | +```rust |
| 108 | +pub mod MyHandlerPreset { |
| 109 | + ... |
| 110 | + |
| 111 | + pub type Provider = UseDelegate<Components>; |
| 112 | + |
| 113 | + delegate_components! { |
| 114 | + new Components { |
| 115 | + String: HandleString, |
| 116 | + u64: HandleU64, |
| 117 | + ... |
| 118 | + } |
| 119 | + } |
| 120 | + |
| 121 | + ... |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | +## Automated `UseDelegate` Derivation in `#[cgp_component]` |
| 126 | + |
| 127 | +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. |
| 128 | + |
| 129 | +### Example |
| 130 | + |
| 131 | +The updated `ErrorRaiser` component can now be defined as: |
| 132 | + |
| 133 | +```rust |
| 134 | +#[cgp_component { |
| 135 | + provider: ErrorRaiser, |
| 136 | + derive_delegate: UseDelegate<SourceError>, |
| 137 | +}] |
| 138 | +pub trait CanRaiseError<SourceError>: HasErrorType { |
| 139 | + fn raise_error(error: SourceError) -> Self::Error; |
| 140 | +} |
| 141 | +``` |
| 142 | + |
| 143 | +This will automatically derive the `UseDelegate` implementation: |
| 144 | + |
| 145 | +```rust |
| 146 | +#[cgp_provider(ErrorRaiserComponent)] |
| 147 | +impl<Context, SourceError, Components, Delegate> ErrorRaiser<Context, SourceError> |
| 148 | + for UseDelegate<Components> |
| 149 | +where |
| 150 | + Context: HasErrorType, |
| 151 | + Components: DelegateComponent<SourceError, Delegate = Delegate>, |
| 152 | + Delegate: ErrorRaiser<Context, SourceError>, |
| 153 | +{ |
| 154 | + fn raise_error(e: SourceError) -> Context::Error { |
| 155 | + Delegate::raise_error(e) |
| 156 | + } |
| 157 | +} |
| 158 | +``` |
| 159 | + |
| 160 | +# Other Improvements |
| 161 | + |
| 162 | +This release also includes several other minor improvements and fixes: |
| 163 | + |
| 164 | +- **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. |
| 165 | +- **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. |
| 166 | +- Use `__Self__` instead of `T` when deriving `Preset::IsPreset` to avoid identifier conflicts when users use `T` in their generic parameters. |
| 167 | +- Included trait bound identifiers in `Preset::components` re-export. |
| 168 | + |
| 169 | +--- |
| 170 | + |
| 171 | +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](https://github.com/contextgeneric/cgp/) and the full [changelog](https://github.com/contextgeneric/cgp/blob/main/CHANGELOG.md) for more details. |
0 commit comments