Skip to main content

lgui_core/
resources.rs

1use std::{
2    any::{type_name, Any, TypeId},
3    collections::HashMap,
4    sync::{Arc, RwLock, Weak},
5};
6
7/// Application-owned typed values shared by every component and window.
8#[derive(Clone, Default)]
9pub struct Resources {
10    values: Arc<RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>>,
11}
12
13#[derive(Clone)]
14pub struct WeakResources {
15    values: Weak<RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>>,
16}
17
18impl Resources {
19    pub fn new() -> Self {
20        Self::default()
21    }
22
23    pub fn downgrade(&self) -> WeakResources {
24        WeakResources {
25            values: Arc::downgrade(&self.values),
26        }
27    }
28
29    pub fn provide<T>(&self, value: T)
30    where
31        T: Send + Sync + 'static,
32    {
33        self.values
34            .write()
35            .expect("application resources poisoned")
36            .insert(TypeId::of::<T>(), Arc::new(value));
37    }
38
39    pub fn get<T>(&self) -> Option<Arc<T>>
40    where
41        T: Send + Sync + 'static,
42    {
43        self.values
44            .read()
45            .expect("application resources poisoned")
46            .get(&TypeId::of::<T>())
47            .cloned()
48            .and_then(|value| value.downcast::<T>().ok())
49    }
50
51    pub fn get_or_insert_with<T>(&self, create: impl FnOnce() -> T) -> Arc<T>
52    where
53        T: Send + Sync + 'static,
54    {
55        let mut values = self.values.write().expect("application resources poisoned");
56        values
57            .entry(TypeId::of::<T>())
58            .or_insert_with(|| Arc::new(create()))
59            .clone()
60            .downcast::<T>()
61            .unwrap_or_else(|_| {
62                panic!(
63                    "application resource type mismatch for `{}`",
64                    type_name::<T>()
65                )
66            })
67    }
68
69    pub fn require<T>(&self) -> Arc<T>
70    where
71        T: Send + Sync + 'static,
72    {
73        self.get::<T>()
74            .unwrap_or_else(|| panic!("missing application resource `{}`", type_name::<T>()))
75    }
76}
77
78impl WeakResources {
79    pub fn upgrade(&self) -> Option<Resources> {
80        self.values.upgrade().map(|values| Resources { values })
81    }
82}
83
84#[cfg(test)]
85#[path = "resources_test.rs"]
86mod tests;