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 = ()> {}