Skip to main content

cgp_component/providers/
use_delegate.rs

1use core::marker::PhantomData;
2
3/**
4    The `UseDelegate` pattern is used as the _default dispatcher_ for CGP
5    components that contain additional generic parameters in their traits.
6
7    When a provider trait contains additional generic parameters in addition
8    to the `Context` type, CGP can generate a `UseDelegate` implementation
9    that uses `Components` as a _type-level lookup table_ to dispatch the
10    implementation to different providers based on the generic types.
11
12    The implementation of `UseDelegate` follows the same pattern as the
13    blanket implementation of a provider trait. However, instead of using
14    the component name type as the key, it uses the specified generic
15    parameters as the key to lookup the provider through `DelegateComponent`.
16
17    `UseDelegate` is very commonly used to perform ad hoc dispatch of
18    concrete types to different context-generic providers. This allows the
19    providers to remain generic, even when they may have implementations
20    that overlaps on the generic parameters.
21
22    The implementation of `UseDelegate` can be automatically generated through
23    the `#[derive_delegate]` attribute in `#[cgp_component]`. It is also possible to
24    implement the dispatcher pattern on types other than `UseDelegate`, especially
25    when there are multiple generic parameters that could be dispatched differently.
26    We mainly use `UseDelegate` as the default dispatcher, so that users don't need
27    to remember the different provider types to be used with each component.
28
29    ## Example
30
31    Given the following component definition:
32
33    ```rust,ignore
34    #[cgp_component(ErrorRaiser)]
35    #[derive_delegate(UseDelegate<SourceError>)]
36    pub trait CanRaiseError<SourceError>: HasErrorType {
37        fn raise_error(error: SourceError) -> Self::Error;
38    }
39    ```
40
41    The following `UseDelegate` implementation would be generated:
42
43    ```rust,ignore
44    impl<Context, SourceError, Components, Delegate> ErrorRaiser<Context, SourceError>
45        for UseDelegate<Components>
46    where
47        Context: HasErrorType,
48        Components: DelegateComponent<(SourceError), Delegate = Delegate>,
49        Delegate: ErrorRaiser<Context, SourceError>,
50    {
51        fn raise_error(error: SourceError) -> Context::Error {
52            Delegate::raise_error(error)
53        }
54    }
55    ```
56*/
57pub struct UseDelegate<Components>(pub PhantomData<Components>);