actix_service/
macros.rs

1/// An implementation of [`poll_ready`]() that always signals readiness.
2///
3/// This should only be used for basic leaf services that have no concept of un-readiness.
4/// For wrapper or other service types, use [`forward_ready!`] for simple cases or write a bespoke
5/// `poll_ready` implementation.
6///
7/// [`poll_ready`]: crate::Service::poll_ready
8///
9/// # Examples
10/// ```no_run
11/// use actix_service::Service;
12/// use futures_util::future::{ready, Ready};
13///
14/// struct IdentityService;
15///
16/// impl Service<u32> for IdentityService {
17///     type Response = u32;
18///     type Error = ();
19///     type Future = Ready<Result<Self::Response, Self::Error>>;
20///
21///     actix_service::always_ready!();
22///
23///     fn call(&self, req: u32) -> Self::Future {
24///         ready(Ok(req))
25///     }
26/// }
27/// ```
28///
29/// [`forward_ready!`]: crate::forward_ready
30#[macro_export]
31macro_rules! always_ready {
32    () => {
33        #[inline]
34        fn poll_ready(
35            &self,
36            _: &mut ::core::task::Context<'_>,
37        ) -> ::core::task::Poll<Result<(), Self::Error>> {
38            ::core::task::Poll::Ready(Ok(()))
39        }
40    };
41}
42
43/// An implementation of [`poll_ready`] that forwards readiness checks to a
44/// named struct field.
45///
46/// Tuple structs are not supported.
47///
48/// [`poll_ready`]: crate::Service::poll_ready
49///
50/// # Examples
51/// ```no_run
52/// use actix_service::Service;
53/// use futures_util::future::{ready, Ready};
54///
55/// struct WrapperService<S> {
56///     inner: S,
57/// }
58///
59/// impl<S> Service<()> for WrapperService<S>
60/// where
61///     S: Service<()>,
62/// {
63///     type Response = S::Response;
64///     type Error = S::Error;
65///     type Future = S::Future;
66///
67///     actix_service::forward_ready!(inner);
68///
69///     fn call(&self, req: ()) -> Self::Future {
70///         self.inner.call(req)
71///     }
72/// }
73/// ```
74#[macro_export]
75macro_rules! forward_ready {
76    ($field:ident) => {
77        #[inline]
78        fn poll_ready(
79            &self,
80            cx: &mut ::core::task::Context<'_>,
81        ) -> ::core::task::Poll<Result<(), Self::Error>> {
82            self.$field
83                .poll_ready(cx)
84                .map_err(::core::convert::Into::into)
85        }
86    };
87}
88
89#[cfg(test)]
90mod tests {
91    use core::{
92        cell::Cell,
93        convert::Infallible,
94        task::{self, Context, Poll},
95    };
96
97    use futures_util::{
98        future::{ready, Ready},
99        task::noop_waker,
100    };
101
102    use crate::Service;
103
104    struct IdentityService;
105
106    impl Service<u32> for IdentityService {
107        type Response = u32;
108        type Error = Infallible;
109        type Future = Ready<Result<Self::Response, Self::Error>>;
110
111        always_ready!();
112
113        fn call(&self, req: u32) -> Self::Future {
114            ready(Ok(req))
115        }
116    }
117
118    struct CountdownService(Cell<u32>);
119
120    impl Service<()> for CountdownService {
121        type Response = ();
122        type Error = Infallible;
123        type Future = Ready<Result<Self::Response, Self::Error>>;
124
125        fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
126            let count = self.0.get();
127
128            if count == 0 {
129                Poll::Ready(Ok(()))
130            } else {
131                self.0.set(count - 1);
132                cx.waker().wake_by_ref();
133                Poll::Pending
134            }
135        }
136
137        fn call(&self, _: ()) -> Self::Future {
138            ready(Ok(()))
139        }
140    }
141
142    struct WrapperService<S> {
143        inner: S,
144    }
145
146    impl<S> Service<()> for WrapperService<S>
147    where
148        S: Service<()>,
149    {
150        type Response = S::Response;
151        type Error = S::Error;
152        type Future = S::Future;
153
154        forward_ready!(inner);
155
156        fn call(&self, _: ()) -> Self::Future {
157            self.inner.call(())
158        }
159    }
160
161    #[test]
162    fn test_always_ready_macro() {
163        let waker = noop_waker();
164        let mut cx = task::Context::from_waker(&waker);
165
166        let svc = IdentityService;
167
168        assert!(svc.poll_ready(&mut cx).is_ready());
169        assert!(svc.poll_ready(&mut cx).is_ready());
170        assert!(svc.poll_ready(&mut cx).is_ready());
171    }
172
173    #[test]
174    fn test_forward_ready_macro() {
175        let waker = noop_waker();
176        let mut cx = task::Context::from_waker(&waker);
177
178        let svc = WrapperService {
179            inner: CountdownService(Cell::new(3)),
180        };
181
182        assert!(svc.poll_ready(&mut cx).is_pending());
183        assert!(svc.poll_ready(&mut cx).is_pending());
184        assert!(svc.poll_ready(&mut cx).is_pending());
185        assert!(svc.poll_ready(&mut cx).is_ready());
186    }
187}