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}