exc_service/traits/
mod.rs

1use super::adapt::{Adapt, AdaptLayer, AdaptService};
2use crate::{Exc, ExchangeError};
3use futures::future::BoxFuture;
4use tower::{
5    util::{BoxCloneService, BoxService, MapErr},
6    Layer, Service,
7};
8
9use std::{
10    fmt,
11    future::Future,
12    marker::PhantomData,
13    task::{Context, Poll},
14};
15
16/// Sendable [`ExcService`].
17#[cfg(feature = "send")]
18pub mod send;
19
20/// Request and Response binding.
21pub trait Request: Sized {
22    /// Response type.
23    type Response;
24}
25
26/// An alias of [`Service`] that requires the input type to be a [`Request`],
27/// and the error type to be [`ExchangeError`].
28///
29/// Basically, [`Request`] is just indicating that the input type has a fixed response type.
30pub trait ExcService<R>
31where
32    R: Request,
33{
34    /// The future response value.
35    type Future: Future<Output = Result<R::Response, ExchangeError>>;
36
37    /// See [`Service::poll_ready`] for more details.
38    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ExchangeError>>;
39
40    /// See [`Service::call`] for more details.
41    fn call(&mut self, req: R) -> Self::Future;
42
43    /// Convert to a [`Service`].
44    fn as_service(&mut self) -> AsService<'_, Self, R>
45    where
46        Self: Sized,
47    {
48        AsService {
49            inner: self,
50            _req: PhantomData,
51        }
52    }
53}
54
55impl<S, R> ExcService<R> for S
56where
57    S: Service<R, Response = R::Response, Error = ExchangeError>,
58    R: Request,
59{
60    type Future = S::Future;
61
62    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ExchangeError>> {
63        Service::<R>::poll_ready(self, cx)
64    }
65
66    fn call(&mut self, req: R) -> Self::Future {
67        Service::<R>::call(self, req)
68    }
69}
70
71/// [`Service`] returns by [`ExcService::as_service`].
72pub struct AsService<'a, S, R> {
73    inner: &'a mut S,
74    _req: PhantomData<R>,
75}
76
77impl<'a, S, R> fmt::Debug for AsService<'a, S, R>
78where
79    S: fmt::Debug,
80{
81    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82        f.debug_struct("AsService")
83            .field("inner", &self.inner)
84            .finish()
85    }
86}
87
88impl<'a, S, R> Service<R> for AsService<'a, S, R>
89where
90    R: Request,
91    S: ExcService<R>,
92{
93    type Response = R::Response;
94
95    type Error = ExchangeError;
96
97    type Future = S::Future;
98
99    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
100        ExcService::<R>::poll_ready(self.inner, cx)
101    }
102
103    fn call(&mut self, req: R) -> Self::Future {
104        ExcService::<R>::call(self.inner, req)
105    }
106}
107
108/// [`Service`] returns by [`ExcServiceExt::into_service`].
109pub struct IntoService<S, R> {
110    inner: S,
111    _req: PhantomData<R>,
112}
113
114impl<S, R> fmt::Debug for IntoService<S, R>
115where
116    S: fmt::Debug,
117{
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        f.debug_struct("IntoService")
120            .field("inner", &self.inner)
121            .finish()
122    }
123}
124
125impl<S, R> Clone for IntoService<S, R>
126where
127    S: Clone,
128{
129    fn clone(&self) -> Self {
130        Self {
131            inner: self.inner.clone(),
132            _req: PhantomData,
133        }
134    }
135}
136
137impl<S, R> Copy for IntoService<S, R> where S: Copy {}
138
139impl<S, R> Service<R> for IntoService<S, R>
140where
141    R: Request,
142    S: ExcService<R>,
143{
144    type Response = R::Response;
145
146    type Error = ExchangeError;
147
148    type Future = S::Future;
149
150    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
151        ExcService::<R>::poll_ready(&mut self.inner, cx)
152    }
153
154    fn call(&mut self, req: R) -> Self::Future {
155        ExcService::<R>::call(&mut self.inner, req)
156    }
157}
158
159/// Extension trait for [`ExcService`].
160pub trait ExcServiceExt<R>: ExcService<R>
161where
162    R: Request,
163{
164    /// Convert into a [`Service`].
165    fn into_service(self) -> IntoService<Self, R>
166    where
167        Self: Sized,
168    {
169        IntoService {
170            inner: self,
171            _req: PhantomData,
172        }
173    }
174
175    /// Apply a layer of which the result service is still a [`ExcService`].
176    fn apply<L, R2>(self, layer: &L) -> L::Service
177    where
178        Self: Sized,
179        R2: Request,
180        L: Layer<Self>,
181        L::Service: ExcService<R2>,
182    {
183        layer.layer(self)
184    }
185
186    /// Adapt the request type to the given.
187    fn adapt<R2>(self) -> Adapt<Self, R, R2>
188    where
189        Self: Sized,
190        R2: Request,
191        Self: AdaptService<R, R2>,
192    {
193        self.apply(&AdaptLayer::default())
194    }
195
196    /// Apply a rate-limit layer to the service.
197    #[cfg(feature = "limit")]
198    fn rate_limited(
199        self,
200        num: u64,
201        per: std::time::Duration,
202    ) -> tower::limit::RateLimit<IntoService<Self, R>>
203    where
204        Self: Sized,
205    {
206        use tower::limit::RateLimitLayer;
207        self.into_service().apply(&RateLimitLayer::new(num, per))
208    }
209
210    /// Apply a retry layer to the service.
211    #[cfg(feature = "retry")]
212    fn retry(
213        self,
214        max_duration: std::time::Duration,
215    ) -> tower::retry::Retry<crate::retry::Always, IntoService<Self, R>>
216    where
217        R: Clone,
218        Self: Sized + Clone,
219    {
220        use crate::retry::Always;
221        use tower::retry::RetryLayer;
222
223        self.into_service()
224            .apply(&RetryLayer::new(Always::with_max_duration(max_duration)))
225    }
226
227    /// Create a boxed [`ExcService`].
228    fn boxed(self) -> BoxExcService<R>
229    where
230        Self: Sized + Send + 'static,
231        R: Send + 'static,
232        Self::Future: Send + 'static,
233    {
234        BoxExcService {
235            inner: BoxService::new(self.into_service()),
236        }
237    }
238
239    /// Create a boxed [`ExcService`] with [`Clone`].
240    fn boxed_clone(&self) -> BoxCloneExcService<R>
241    where
242        R: Send + 'static,
243        Self: Sized + Clone + Send + 'static,
244        Self::Future: Send + 'static,
245    {
246        BoxCloneExcService {
247            inner: BoxCloneService::new(self.clone().into_service()),
248        }
249    }
250}
251
252impl<S, R> ExcServiceExt<R> for S
253where
254    S: ExcService<R>,
255    R: Request,
256{
257}
258
259type MapErrFn<E> = fn(E) -> ExchangeError;
260
261/// Service that can be converted into a [`Exc`].
262pub trait IntoExc<R>: Service<R, Response = R::Response>
263where
264    Self::Error: Into<ExchangeError>,
265    R: Request,
266{
267    /// Convert into a [`Exc`].
268    fn into_exc(self) -> Exc<MapErr<Self, MapErrFn<Self::Error>>, R>
269    where
270        Self: Sized,
271    {
272        Exc::new(MapErr::new(self, Self::Error::into))
273    }
274}
275
276impl<S, R> IntoExc<R> for S
277where
278    S: Service<R, Response = R::Response>,
279    S::Error: Into<ExchangeError>,
280    R: Request,
281{
282}
283
284/// Boxed [`ExcService`].
285#[derive(Debug)]
286pub struct BoxExcService<R>
287where
288    R: Request,
289{
290    inner: BoxService<R, R::Response, ExchangeError>,
291}
292
293impl<R> Service<R> for BoxExcService<R>
294where
295    R: Request,
296{
297    type Response = R::Response;
298
299    type Error = ExchangeError;
300
301    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
302
303    fn poll_ready(
304        &mut self,
305        cx: &mut std::task::Context<'_>,
306    ) -> std::task::Poll<Result<(), Self::Error>> {
307        Service::<R>::poll_ready(&mut self.inner, cx)
308    }
309
310    fn call(&mut self, req: R) -> Self::Future {
311        Service::<R>::call(&mut self.inner, req)
312    }
313}
314
315/// Boxed [`ExcService`] with [`Clone`].
316#[derive(Debug)]
317pub struct BoxCloneExcService<R>
318where
319    R: Request,
320{
321    inner: BoxCloneService<R, R::Response, ExchangeError>,
322}
323
324impl<R> Clone for BoxCloneExcService<R>
325where
326    R: Request,
327{
328    fn clone(&self) -> Self {
329        Self {
330            inner: self.inner.clone(),
331        }
332    }
333}
334
335impl<R> Service<R> for BoxCloneExcService<R>
336where
337    R: Request,
338{
339    type Response = R::Response;
340
341    type Error = ExchangeError;
342
343    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
344
345    fn poll_ready(
346        &mut self,
347        cx: &mut std::task::Context<'_>,
348    ) -> std::task::Poll<Result<(), Self::Error>> {
349        Service::<R>::poll_ready(&mut self.inner, cx)
350    }
351
352    fn call(&mut self, req: R) -> Self::Future {
353        Service::<R>::call(&mut self.inner, req)
354    }
355}