1use crate::app::AppInner;
4use crate::handler::BoxFuture;
5use crate::request::Request;
6use crate::response::Response;
7use std::sync::{Arc, OnceLock};
8
9type DispatchFn = Arc<dyn Fn(Request) -> BoxFuture<Response> + Send + Sync>;
10
11struct Inner {
12 dispatch: DispatchFn,
13}
14
15#[derive(Clone, Default)]
17pub struct AppDispatch {
18 slot: Arc<OnceLock<Inner>>,
19}
20
21impl AppDispatch {
22 pub fn try_dispatch(&self, req: Request) -> Option<BoxFuture<Response>> {
24 Some((self.slot.get()?.dispatch)(req))
25 }
26
27 pub(crate) fn install_if_needed(&self, inner: &AppInner) {
28 if self.slot.get().is_some() {
29 return;
30 }
31 let _ = self.install(inner);
32 }
33
34 pub(crate) fn install(&self, inner: &AppInner) -> bool {
35 if self.slot.get().is_some() {
36 return false;
37 }
38 let compiled = Arc::clone(&inner.compiled);
39 let state = inner.state();
40 let dispatch: DispatchFn = Arc::new(move |mut req: Request| {
41 req.state = Arc::clone(&state);
42 let compiled = Arc::clone(&compiled);
43 Box::pin(async move { compiled.dispatch(req).await })
44 });
45 self.slot.set(Inner { dispatch }).is_ok()
46 }
47}