1use alloc::{rc::Rc, sync::Arc};
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::{IntoServiceFactory, Service, ServiceFactory};
13
14pub fn apply<T, S, I, Req>(t: T, factory: I) -> ApplyTransform<T, S, Req>
16where
17 I: IntoServiceFactory<S, Req>,
18 S: ServiceFactory<Req>,
19 T: Transform<S::Service, Req, InitError = S::InitError>,
20{
21 ApplyTransform::new(t, factory.into_factory())
22}
23
24pub trait Transform<S, Req> {
84 type Response;
86
87 type Error;
89
90 type Transform: Service<Req, Response = Self::Response, Error = Self::Error>;
92
93 type InitError;
95
96 type Future: Future<Output = Result<Self::Transform, Self::InitError>>;
98
99 fn new_transform(&self, service: S) -> Self::Future;
101}
102
103impl<T, S, Req> Transform<S, Req> for Rc<T>
104where
105 T: Transform<S, Req>,
106{
107 type Response = T::Response;
108 type Error = T::Error;
109 type Transform = T::Transform;
110 type InitError = T::InitError;
111 type Future = T::Future;
112
113 fn new_transform(&self, service: S) -> T::Future {
114 self.as_ref().new_transform(service)
115 }
116}
117
118impl<T, S, Req> Transform<S, Req> for Arc<T>
119where
120 T: Transform<S, Req>,
121{
122 type Response = T::Response;
123 type Error = T::Error;
124 type Transform = T::Transform;
125 type InitError = T::InitError;
126 type Future = T::Future;
127
128 fn new_transform(&self, service: S) -> T::Future {
129 self.as_ref().new_transform(service)
130 }
131}
132
133pub struct ApplyTransform<T, S, Req>(Rc<(T, S)>, PhantomData<Req>);
135
136impl<T, S, Req> ApplyTransform<T, S, Req>
137where
138 S: ServiceFactory<Req>,
139 T: Transform<S::Service, Req, InitError = S::InitError>,
140{
141 fn new(t: T, service: S) -> Self {
143 Self(Rc::new((t, service)), PhantomData)
144 }
145}
146
147impl<T, S, Req> Clone for ApplyTransform<T, S, Req> {
148 fn clone(&self) -> Self {
149 ApplyTransform(self.0.clone(), PhantomData)
150 }
151}
152
153impl<T, S, Req> ServiceFactory<Req> for ApplyTransform<T, S, Req>
154where
155 S: ServiceFactory<Req>,
156 T: Transform<S::Service, Req, InitError = S::InitError>,
157{
158 type Response = T::Response;
159 type Error = T::Error;
160
161 type Config = S::Config;
162 type Service = T::Transform;
163 type InitError = T::InitError;
164 type Future = ApplyTransformFuture<T, S, Req>;
165
166 fn new_service(&self, cfg: S::Config) -> Self::Future {
167 ApplyTransformFuture {
168 store: self.0.clone(),
169 state: ApplyTransformFutureState::A {
170 fut: self.0.as_ref().1.new_service(cfg),
171 },
172 }
173 }
174}
175
176pin_project! {
177 pub struct ApplyTransformFuture<T, S, Req>
178 where
179 S: ServiceFactory<Req>,
180 T: Transform<S::Service, Req, InitError = S::InitError>,
181 {
182 store: Rc<(T, S)>,
183 #[pin]
184 state: ApplyTransformFutureState<T, S, Req>,
185 }
186}
187
188pin_project! {
189 #[project = ApplyTransformFutureStateProj]
190 pub enum ApplyTransformFutureState<T, S, Req>
191 where
192 S: ServiceFactory<Req>,
193 T: Transform<S::Service, Req, InitError = S::InitError>,
194 {
195 A { #[pin] fut: S::Future },
196 B { #[pin] fut: T::Future },
197 }
198}
199
200impl<T, S, Req> Future for ApplyTransformFuture<T, S, Req>
201where
202 S: ServiceFactory<Req>,
203 T: Transform<S::Service, Req, InitError = S::InitError>,
204{
205 type Output = Result<T::Transform, T::InitError>;
206
207 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
208 let mut this = self.as_mut().project();
209
210 match this.state.as_mut().project() {
211 ApplyTransformFutureStateProj::A { fut } => {
212 let srv = ready!(fut.poll(cx))?;
213 let fut = this.store.0.new_transform(srv);
214 this.state.set(ApplyTransformFutureState::B { fut });
215 self.poll(cx)
216 }
217 ApplyTransformFutureStateProj::B { fut } => fut.poll(cx),
218 }
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use core::time::Duration;
225
226 use actix_utils::future::{ready, Ready};
227
228 use super::*;
229
230 #[allow(unused)]
232 pub struct TimeoutTransform {
233 timeout: Duration,
234 }
235
236 impl<S: Service<Req>, Req> Transform<S, Req> for TimeoutTransform {
238 type Response = S::Response;
239 type Error = S::Error;
240 type InitError = S::Error;
241 type Transform = Timeout<S>;
242 type Future = Ready<Result<Self::Transform, Self::InitError>>;
243
244 fn new_transform(&self, service: S) -> Self::Future {
245 ready(Ok(Timeout {
246 service,
247 _timeout: self.timeout,
248 }))
249 }
250 }
251
252 #[allow(unused)]
254 pub struct Timeout<S> {
255 service: S,
256 _timeout: Duration,
257 }
258
259 impl<S: Service<Req>, Req> Service<Req> for Timeout<S> {
261 type Response = S::Response;
262 type Error = S::Error;
263 type Future = S::Future;
264
265 crate::forward_ready!(service);
266
267 fn call(&self, req: Req) -> Self::Future {
268 self.service.call(req)
269 }
270 }
271}