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