service_async/make_service.rs
1use std::{future::Future, sync::Arc};
2
3/// A trait implemented by service factories to create instances of services that implement the [`Service`](crate::Service) trait.
4///
5/// `MakeService` enables flexible service chain construction with state migration between instances.
6/// It's particularly useful for managing stateful resources (e.g., connection pools) when updating
7/// service configurations.
8///
9/// # Key Features
10///
11/// - State preservation and resource reuse between service instances
12/// - Optional creation of services from scratch
13/// - Efficient management of stateful resources across service updates
14///
15/// # Example Implementation
16///
17/// ```rust
18/// use std::convert::Infallible;
19/// use service_async::{MakeService, Service};
20///
21/// struct MyService {
22/// connection_pool: ConnectionPool,
23/// config: Config,
24/// }
25///
26/// struct MyServiceFactory {
27/// config: Config,
28/// }
29///
30/// impl MakeService for MyServiceFactory {
31/// type Service = MyService;
32/// type Error = Infallible;
33///
34/// fn make_via_ref(&self, old: Option<&Self::Service>) -> Result<Self::Service, Self::Error> {
35/// Ok(match old {
36/// Some(existing) => MyService {
37/// connection_pool: existing.connection_pool.clone(),
38/// config: self.config.clone(),
39/// },
40/// None => MyService {
41/// connection_pool: ConnectionPool::new(),
42/// config: self.config.clone(),
43/// },
44/// })
45/// }
46/// }
47/// ```
48///
49/// In this example, `MyServiceFactory` implements `MakeService` to create `MyService` instances,
50/// demonstrating how to reuse a connection pool when an existing service is provided.
51pub trait MakeService {
52 /// The type of service this factory creates.
53 type Service;
54
55 /// The type of error that can occur during service creation.
56 type Error;
57
58 /// Creates a new service, optionally using an existing service as a reference.
59 ///
60 /// This method allows for sophisticated service creation logic that can reuse
61 /// state from an existing service instance.
62 ///
63 /// # Arguments
64 ///
65 /// * `old` - An optional reference to an existing service instance.
66 ///
67 /// # Returns
68 ///
69 /// A `Result` containing either the newly created service or an error.
70 fn make_via_ref(&self, old: Option<&Self::Service>) -> Result<Self::Service, Self::Error>;
71
72 /// Creates a new service without referencing an existing one.
73 ///
74 /// This is a convenience method that calls `make_via_ref` with `None`.
75 ///
76 /// # Returns
77 ///
78 /// A `Result` containing either the newly created service or an error.
79 fn make(&self) -> Result<Self::Service, Self::Error> {
80 self.make_via_ref(None)
81 }
82}
83
84impl<T: MakeService + ?Sized> MakeService for &T {
85 type Service = T::Service;
86 type Error = T::Error;
87 fn make_via_ref(&self, old: Option<&Self::Service>) -> Result<Self::Service, Self::Error> {
88 (*self).make_via_ref(old)
89 }
90}
91
92impl<T: MakeService + ?Sized> MakeService for Arc<T> {
93 type Service = T::Service;
94 type Error = T::Error;
95 fn make_via_ref(&self, old: Option<&Self::Service>) -> Result<Self::Service, Self::Error> {
96 self.as_ref().make_via_ref(old)
97 }
98}
99
100impl<T: MakeService + ?Sized> MakeService for Box<T> {
101 type Service = T::Service;
102 type Error = T::Error;
103 fn make_via_ref(&self, old: Option<&Self::Service>) -> Result<Self::Service, Self::Error> {
104 self.as_ref().make_via_ref(old)
105 }
106}
107
108/// A boxed trait object of `MakeService` that enables type erasure for service factories.
109///
110/// `BoxedMakeService<S, E>` allows different implementations of `MakeService` to be
111/// treated uniformly, as long as they produce the same `Service` type `S` and `Error` type `E`.
112//
113/// This type is particularly useful when designing systems with pluggable or configurable
114/// service factories, where the exact implementation of the factory may vary or be determined at runtime.
115pub type BoxedMakeService<S, E> =
116 Box<dyn MakeService<Service = S, Error = E> + Send + Sync + 'static>;
117
118/// `ArcMakeService<S, E>` is similar to `BoxedMakeService<S, E>`, but uses `Arc` instead of `Box`.
119/// This allows for multiple owners of the same `MakeService` implementation, enabling efficient
120/// cloning and sharing across multiple components or threads.
121///
122/// # Key Features
123///
124/// - Shared Ownership: Allows multiple components to share the same `MakeService` instance.
125/// - Type Erasure: Enables storing different `MakeService` implementations uniformly.
126/// - Efficient Cloning: `Arc` allows for cheap cloning of the service factory reference.
127///
128/// This type is particularly useful in scenarios where a service factory needs to be
129/// shared across multiple parts of an application, such as in worker pools.
130pub type ArcMakeService<S, E> =
131 Arc<dyn MakeService<Service = S, Error = E> + Send + Sync + 'static>;
132
133pub type BoxedMakeBoxedService<Req, Resp, SE, ME> =
134 BoxedMakeService<crate::BoxedService<Req, Resp, SE>, ME>;
135pub type ArcMakeBoxedService<Req, Resp, SE, ME> =
136 ArcMakeService<crate::BoxedService<Req, Resp, SE>, ME>;
137
138/// A trait implemented by asynchronous service factories to create instances of services
139/// that implement the [`Service`](crate::Service) trait.
140///
141/// `AsyncMakeService` is the asynchronous counterpart to [`MakeService`]. It enables flexible
142/// service chain construction with state migration between instances, allowing for asynchronous
143/// initialization or resource acquisition.
144///
145/// # Key Features
146///
147/// - Asynchronous service creation, suitable for I/O-bound initialization
148/// - State preservation and resource reuse between service instances
149/// - Optional creation of services from scratch
150/// - Efficient management of stateful resources across service updates
151///
152/// # Example Implementation
153///
154/// ```rust
155/// use std::convert::Infallible;
156/// use your_crate::{AsyncMakeService, Service};
157///
158/// struct MyAsyncService {
159/// connection_pool: AsyncConnectionPool,
160/// config: Config,
161/// }
162///
163/// struct MyAsyncServiceFactory {
164/// config: Config,
165/// }
166///
167/// impl AsyncMakeService for MyAsyncServiceFactory {
168/// type Service = MyAsyncService;
169/// type Error = Infallible;
170///
171/// async fn make_via_ref(&self, old: Option<&Self::Service>) -> Result<Self::Service, Self::Error> {
172/// Ok(match old {
173/// Some(existing) => MyAsyncService {
174/// connection_pool: existing.connection_pool.clone(),
175/// config: self.config.clone(),
176/// },
177/// None => MyAsyncService {
178/// connection_pool: AsyncConnectionPool::new().await,
179/// config: self.config.clone(),
180/// },
181/// })
182/// }
183/// }
184/// ```
185///
186/// In this example, `MyAsyncServiceFactory` implements `AsyncMakeService` to create `MyAsyncService`
187/// instances asynchronously, demonstrating how to reuse a connection pool or create a new one when needed.
188pub trait AsyncMakeService {
189 /// The type of service this factory creates.
190 type Service;
191
192 /// The type of error that can occur during service creation.
193 type Error;
194
195 /// Asynchronously creates a new service, optionally using an existing service as a reference.
196 ///
197 /// This method allows for sophisticated asynchronous service creation logic that can reuse
198 /// state from an existing service instance.
199 ///
200 /// # Arguments
201 ///
202 /// * `old` - An optional reference to an existing service instance.
203 ///
204 /// # Returns
205 ///
206 /// A `Future` that resolves to a `Result` containing either the newly created service or an error.
207 fn make_via_ref(
208 &self,
209 old: Option<&Self::Service>,
210 ) -> impl Future<Output = Result<Self::Service, Self::Error>>;
211
212 /// Asynchronously creates a new service without referencing an existing one.
213 ///
214 /// This is a convenience method that calls `make_via_ref` with `None`.
215 ///
216 /// # Returns
217 ///
218 /// A `Future` that resolves to a `Result` containing either the newly created service or an error.
219 fn make(&self) -> impl Future<Output = Result<Self::Service, Self::Error>> {
220 self.make_via_ref(None)
221 }
222}
223
224impl<T: AsyncMakeService + ?Sized> AsyncMakeService for &T {
225 type Service = T::Service;
226 type Error = T::Error;
227 async fn make_via_ref(
228 &self,
229 old: Option<&Self::Service>,
230 ) -> Result<Self::Service, Self::Error> {
231 (*self).make_via_ref(old).await
232 }
233}
234
235impl<T: AsyncMakeService + ?Sized> AsyncMakeService for Arc<T> {
236 type Service = T::Service;
237 type Error = T::Error;
238 async fn make_via_ref(
239 &self,
240 old: Option<&Self::Service>,
241 ) -> Result<Self::Service, Self::Error> {
242 self.as_ref().make_via_ref(old).await
243 }
244}
245
246impl<T: AsyncMakeService + ?Sized> AsyncMakeService for Box<T> {
247 type Service = T::Service;
248 type Error = T::Error;
249 async fn make_via_ref(
250 &self,
251 old: Option<&Self::Service>,
252 ) -> Result<Self::Service, Self::Error> {
253 self.as_ref().make_via_ref(old).await
254 }
255}
256
257/// Impl AsyncMakeService where T: MakeService.
258#[repr(transparent)]
259#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
260pub struct AsyncMakeServiceWrapper<T>(pub T);
261
262impl<T: MakeService> AsyncMakeService for AsyncMakeServiceWrapper<T> {
263 type Service = <T as MakeService>::Service;
264 type Error = <T as MakeService>::Error;
265
266 async fn make_via_ref(
267 &self,
268 old: Option<&Self::Service>,
269 ) -> Result<Self::Service, Self::Error> {
270 <T as MakeService>::make_via_ref(&self.0, old)
271 }
272 async fn make(&self) -> Result<Self::Service, Self::Error> {
273 <T as MakeService>::make(&self.0)
274 }
275}