Skip to main content

modo/service/
state.rs

1use std::any::{Any, TypeId};
2use std::collections::HashMap;
3use std::sync::Arc;
4
5use super::Registry;
6
7/// Immutable, cheaply-cloneable application state produced by [`Registry::into_state`].
8///
9/// `AppState` is the value passed to [`Router::with_state`](axum::Router::with_state).
10/// axum clones it for every request, so the underlying service map is wrapped in an
11/// [`Arc`] and never copied.
12///
13/// Retrieve individual services inside handlers through the
14/// [`Service<T>`](crate::extractor::Service) extractor, which calls
15/// [`AppState::get`] internally.
16#[derive(Clone)]
17pub struct AppState {
18    services: Arc<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
19}
20
21impl AppState {
22    /// Returns a reference-counted handle to the service registered as type `T`,
23    /// or `None` if no such service exists.
24    pub fn get<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> {
25        self.services
26            .get(&TypeId::of::<T>())
27            .and_then(|arc| arc.clone().downcast::<T>().ok())
28    }
29}
30
31impl From<Registry> for AppState {
32    /// Converts a [`Registry`] into an [`AppState`] by freezing the service map.
33    fn from(registry: Registry) -> Self {
34        Self {
35            services: Arc::new(registry.into_inner()),
36        }
37    }
38}