xitca_service/ready/mod.rs
1//! trait and types for backpressure handling.
2
3mod and_then;
4mod enclosed_fn;
5mod function;
6mod map;
7mod map_err;
8
9use core::{future::Future, ops::Deref, pin::Pin};
10
11/// Extend trait for [Service](crate::Service).
12///
13/// Can be used to cehck the ready state of a service before calling it.
14///
15/// # Examples:
16/// ```rust
17/// # use std::{cell::Cell, rc::Rc, future::Future};
18/// # use xitca_service::{Service, ready::ReadyService};
19///
20/// // a service with conditional availability based on state of Permit.
21/// struct Foo(Permit);
22///
23/// // a permit reset the inner boolean to true on drop.
24/// #[derive(Clone)]
25/// struct Permit(Rc<Cell<bool>>);
26///
27/// impl Drop for Permit {
28/// fn drop(&mut self) {
29/// self.0.set(true);
30/// }
31/// }
32///
33/// impl Service<()> for Foo {
34/// type Response = ();
35/// type Error = ();
36///
37/// async fn call(&self, _req: ()) -> Result<Self::Response, Self::Error> {
38/// Ok(())
39/// }
40/// }
41///
42/// impl ReadyService for Foo {
43/// type Ready = Result<Permit, ()>;
44///
45/// async fn ready(&self) -> Self::Ready {
46/// if self.0.0.get() {
47/// // set permit to false and return with Ok<Permit>
48/// self.0.0.set(false);
49/// Ok(self.0.clone())
50/// } else {
51/// // return error is to simply the example.
52/// // In real world this branch should be an async waiting for Permit reset to true.
53/// Err(())
54/// }
55/// }
56/// }
57///
58/// async fn workflow(service: &Foo) {
59/// let permit = service.ready().await.unwrap(); // check service ready state.
60///
61/// service.call(()).await.unwrap(); // run Service::call when permit is held in scope.
62///
63/// drop(permit); // drop permit after Service::call is finished.
64/// }
65///
66/// async fn throttle(service: &Foo) {
67/// let permit = service.ready().await.unwrap();
68/// assert!(service.ready().await.is_err()); // service is throttled because permit is still held in scope.
69/// }
70/// ```
71pub trait ReadyService {
72 type Ready;
73
74 fn ready(&self) -> impl Future<Output = Self::Ready>;
75}
76
77#[cfg(feature = "alloc")]
78mod alloc_impl {
79 use super::ReadyService;
80
81 use alloc::{boxed::Box, rc::Rc, sync::Arc};
82
83 macro_rules! impl_alloc {
84 ($alloc: ident) => {
85 impl<S> ReadyService for $alloc<S>
86 where
87 S: ReadyService + ?Sized,
88 {
89 type Ready = S::Ready;
90
91 #[inline]
92 async fn ready(&self) -> Self::Ready {
93 (**self).ready().await
94 }
95 }
96 };
97 }
98
99 impl_alloc!(Box);
100 impl_alloc!(Rc);
101 impl_alloc!(Arc);
102}
103
104impl<S> ReadyService for Pin<S>
105where
106 S: Deref,
107 S::Target: ReadyService,
108{
109 type Ready = <S::Target as ReadyService>::Ready;
110
111 #[inline]
112 async fn ready(&self) -> Self::Ready {
113 self.as_ref().get_ref().ready().await
114 }
115}