Skip to main content

sword_core/
state.rs

1use std::{
2    any::{Any, TypeId, type_name},
3    collections::HashMap,
4    sync::Arc,
5};
6
7use crate::DependencyInjectionError;
8use parking_lot::RwLock;
9
10/// Application state container for type-safe dependency injection and data sharing.
11///
12/// `State` provides a thread-safe way to store and retrieve shared data across
13/// the entire application. It uses `TypeId` as keys to ensure type safety.
14#[derive(Clone, Debug)]
15pub struct State {
16    inner: Arc<RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>>,
17}
18
19impl State {
20    /// Creates an empty shared state container.
21    pub fn new() -> Self {
22        Self {
23            inner: Arc::new(RwLock::new(HashMap::new())),
24        }
25    }
26
27    /// Extract a clone of the stored value of type `T` from the state.
28    ///
29    /// # Errors
30    ///
31    /// Returns an error if no value of type `T` has been registered in the
32    /// state. This usually indicates that the dependency was never inserted or
33    /// was expected to be provided by a module/provider that was not registered.
34    pub fn get<T>(&self) -> Result<T, DependencyInjectionError>
35    where
36        T: Clone + Send + Sync + 'static,
37    {
38        self.borrow::<T>().map(|value| (*value).clone())
39    }
40
41    /// Borrow an `Arc` to the stored value of type `T` from the state.
42    /// This returns an `Arc<T>` without cloning the underlying value.
43    ///
44    /// # Errors
45    ///
46    /// Returns an error if no value of type `T` has been registered in the
47    /// state or if the stored value cannot be downcast back to `T`.
48    pub fn borrow<T>(&self) -> Result<Arc<T>, DependencyInjectionError>
49    where
50        T: Send + Sync + 'static,
51    {
52        let map = self.inner.read();
53        let type_name = type_name::<T>().to_string();
54
55        let state_ref = map
56            .get(&TypeId::of::<T>())
57            .ok_or_else(|| DependencyInjectionError::dependency_not_found(type_name.clone()))?;
58
59        state_ref
60            .clone()
61            .downcast::<T>()
62            .map_err(|_| DependencyInjectionError::dependency_not_found(type_name))
63    }
64
65    pub fn insert<T: Send + Sync + 'static>(&self, state: T) {
66        self.inner
67            .write()
68            .insert(TypeId::of::<T>(), Arc::new(state));
69    }
70
71    pub(crate) fn insert_instance(&self, type_id: TypeId, instance: Arc<dyn Any + Send + Sync>) {
72        self.inner.write().insert(type_id, instance);
73    }
74}
75
76impl Default for State {
77    fn default() -> Self {
78        Self::new()
79    }
80}