limnus_local_resource/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/limnus
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5pub mod prelude;
6
7use std::any::{Any, TypeId, type_name};
8use std::collections::HashMap;
9use std::fmt::Debug;
10
11/// A trait representing a local resource (single threaded). It extends `Any` to allow for downcasting.
12pub trait LocalResource: Any + Debug + 'static {}
13
14/// Storage for various resources identified by their `TypeId`.
15#[derive(Debug)]
16pub struct LocalResourceStorage {
17    resources: HashMap<TypeId, Box<dyn Any + 'static>>,
18}
19
20impl Default for LocalResourceStorage {
21    fn default() -> Self {
22        Self::new()
23    }
24}
25
26impl LocalResourceStorage {
27    #[must_use]
28    pub fn new() -> Self {
29        Self {
30            resources: HashMap::new(),
31        }
32    }
33
34    /// Inserts a new resource into the storage.
35    ///
36    /// If a resource of the same type already exists, it will be replaced.
37    pub fn insert<R: LocalResource>(&mut self, resource: R) {
38        self.resources.insert(TypeId::of::<R>(), Box::new(resource));
39    }
40
41    /// Retrieves a reference to a resource of type `R`.
42    ///
43    /// # Panics
44    ///
45    /// Panics if the resource does not exist.
46    #[must_use]
47    pub fn fetch<R: LocalResource>(&self) -> &R {
48        self.resources
49            .get(&TypeId::of::<R>())
50            .unwrap_or_else(|| panic!("LocalResource of type '{}' not found.", type_name::<R>()))
51            .downcast_ref::<R>()
52            .expect("Failed to downcast resource to the expected type.")
53    }
54
55    /// Retrieves a mutable reference to a resource of type `R`.
56    ///
57    /// # Panics
58    ///
59    /// Panics if the resource does not exist.
60    #[must_use]
61    pub fn fetch_mut<R: LocalResource>(&mut self) -> &mut R {
62        self.resources
63            .get_mut(&TypeId::of::<R>())
64            .unwrap_or_else(|| panic!("LocalResource of type '{}' not found.", type_name::<R>()))
65            .downcast_mut::<R>()
66            .expect("Failed to downcast resource to the expected type.")
67    }
68
69    /// Retrieves an immutable reference to a resource of type `R`.
70    ///
71    /// Returns `Some(&R)` if the resource exists, otherwise returns `None`.
72    #[must_use]
73    pub fn get<R: LocalResource + 'static>(&self) -> Option<&R> {
74        self.resources
75            .get(&TypeId::of::<R>())
76            .and_then(|boxed_any| boxed_any.downcast_ref::<R>())
77    }
78
79    /// Retrieves a mutable reference to a resource of type `R`.
80    ///
81    /// Returns `Some(&mut R)` if the resource exists, otherwise returns `None`.
82    #[must_use]
83    pub fn get_mut<R: LocalResource + 'static>(&mut self) -> Option<&mut R> {
84        self.resources
85            .get_mut(&TypeId::of::<R>())
86            .and_then(|boxed_any| boxed_any.downcast_mut::<R>())
87    }
88
89    /// Removes a resource of type `R` from the storage.
90    ///
91    /// Returns `Some(R)` if the resource was present, otherwise `None`.
92    ///
93    /// # Panics
94    ///
95    /// Panics if the resource stored is not of the expected type `R`. Should be very unlikely.
96    pub fn remove<R: LocalResource>(&mut self) -> Option<R> {
97        self.resources.remove(&TypeId::of::<R>()).map(|boxed_any| {
98            *boxed_any
99                .downcast::<R>()
100                .expect("Failed to downcast resource to the expected type.")
101        })
102    }
103
104    /// Checks if a resource of type `R` exists in the storage.
105    #[must_use]
106    pub fn contains<R: LocalResource>(&self) -> bool {
107        self.resources.contains_key(&TypeId::of::<R>())
108    }
109}