actix_service/
apply_cfg.rs

1use alloc::rc::Rc;
2use core::{
3    future::Future,
4    marker::PhantomData,
5    pin::Pin,
6    task::{Context, Poll},
7};
8
9use futures_core::ready;
10use pin_project_lite::pin_project;
11
12use crate::{Service, ServiceFactory};
13
14/// Convert `Fn(Config, &Service1) -> Future<Service2>` fn to a service factory.
15pub fn apply_cfg<S1, Req, F, Cfg, Fut, S2, Err>(
16    srv: S1,
17    f: F,
18) -> impl ServiceFactory<
19    Req,
20    Config = Cfg,
21    Response = S2::Response,
22    Error = S2::Error,
23    Service = S2,
24    InitError = Err,
25    Future = Fut,
26> + Clone
27where
28    S1: Service<Req>,
29    F: Fn(Cfg, &S1) -> Fut,
30    Fut: Future<Output = Result<S2, Err>>,
31    S2: Service<Req>,
32{
33    ApplyConfigService {
34        srv: Rc::new((srv, f)),
35        _phantom: PhantomData,
36    }
37}
38
39/// Convert `Fn(Config, &ServiceFactory1) -> Future<ServiceFactory2>` fn to a service factory.
40///
41/// Service1 get constructed from `T` factory.
42pub fn apply_cfg_factory<SF, Req, F, Cfg, Fut, S>(
43    factory: SF,
44    f: F,
45) -> impl ServiceFactory<
46    Req,
47    Config = Cfg,
48    Response = S::Response,
49    Error = S::Error,
50    Service = S,
51    InitError = SF::InitError,
52> + Clone
53where
54    SF: ServiceFactory<Req, Config = ()>,
55    F: Fn(Cfg, &SF::Service) -> Fut,
56    SF::InitError: From<SF::Error>,
57    Fut: Future<Output = Result<S, SF::InitError>>,
58    S: Service<Req>,
59{
60    ApplyConfigServiceFactory {
61        srv: Rc::new((factory, f)),
62        _phantom: PhantomData,
63    }
64}
65
66/// Convert `Fn(Config, &Server) -> Future<Service>` fn to NewService\
67struct ApplyConfigService<S1, Req, F, Cfg, Fut, S2, Err>
68where
69    S1: Service<Req>,
70    F: Fn(Cfg, &S1) -> Fut,
71    Fut: Future<Output = Result<S2, Err>>,
72    S2: Service<Req>,
73{
74    srv: Rc<(S1, F)>,
75    _phantom: PhantomData<(Cfg, Req, Fut, S2)>,
76}
77
78impl<S1, Req, F, Cfg, Fut, S2, Err> Clone for ApplyConfigService<S1, Req, F, Cfg, Fut, S2, Err>
79where
80    S1: Service<Req>,
81    F: Fn(Cfg, &S1) -> Fut,
82    Fut: Future<Output = Result<S2, Err>>,
83    S2: Service<Req>,
84{
85    fn clone(&self) -> Self {
86        ApplyConfigService {
87            srv: self.srv.clone(),
88            _phantom: PhantomData,
89        }
90    }
91}
92
93impl<S1, Req, F, Cfg, Fut, S2, Err> ServiceFactory<Req>
94    for ApplyConfigService<S1, Req, F, Cfg, Fut, S2, Err>
95where
96    S1: Service<Req>,
97    F: Fn(Cfg, &S1) -> Fut,
98    Fut: Future<Output = Result<S2, Err>>,
99    S2: Service<Req>,
100{
101    type Response = S2::Response;
102    type Error = S2::Error;
103    type Config = Cfg;
104    type Service = S2;
105
106    type InitError = Err;
107    type Future = Fut;
108
109    fn new_service(&self, cfg: Cfg) -> Self::Future {
110        let (t, f) = &*self.srv;
111        f(cfg, t)
112    }
113}
114
115/// Convert `Fn(&Config) -> Future<Service>` fn to NewService
116struct ApplyConfigServiceFactory<SF, Req, F, Cfg, Fut, S>
117where
118    SF: ServiceFactory<Req, Config = ()>,
119    F: Fn(Cfg, &SF::Service) -> Fut,
120    Fut: Future<Output = Result<S, SF::InitError>>,
121    S: Service<Req>,
122{
123    srv: Rc<(SF, F)>,
124    _phantom: PhantomData<(Cfg, Req, Fut, S)>,
125}
126
127impl<SF, Req, F, Cfg, Fut, S> Clone for ApplyConfigServiceFactory<SF, Req, F, Cfg, Fut, S>
128where
129    SF: ServiceFactory<Req, Config = ()>,
130    F: Fn(Cfg, &SF::Service) -> Fut,
131    Fut: Future<Output = Result<S, SF::InitError>>,
132    S: Service<Req>,
133{
134    fn clone(&self) -> Self {
135        Self {
136            srv: self.srv.clone(),
137            _phantom: PhantomData,
138        }
139    }
140}
141
142impl<SF, Req, F, Cfg, Fut, S> ServiceFactory<Req>
143    for ApplyConfigServiceFactory<SF, Req, F, Cfg, Fut, S>
144where
145    SF: ServiceFactory<Req, Config = ()>,
146    SF::InitError: From<SF::Error>,
147    F: Fn(Cfg, &SF::Service) -> Fut,
148    Fut: Future<Output = Result<S, SF::InitError>>,
149    S: Service<Req>,
150{
151    type Response = S::Response;
152    type Error = S::Error;
153    type Config = Cfg;
154    type Service = S;
155
156    type InitError = SF::InitError;
157    type Future = ApplyConfigServiceFactoryResponse<SF, Req, F, Cfg, Fut, S>;
158
159    fn new_service(&self, cfg: Cfg) -> Self::Future {
160        ApplyConfigServiceFactoryResponse {
161            cfg: Some(cfg),
162            store: self.srv.clone(),
163            state: State::A {
164                fut: self.srv.0.new_service(()),
165            },
166        }
167    }
168}
169
170pin_project! {
171    struct ApplyConfigServiceFactoryResponse<SF, Req, F, Cfg, Fut, S>
172    where
173        SF: ServiceFactory<Req, Config = ()>,
174        SF::InitError: From<SF::Error>,
175        F: Fn(Cfg, &SF::Service) -> Fut,
176        Fut: Future<Output = Result<S, SF::InitError>>,
177        S: Service<Req>,
178    {
179        cfg: Option<Cfg>,
180        store: Rc<(SF, F)>,
181        #[pin]
182        state: State<SF, Fut, S, Req>,
183    }
184}
185
186pin_project! {
187    #[project = StateProj]
188    enum State<SF, Fut, S, Req>
189    where
190        SF: ServiceFactory<Req, Config = ()>,
191        SF::InitError: From<SF::Error>,
192        Fut: Future<Output = Result<S, SF::InitError>>,
193        S: Service<Req>,
194    {
195        A { #[pin] fut: SF::Future },
196        B { svc: SF::Service },
197        C { #[pin] fut: Fut },
198    }
199}
200
201impl<SF, Req, F, Cfg, Fut, S> Future for ApplyConfigServiceFactoryResponse<SF, Req, F, Cfg, Fut, S>
202where
203    SF: ServiceFactory<Req, Config = ()>,
204    SF::InitError: From<SF::Error>,
205    F: Fn(Cfg, &SF::Service) -> Fut,
206    Fut: Future<Output = Result<S, SF::InitError>>,
207    S: Service<Req>,
208{
209    type Output = Result<S, SF::InitError>;
210
211    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
212        let mut this = self.as_mut().project();
213
214        match this.state.as_mut().project() {
215            StateProj::A { fut } => {
216                let svc = ready!(fut.poll(cx))?;
217                this.state.set(State::B { svc });
218                self.poll(cx)
219            }
220            StateProj::B { svc } => {
221                ready!(svc.poll_ready(cx))?;
222                {
223                    let (_, f) = &**this.store;
224                    let fut = f(this.cfg.take().unwrap(), svc);
225                    this.state.set(State::C { fut });
226                }
227                self.poll(cx)
228            }
229            StateProj::C { fut } => fut.poll(cx),
230        }
231    }
232}