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
14pub 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
39pub 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
66struct 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
115struct 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}