Skip to main content

rinf_router/
handler.rs

1//! ## Handler
2//!
3//! Any async function that take a number of "extractors", [`FromRequest`], and
4//! ends with a RINF signal type, is a handler capable of being registered in
5//! the router.
6//!
7//! It's important to note that the order of arguments matter -- **All but the
8//! last arguments are meant for extractors while the last is meant for the Dart
9//! signal**.
10
11use std::{convert::Infallible, future::Future};
12
13use futures::future::BoxFuture;
14use rinf::{DartSignal, RustSignal};
15
16use crate::{extractor::FromRequest, into_response::IntoResponse};
17
18/// A thin Service wrapper that holds a Handler and its state.
19pub struct HandlerService<H, T, S> {
20    handler: H,
21    state: S,
22    _phantom: std::marker::PhantomData<fn() -> T>,
23}
24
25impl<H, T, S> Clone for HandlerService<H, T, S>
26where
27    H: Clone,
28    S: Clone,
29{
30    fn clone(&self) -> Self {
31        Self {
32            handler: self.handler.clone(),
33            state: self.state.clone(),
34            _phantom: std::marker::PhantomData,
35        }
36    }
37}
38
39impl<H, T, S> HandlerService<H, T, S>
40where
41    H: Clone,
42    S: Clone,
43{
44    /// Create a new HandlerService with handler and state.
45    pub fn new(handler: H, state: S) -> Self {
46        Self {
47            handler,
48            state,
49            _phantom: std::marker::PhantomData,
50        }
51    }
52}
53
54impl<H, T, S> tower::Service<H::Signal> for HandlerService<H, T, S>
55where
56    H: Handler<T, S>,
57    H::Future: Send + 'static,
58    S: Clone,
59{
60    type Error = Infallible;
61    type Future = BoxFuture<'static, Result<(), Infallible>>;
62    type Response = ();
63
64    fn poll_ready(
65        &mut self,
66        _cx: &mut std::task::Context<'_>,
67    ) -> std::task::Poll<Result<(), Self::Error>> {
68        std::task::Poll::Ready(Ok(()))
69    }
70
71    fn call(&mut self, signal: H::Signal) -> Self::Future {
72        let future = self.handler.clone().call(signal, self.state.clone());
73        Box::pin(async move {
74            future.await;
75            Ok(())
76        })
77    }
78}
79
80macro_rules! impl_handler {
81    (
82        [$($arg:ident),*], $last:ident
83    ) => {
84        #[allow(non_snake_case)]
85        // Handler trait implementation for async functions
86        impl<F, Fut, R $(,$arg)*, $last, S> Handler<($($arg,)* $last,), S> for F
87        where
88            F: FnOnce($($arg,)* $last) -> Fut + Clone + Send + Sync + 'static,
89            Fut: Future<Output = R> + Send + 'static,
90            S: Clone + Send + Sync + 'static,
91            R: IntoResponse + Send + 'static,
92            $(
93              $arg: FromRequest<$last, S> + Send + 'static,
94            )*
95            $last: DartSignal + Send + Sync + 'static,
96        {
97            type Signal = $last;
98            type Future = BoxFuture<'static, ()>;
99
100
101            #[cfg_attr(feature = "tracing", tracing::instrument(skip_all, level = "info"))]
102            fn call(self, signal: $last, state: S) -> Self::Future {
103                Box::pin(async move {
104                    // Allow unused state when no extractors are present
105                    #[allow(unused_variables)]
106                    let _ = &state;
107
108                    // Extract all the extractors
109                    $(
110                        let $arg = $arg::from_request(&signal, &state).await;
111                    )*
112
113                    // Call the async function
114                    let result = self($($arg,)* signal).await.into_response();
115
116                    // Send response back to Dart
117                    result.send_signal_to_dart();
118                })
119            }
120        }
121    };
122}
123
124/// ### Handler
125///
126/// The [`Handler`] trait represents an async function that can process RINF
127/// signals.
128///
129/// You will very rarely implement this trait manually—implementations are
130/// generated for you by the [`impl_handler!`] macro for functions that:
131///
132/// * Are `async`
133/// * Take **zero or more _extractors_** (types that implement [`FromRequest`])
134///   as their **leading** parameters
135/// * End with the concrete RINF [`DartSignal`] message type
136///
137/// The Handler trait focuses on calling the async function with proper
138/// extractors. To turn a Handler into a Tower Service, use
139/// [`HandlerWithoutStateExt::into_service`] on a [`Handler`].
140pub trait Handler<T, S>: Clone + Send + Sized {
141    /// The specific RINF signal type this handler processes.
142    type Signal: DartSignal + Send + Sync + 'static;
143
144    /// The future returned by calling this handler.
145    type Future: Future<Output = ()> + Send + 'static;
146
147    /// Call the handler with the given signal and state.
148    fn call(self, signal: Self::Signal, state: S) -> Self::Future;
149
150    /// Apply a Tower layer to this handler, creating a new layered handler.
151    fn layer<L>(self, layer: L) -> Layered<L, Self, T, S>
152    where
153        L: tower::Layer<HandlerService<Self, T, S>> + Clone + Send + 'static,
154        L::Service: tower::Service<Self::Signal, Response = (), Error = Infallible>
155            + Clone
156            + Send
157            + 'static,
158        S: Clone + Send + Sync + 'static,
159    {
160        Layered {
161            layer,
162            handler: self,
163            _phantom: std::marker::PhantomData,
164        }
165    }
166
167    /// Convert this handler into a Tower Service with state.
168    /// This creates a HandlerService wrapper around the handler.
169    fn with_state(self, state: S) -> HandlerService<Self, T, S>
170    where
171        S: Clone + Send + Sync + 'static,
172    {
173        HandlerService::new(self, state)
174    }
175}
176
177/// A handler wrapped with a Tower layer for middleware.
178///
179/// This type is returned by [`Handler::layer`] and implements [`Handler`]
180/// itself, allowing you to compose multiple layers or pass it to
181/// [`Router::route`].
182pub struct Layered<L, H, T, S> {
183    layer: L,
184    handler: H,
185    _phantom: std::marker::PhantomData<fn() -> (T, S)>,
186}
187
188impl<L, H, T, S> Clone for Layered<L, H, T, S>
189where
190    L: Clone,
191    H: Clone,
192{
193    fn clone(&self) -> Self {
194        Self {
195            layer: self.layer.clone(),
196            handler: self.handler.clone(),
197            _phantom: std::marker::PhantomData,
198        }
199    }
200}
201
202impl<L, H, T, S> Handler<T, S> for Layered<L, H, T, S>
203where
204    H: Handler<T, S>,
205    L: tower::Layer<HandlerService<H, T, S>> + Clone + Send + 'static,
206    L::Service:
207        tower::Service<H::Signal, Response = (), Error = Infallible> + Clone + Send + 'static,
208    <L::Service as tower::Service<H::Signal>>::Future: Send + 'static,
209    S: Clone + Send + Sync + 'static,
210    T: Send + Sync + 'static,
211{
212    type Future = BoxFuture<'static, ()>;
213    type Signal = H::Signal;
214
215    fn call(self, signal: Self::Signal, state: S) -> Self::Future {
216        let svc = self.handler.with_state(state);
217        let svc = self.layer.layer(svc);
218
219        Box::pin(async move {
220            use tower::ServiceExt;
221            let _ = svc.oneshot(signal).await;
222        })
223    }
224}
225
226/// Extension trait for handlers that don't require state.
227pub trait HandlerWithoutStateExt<T>: Handler<T, ()> + Sized {
228    /// Convert this handler into a service without requiring state.
229    fn into_service(self) -> HandlerService<Self, T, ()> {
230        Handler::with_state(self, ())
231    }
232}
233
234impl<H, T> HandlerWithoutStateExt<T> for H where H: Handler<T, ()> {}
235
236impl_handler!([], T1);
237impl_handler!([T1], T2);
238impl_handler!([T1, T2], T3);
239impl_handler!([T1, T2, T3], T4);
240impl_handler!([T1, T2, T3, T4], T5);
241impl_handler!([T1, T2, T3, T4, T5], T6);
242impl_handler!([T1, T2, T3, T4, T5, T6], T7);
243impl_handler!([T1, T2, T3, T4, T5, T6, T7], T8);
244impl_handler!([T1, T2, T3, T4, T5, T6, T7, T8], T9);
245impl_handler!([T1, T2, T3, T4, T5, T6, T7, T8, T9], T10);
246impl_handler!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T11);
247impl_handler!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], T12);
248impl_handler!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], T13);
249impl_handler!(
250    [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13],
251    T14
252);
253impl_handler!(
254    [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14],
255    T15
256);
257impl_handler!(
258    [
259        T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15
260    ],
261    T16
262);
263
264#[cfg(all(test, feature = "test-helpers"))]
265mod tests {
266    use std::sync::{
267        Arc,
268        Mutex,
269        atomic::{AtomicUsize, Ordering},
270    };
271
272    use serial_test::serial;
273    use tower::ServiceExt;
274
275    use super::*;
276    use crate::{
277        State,
278        test_helpers::{EmptySignal, Signal, assert_handler},
279    };
280
281    // Compilation tests for various handler signatures
282    #[tokio::test]
283    #[allow(unused_must_use)]
284    async fn handler_signatures_compile() {
285        async fn empty_handler() {}
286        async fn signal_handler(_: Signal) {}
287        async fn stateful_handler(State(_): State<String>, _: Signal) {}
288        async fn response_handler(State(_): State<String>, _: Signal) -> Option<()> {
289            None
290        }
291
292        assert_handler::<_, (), _>(empty_handler);
293        assert_handler::<_, (), _>(signal_handler);
294        assert_handler(stateful_handler);
295        assert_handler(response_handler);
296    }
297
298    #[tokio::test]
299    async fn into_service_converts_stateless_handler() {
300        let counter = Arc::new(AtomicUsize::new(0));
301        let counter_clone = Arc::clone(&counter);
302
303        let handler = move || {
304            let counter = Arc::clone(&counter_clone);
305            async move {
306                counter.fetch_add(1, Ordering::SeqCst);
307            }
308        };
309
310        let service = handler.into_service();
311        service.oneshot(EmptySignal).await.unwrap();
312
313        assert_eq!(counter.load(Ordering::SeqCst), 1);
314    }
315
316    #[tokio::test]
317    #[serial]
318    async fn handler_processes_signal() {
319        let received = Arc::new(Mutex::new(String::new()));
320        let received_clone = Arc::clone(&received);
321
322        let handler = move |signal: Signal| {
323            let received = Arc::clone(&received_clone);
324            async move {
325                *received.lock().unwrap() = signal.message;
326            }
327        };
328
329        handler.call(Signal::new("test"), ()).await;
330        assert_eq!(*received.lock().unwrap(), "test");
331    }
332}