service_async/
stack.rs

1use std::sync::Arc;
2
3use crate::{AsyncMakeServiceWrapper, BoxedAsyncMakeService};
4
5use super::{
6    boxed::BoxServiceFactory, layer::FactoryLayer, ArcMakeService, AsyncMakeService,
7    BoxedMakeService, MakeService, MapTargetService, Service,
8};
9/// A powerful abstraction for creating complex service chains by managing a stack of service factories.
10///
11/// `FactoryStack` allows for the composition of multiple `FactoryLayer`s, where each layer
12/// can add functionality, modify behavior of inner layers, or transform the service chain.
13///
14/// The `FactoryStack` works by composing multiple `FactoryLayer`s together. Each layer in the stack
15/// wraps the layers below it, creating a nested structure of factories. When you call `make` or
16/// `make_async` on a `FactoryStack`, it traverses this structure from the outermost layer to the
17/// innermost, creating the complete service chain.
18///
19/// This approach allows users to create complex service factories by chaining multiple factory
20/// layers together in an intuitive manner. Each layer can add its own functionality, modify the
21/// behavior of inner layers, or even completely transform the service chain.
22///
23/// # Usage
24///
25/// To create a chain of services using `FactoryStack`:
26///
27/// 1. Start with a `FactoryStack` initialized with your configuration.
28/// 2. Use the `push` method to add layers to the stack.
29/// 3. Each layer can modify or enhance the behavior of the inner layers.
30/// 4. Finally, call `make` or `make_async` to create the complete service chain.
31///
32/// This system offers a powerful and flexible way to construct and update service chains while
33/// managing state and resources efficiently. It allows for modular, reusable pieces of functionality,
34/// easy reconfiguration of service chains, and clear separation of concerns between different parts
35/// of your service logic.
36///
37/// # Example
38///
39/// ```rust
40/// use service_async::{layer::FactoryLayer, stack::FactoryStack, MakeService, Service};
41///
42/// struct Config { /* ... */ }
43/// struct ServiceA;
44/// struct ServiceB<T>(T);
45///
46/// impl<C> FactoryLayer<C, ()> for ServiceA {
47///     type Factory = Self;
48///     fn layer(&self, _: &C, _: ()) -> Self::Factory { ServiceA }
49/// }
50///
51/// impl<C, T> FactoryLayer<C, T> for ServiceB<T> {
52///     type Factory = Self;
53///     fn layer(&self, _: &C, inner: T) -> Self::Factory { ServiceB(inner) }
54/// }
55///
56/// let config = Config { /* ... */ };
57/// let stack = FactoryStack::new(config)
58///     .push(ServiceA::layer())
59///     .push(ServiceB::layer());
60///
61/// let service = stack.make().expect("Failed to create service");
62/// ```
63///
64/// This example demonstrates how to create a `FactoryStack` with two layers (`ServiceA` and `ServiceB`)
65/// and then use it to create a service.
66pub struct FactoryStack<C, S> {
67    config: C,
68    inner: S,
69}
70
71impl<C> FactoryStack<C, ()> {
72    pub const fn new(config: C) -> Self {
73        FactoryStack { config, inner: () }
74    }
75}
76
77impl<C, F> FactoryStack<C, F> {
78    /// Replace inner with a new factory.
79    #[inline]
80    pub fn replace<NF>(self, factory: NF) -> FactoryStack<C, NF> {
81        FactoryStack {
82            config: self.config,
83            inner: factory,
84        }
85    }
86
87    /// Push a new factory layer.
88    #[inline]
89    pub fn push<L>(self, layer: L) -> FactoryStack<C, L::Factory>
90    where
91        L: FactoryLayer<C, F>,
92    {
93        let inner = layer.layer(&self.config, self.inner);
94        FactoryStack {
95            config: self.config,
96            inner,
97        }
98    }
99
100    /// Convert the factory to an async factory.
101    #[inline]
102    pub fn into_async(self) -> FactoryStack<C, AsyncMakeServiceWrapper<F>> {
103        let inner = AsyncMakeServiceWrapper(self.inner);
104        FactoryStack {
105            config: self.config,
106            inner,
107        }
108    }
109
110    /// Push a new factory of service to map the request type.
111    #[inline]
112    pub fn push_map_target<M: Clone>(self, f: M) -> FactoryStack<C, MapTargetService<F, M>> {
113        FactoryStack {
114            config: self.config,
115            inner: MapTargetService {
116                f,
117                inner: self.inner,
118            },
119        }
120    }
121
122    /// Convert the factory to factory of [`BoxedService`](crate::BoxedService).
123    /// Works for MakeService and AsyncMakeService.
124    #[inline]
125    pub fn into_boxed_service<Req>(self) -> FactoryStack<C, BoxServiceFactory<F, Req>> {
126        FactoryStack {
127            config: self.config,
128            inner: BoxServiceFactory::new(self.inner),
129        }
130    }
131
132    /// Convert the factory to factory of BoxedService.
133    /// Works for MakeService and AsyncMakeService.
134    #[deprecated = "use `into_boxed_service` instead"]
135    #[inline]
136    pub fn push_boxed_service<Req>(self) -> FactoryStack<C, BoxServiceFactory<F, Req>>
137    where
138        F: MakeService,
139        F::Service: Service<Req>,
140    {
141        self.into_boxed_service()
142    }
143
144    /// Convert the factory to a fixed type factory(Box dyn).
145    /// Only works for MakeService.
146    #[inline]
147    pub fn into_boxed_factory(self) -> FactoryStack<C, BoxedMakeService<F::Service, F::Error>>
148    where
149        F: MakeService + Send + Sync + 'static,
150    {
151        FactoryStack {
152            config: self.config,
153            inner: Box::new(self.inner),
154        }
155    }
156
157    /// Convert the factory to a fixed type factory(Box dyn).
158    /// Only works for AsyncMakeService.
159    #[inline]
160    pub fn into_async_boxed_factory(
161        self,
162    ) -> FactoryStack<C, BoxedAsyncMakeService<F::Service, F::Error>>
163    where
164        F: AsyncMakeService + Send + Sync + 'static,
165        F::Service: 'static,
166    {
167        FactoryStack {
168            config: self.config,
169            inner: BoxedAsyncMakeService::new(self.inner),
170        }
171    }
172
173    /// Convert the factory to a fixed type factory(Box dyn).
174    /// Only works for MakeService.
175    #[deprecated = "use `into_boxed_factory` instead"]
176    #[inline]
177    pub fn push_boxed_factory(self) -> FactoryStack<C, BoxedMakeService<F::Service, F::Error>>
178    where
179        F: MakeService + Send + Sync + 'static,
180    {
181        self.into_boxed_factory()
182    }
183
184    /// Convert the factory to a fixed type factory(Arc dyn).
185    /// Only works for MakeService.
186    #[inline]
187    pub fn into_arc_factory(self) -> FactoryStack<C, ArcMakeService<F::Service, F::Error>>
188    where
189        F: MakeService + Send + Sync + 'static,
190    {
191        FactoryStack {
192            config: self.config,
193            inner: Arc::new(self.inner),
194        }
195    }
196
197    /// Convert the factory to a fixed type factory(Arc Box dyn).
198    /// Only works for AsyncMakeService.
199    #[allow(clippy::type_complexity)]
200    #[inline]
201    pub fn into_async_arc_factory(
202        self,
203    ) -> FactoryStack<C, Arc<BoxedAsyncMakeService<F::Service, F::Error>>>
204    where
205        F: AsyncMakeService + Send + Sync + 'static,
206        F::Service: 'static,
207    {
208        FactoryStack {
209            config: self.config,
210            inner: Arc::new(BoxedAsyncMakeService::new(self.inner)),
211        }
212    }
213
214    /// Convert the factory to a fixed type factory(Arc dyn).
215    /// Only works for MakeService.
216    #[deprecated = "use `into_arc_factory` instead"]
217    #[inline]
218    pub fn push_arc_factory(self) -> FactoryStack<C, ArcMakeService<F::Service, F::Error>>
219    where
220        F: MakeService + Send + Sync + 'static,
221    {
222        self.into_arc_factory()
223    }
224
225    /// Check if the stack is a factory of `Service<R>`.
226    #[inline]
227    pub fn check_make_svc<R>(self) -> Self
228    where
229        F: MakeService,
230        F::Service: Service<R>,
231    {
232        self
233    }
234
235    /// Check if the stack is an async factory of `Service<R>`.
236    #[inline]
237    pub fn check_async_make_svc<R>(self) -> Self
238    where
239        F: AsyncMakeService,
240        F::Service: Service<R>,
241    {
242        self
243    }
244
245    /// Get the inner factory.
246    #[inline]
247    pub fn into_inner(self) -> F {
248        self.inner
249    }
250
251    /// Into config and the factory.
252    #[inline]
253    pub fn into_parts(self) -> (C, F) {
254        (self.config, self.inner)
255    }
256}
257
258impl<C, F> FactoryStack<C, F>
259where
260    F: MakeService,
261{
262    /// Make a service.
263    #[inline]
264    pub fn make(&self) -> Result<F::Service, F::Error> {
265        self.inner.make()
266    }
267}
268
269impl<C, F> FactoryStack<C, F>
270where
271    F: AsyncMakeService,
272{
273    /// Make a service in async.
274    #[inline]
275    pub async fn make_async(&self) -> Result<F::Service, F::Error> {
276        self.inner.make().await
277    }
278}