You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The `delegate_components!` macro accepts an argument to an existing type,
192
235
`TargetProvider`, which is expected to be defined outside of the macro.
193
236
It is followed by an open brace, and contain entries that look like
194
-
key-value pairs. For a key-value pair `ComponentA: ProviderA`, the type
195
-
`ComponentA` is used as the component name, and `ProviderA` refers to
196
-
the provider implementation.
237
+
key-value pairs.
238
+
239
+
For a key-value pair `ComponentA: ProviderA`, the type `ComponentA` is used as the component name, and `ProviderA` refers to the provider implementation.
197
240
When multiple keys map to the same value, i.e. multiple components are
198
241
delegated to the same provider implementation, the array syntax can be
199
242
used to further simplify the mapping.
200
243
244
+
Instead of defining the provider struct on our own, we can also instruct `delegate_components!` to also define the provider struct for us, by adding a `new` keyword in front:
245
+
246
+
```rust,ignore
247
+
delegate_components! {
248
+
new TargetProvider {
249
+
ComponentA: ProviderA,
250
+
ComponentB: ProviderB,
251
+
[
252
+
ComponentC1,
253
+
ComponentC2,
254
+
...
255
+
]: ProviderC,
256
+
}
257
+
}
258
+
```
259
+
260
+
## `#[cgp_provider]` Macro
261
+
262
+
When implementing a provider, the `#[cgp_provider]` macro needs to be used to automatically implement the `IsProviderFor` implementation, with all constraints within the `impl` block copied over.
263
+
264
+
Given a provider trait implementation with the pattern:
265
+
266
+
```rust,ignore
267
+
pub struct Provider;
268
+
269
+
#[cgp_provider(ActionPerformerComponent)]
270
+
impl<Context, GenericA, GenericB, ...>
271
+
ActionPerformer<Context, GenericA, GenericB, ...>
272
+
for Provider
273
+
where
274
+
Context: ConstraintA + ConstraintB + ...,
275
+
Context::Assoc: ConstraintC + ConstraintD + ...,
276
+
{ ... }
277
+
```
278
+
279
+
`#[cgp_provider]` would generate an `IsProviderFor` implementation that follows the pattern:
If the component name for the provider trait follows the format `"{ProviderTraitName}Component"`, then the component name can be omitted in the attribute argument for `#[cgp_provider]`, simplifying the code to:
292
+
293
+
```rust,ignore
294
+
pub struct Provider;
295
+
296
+
#[cgp_provider]
297
+
impl<Context, GenericA, GenericB, ...>
298
+
ActionPerformer<Context, GenericA, GenericB, ...>
299
+
for Provider
300
+
where
301
+
Context: ConstraintA + ConstraintB + ...,
302
+
Context::Assoc: ConstraintC + ConstraintD + ...,
303
+
{ ... }
304
+
```
305
+
306
+
Note, however, that the generated code would require the component type `"{ProviderTraitName}Component"` to be imported into scope. If the component name is not specified, IDEs like Rust Analyzer may not provide quick fix for auto importing the component. As a result, it may still be preferrable to include the component name attribute, especially when writing new code.
307
+
308
+
There is also a variant of the macro, `#[cgp_new_provider]`, which would also automatically define the struct for the provider. With that, the code can be defined with the `struct` definition omitted:
309
+
310
+
```rust,ignore
311
+
#[cgp_new_provider]
312
+
impl<Context, GenericA, GenericB, ...>
313
+
ActionPerformer<Context, GenericA, GenericB, ...>
314
+
for Provider
315
+
where
316
+
Context: ConstraintA + ConstraintB + ...,
317
+
Context::Assoc: ConstraintC + ConstraintD + ...,
318
+
{ ... }
319
+
```
320
+
321
+
`#[cgp_new_provider]` is mainly useful in cases where a provider only implements one provider trait. When definining a provider with multiple provider trait implementations, it may be more clear to define the provider struct explicitly, or only use `#[cgp_new_provider]` for the first `impl` block of the provider.
322
+
323
+
## `check_components!` Macro
324
+
325
+
To help with debugging CGP code, the `check_components!` macro is provided to allow us to quickly write compile-time tests on the component wiring.
The `check_components!` macro allows the use of array syntax at either the key or value position, when there are multiple components that share the same set of generic parameters.
363
+
201
364
## Example Use
202
365
203
366
To illustrate how `cgp_component` and `delegate_components` can be
@@ -219,29 +382,19 @@ use serde::{Serialize, Deserialize};
As we can see, the new code is significantly simpler and more readable than before.
302
-
Using `cgp_component`, we no longer need to explicitly define the provider
303
-
traits `StringFormatter` and `StringParser`, and the blanket implementations
304
-
can be omitted. We also make use of `delegate_components!` on `PersonComponents`
305
-
to delegate `StringFormatterComponent` to `FormatAsJsonString`, and
306
-
`StringParserComponent` to `ParseFromJsonString`.
449
+
Using `#[cgp_component]`, we no longer need to explicitly define the provider traits `StringFormatter` and `StringParser`, and the blanket implementations can be omitted.
450
+
451
+
With `#[cgp_new_provider]`, the `IsProviderFor` implementations for `FormatAsJsonString` and `ParseFromJsonString` are automatically implemented, together with the struct definitions.
452
+
453
+
We also make use of `delegate_components!` on `PersonComponents` to delegate `StringFormatterComponent` to `FormatAsJsonString`, and `StringParserComponent` to `ParseFromJsonString`.
454
+
455
+
Finally, the `check_components!` macro helps us check that we can in fact use `StringFormatterComponent` and `StringParserComponent` with the `Person` context.
0 commit comments