Skip to main content

cgp_monad/providers/
pipe_monadic.rs

1use cgp_core::field::traits::MapFields;
2use cgp_core::prelude::*;
3use cgp_handler::{
4    AsyncComputerComponent, ComposeHandlers, ComputerComponent, HandlerComponent,
5    TryComputerComponent, TryPromote,
6};
7
8use crate::monadic::err::ErrMonadic;
9use crate::traits::{MonadicBind, MonadicTrans};
10
11pub struct PipeMonadic<M, Providers>(pub PhantomData<(M, Providers)>);
12
13delegate_components! {
14    <Provider, M, Providers: BindProviders<M, Provider = Provider>>
15    PipeMonadic<M, Providers> {
16        [
17            ComputerComponent,
18            AsyncComputerComponent,
19        ]: Provider,
20    }
21}
22
23// Support monadic piping of TryComputer by first demoting them to Computer,
24// together with a monad transformer application of ErrMonadic to the base monad,
25// compose them, and then TryPromote them again back into TryComputer.
26
27delegate_components! {
28    <
29        Provider,
30        M1: MonadicTrans<ErrMonadic, M = M2>,
31        M2,
32        ProvidersA: MapFields<TryPromoteProviders, Mapped = ProvidersB>,
33        ProvidersB: BindProviders<M2, Provider = Provider>,
34    >
35    PipeMonadic<M1, ProvidersA> {
36        TryComputerComponent: TryPromote<Provider>,
37        HandlerComponent: TryPromote<Provider>,
38    }
39}
40
41pub struct TryPromoteProviders;
42
43impl MapType for TryPromoteProviders {
44    type Map<Provider> = TryPromote<Provider>;
45}
46
47trait BindProviders<M> {
48    type Provider;
49}
50
51impl<M, ProviderA, ProviderB, RestProviders, OutProviders> BindProviders<M>
52    for Cons<ProviderA, Cons<ProviderB, RestProviders>>
53where
54    Cons<ProviderB, RestProviders>: BindProviders<M, Provider = OutProviders>,
55    M: MonadicBind<OutProviders>,
56{
57    type Provider = ComposeHandlers<ProviderA, M::Provider>;
58}
59
60impl<M, Provider> BindProviders<M> for Cons<Provider, Nil> {
61    type Provider = Provider;
62}