Skip to content

Commit 3981b41

Browse files
committed
Use delegate_and_checks! to simplify examples
1 parent 5f5cb71 commit 3981b41

3 files changed

Lines changed: 58 additions & 33 deletions

File tree

content/associated-types.md

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ pub mod contexts {
8484
pub auth_tokens_store: BTreeMap<String, u64>,
8585
}
8686

87-
delegate_components! {
87+
delegate_and_check_components! {
88+
CanUseMockApp for MockApp;
8889
MockAppComponents {
8990
CurrentTimeGetterComponent: GetSystemTimestamp,
9091
AuthTokenValidatorComponent: ValidateTokenIsNotExpired,
@@ -104,12 +105,6 @@ pub mod contexts {
104105
.ok_or_else(|| anyhow!("invalid auth token"))
105106
}
106107
}
107-
108-
check_components! {
109-
CanUseMockApp for MockApp {
110-
AuthTokenValidatorComponent,
111-
}
112-
}
113108
}
114109
#
115110
# }
@@ -663,7 +658,8 @@ pub mod contexts {
663658
pub auth_tokens_store: BTreeMap<String, LocalDateTime>,
664659
}
665660

666-
delegate_components! {
661+
delegate_and_check_components! {
662+
CanUseMockApp for MockApp;
667663
MockAppComponents {
668664
[
669665
TimeTypeProviderComponent,
@@ -687,13 +683,6 @@ pub mod contexts {
687683
.ok_or_else(|| anyhow!("invalid auth token"))
688684
}
689685
}
690-
691-
692-
check_components! {
693-
CanUseMockApp for MockApp {
694-
AuthTokenValidatorComponent,
695-
}
696-
}
697686
}
698687
#
699688
# }

content/component-macros.md

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,55 @@ impl CanUseContext for Context {}
361361

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

364+
## `delegate_and_check_components!` Macro
365+
366+
The `delegate_and_check_components!` macro combines both calls to `delegate_components!` and `check_components!`, so that wiring checks are done as soon as a delegate entry is added. This can simplify the boilerplate required to duplicate the code of listing all components in both delegate and check entries.
367+
368+
Given the following:
369+
370+
```rust,ignore
371+
delegate_and_check_components! {
372+
CanUseContext for Context;
373+
ContextComponents {
374+
ComponentA: ProviderA,
375+
ComponentB: ProviderB,
376+
[
377+
ComponentC1,
378+
ComponentC2,
379+
...
380+
]: ProviderC,
381+
}
382+
}
383+
```
384+
385+
The macro would expand into the equivalent of:
386+
387+
```rust,ignore
388+
delegate_components! {
389+
ContextComponents {
390+
ComponentA: ProviderA,
391+
ComponentB: ProviderB,
392+
[
393+
ComponentC1,
394+
ComponentC2,
395+
...
396+
]: ProviderC,
397+
}
398+
}
399+
400+
check_components! {
401+
CanUseContext for Context {
402+
ComponentA,
403+
ComponentB,
404+
ComponentC1,
405+
ComponentC2,
406+
}
407+
}
408+
```
409+
410+
You may wonder why we need define a separate macro, instead of always checking the wiring directly inside `delegate_components!`. The main reason is that while `delegate_and_check_components!` can work for the simple cases, it is more limited and cannot handle well on advanced cases where the CGP traits contain additional generic parameters. For such cases, it is still better to call `delegate_components!` and `check_components!` separately.
411+
412+
364413
## Example Use
365414

366415
To illustrate how `cgp_component` and `delegate_components` can be
@@ -428,31 +477,23 @@ impl HasCgpProvider for Person {
428477
type CgpProvider = PersonComponents;
429478
}
430479

431-
delegate_components! {
480+
delegate_and_check_components! {
481+
CanUsePerson for Person;
432482
PersonComponents {
433483
StringFormatterComponent:
434484
FormatAsJsonString,
435485
StringParserComponent:
436486
ParseFromJsonString,
437487
}
438488
}
439-
440-
check_components! {
441-
CanUsePerson for Person {
442-
StringFormatterComponent,
443-
StringParserComponent,
444-
}
445-
}
446489
```
447490

448491
As we can see, the new code is significantly simpler and more readable than before.
449492
Using `#[cgp_component]`, we no longer need to explicitly define the provider traits `StringFormatter` and `StringParser`, and the blanket implementations can be omitted.
450493

451494
With `#[cgp_new_provider]`, the `IsProviderFor` implementations for `FormatAsJsonString` and `ParseFromJsonString` are automatically implemented, together with the struct definitions.
452495

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.
496+
We also make use of `delegate_and_check_components!` on `PersonComponents` to delegate `StringFormatterComponent` to `FormatAsJsonString`, and `StringParserComponent` to `ParseFromJsonString`, and then check to ensure that the wirings are implemented correctly for the `Person` context.
456497

457498
## CGP Macros as Language Extension
458499

content/error-handling.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,8 @@ pub mod contexts {
497497
pub auth_tokens_store: BTreeMap<String, LocalDateTime>,
498498
}
499499

500-
delegate_components! {
500+
delegate_and_check_components! {
501+
CanUseMockApp for MockApp;
501502
MockAppComponents {
502503
ErrorTypeProviderComponent:
503504
UseAnyhowError,
@@ -525,12 +526,6 @@ pub mod contexts {
525526
.ok_or_else(|| anyhow!("invalid auth token"))
526527
}
527528
}
528-
529-
check_components! {
530-
CanUseMockApp for MockApp {
531-
AuthTokenValidatorComponent,
532-
}
533-
}
534529
}
535530
#
536531
# }

0 commit comments

Comments
 (0)