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}