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}