1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/**
The `IsProviderFor` trait is used to propagate the constraints required to
implement the provider trait that corresponds to the `Component` type.
## Parameters
The `IsProviderFor` trait parameters are used as follows:
- `Component`: The component name type that corresponds to the provider trait.
- `Context`: The `Context` type used in the provider trait.
- `Params`: Any additional generic parameters in the provider trait, with
multiple generic parameters grouped inside a tuple.
## `IsProviderFor` as a constraint carrier
The trait definition for `IsProviderFor` has an empty body that can be trivially
implemented. However, when used with `#[cgp_provider]` or `#[cgp_new_provider]`,
on a provider trait implementation, it would be implemented by the `Provider` type
with the same set of constraints as the provider trait implementation.
The `IsProviderFor` trait is included as a supertrait of all CGP provider traits
generated from `#[cgp_component]`. This means that when there is any unsatisfied
constraint in the provider trait implementation, it would also result in the
same error shown in the `IsProviderFor` implementation.
## Why is this trait necessary?
The trait is necessary to force the Rust compiler to show any relevant error message
when there are unsatisfied constraints in the provider trait implementation. By default,
Rust would hide the error messages from the provider trait implementation, because there
is also an alternative candidate implementation available, which is the blanket
implementation of the provider trait.
On the other hand, the `IsProviderFor` trait is explicitly propagated inside
`delegate_components!`, together with `DelegateComponent`. Because of this different
implementation path, we are able to "unhide" the error messages that were hidden away
by Rust.
## Example Definition
Given a CGP trait definition such as:
```rust,ignore
#[cgp_component(FooGetterAt)]
pub trait CanGetFooAt<I, J> {
fn foo_at(&self, _phantom: PhantomData<(I, J)>) -> u64;
}
```
The following provider trait would be generated with the `IsProviderFor` supertrait:
```rust,ignore
pub trait FooGetterAt<Context, I, J>:
IsProviderFor<FooGetterAtComponent, Context, (I, J)>
{
fn foo_at(context: &Context, _phantom: PhantomData<(I, J)>) -> u64;
}
```
## Example Implementation
Given a provider trait implementation such as:
```rust,ignore
#[cgp_provider(FooGetterAt)]
impl<I, J> FooGetterAt<Context, I, J> for GetFooValue
where
Context: HasField<symbol!("foo"), Value = u64>,
{
fn foo_at(context: &Context, _phantom: PhantomData<(I, J)>) -> u64 {
context.get_field(PhantomData)
}
}
```
The following implementation for `IsProviderFor` would be generated:
```rust,ignore
impl<Context, I, J>
IsProviderFor<FooGetterAtComponent, Context, (I, J)>
for GetFooValue
where
Context: HasField<symbol!("foo"), Value = u64>,
{
}
```
## Example Delegation
Given a component delegation such as:
```rust,ignore
delegate_component! {
MyAppComponents {
FooGetterAtComponent: GetFooValue,
}
}
```
The following `IsProviderFor` implementation would be generated:
```rust,ignore
impl<Context, Params>
IsProviderFor<FooGetterAtComponent, Context, Params>
for MyAppComponents
where
GetFooValue: IsProviderFor<FooGetterAtComponent, Context, Params>,
{
}
```
This means that `MyAppComponents` has an explicit implementation of `IsProviderFor`
for all possible `Context` and `Params`, with the `where` constraint propagating
the constraints coming from `GetFooValue` with the same `Context` and `Params`.
Because of this is an explicit implementation and not a blanket implementation,
Rust would follow the implementation path and surface all unsatisfied constraints
from `GetFooValue`.
*/