maplibre/tcs/
resources.rs1use std::{any, any::TypeId, cell::UnsafeCell, collections::HashMap};
2
3use downcast_rs::{impl_downcast, Downcast};
4
5use crate::tcs::{EphemeralQueryState, GlobalQueryState, QueryState};
6
7pub trait Resource: Downcast + 'static {}
8impl_downcast!(Resource);
9
10impl<T> Resource for T where T: 'static {}
11
12#[derive(Default)]
13pub struct Resources {
14 resources: Vec<UnsafeCell<Box<dyn Resource>>>,
15 index: HashMap<TypeId, usize>,
16}
17
18impl Resources {
19 pub fn init<R: Resource + Default>(&mut self) {
20 self.insert(R::default());
21 }
22
23 pub fn get_or_init_mut<R: Resource + Default>(&mut self) -> &mut R {
24 if self.exists::<R>() {
25 self.get_mut::<R>()
26 .expect("unable get get just initialized resource")
27 } else {
28 self.init::<R>();
29 self.get_mut()
30 .expect("unable get get just initialized resource")
31 }
32 }
33
34 pub fn insert<R: Resource>(&mut self, resource: R) {
35 let index = self.resources.len();
36 self.resources.push(UnsafeCell::new(Box::new(resource)));
37 self.index.insert(TypeId::of::<R>(), index);
38 }
39
40 pub fn exists<R: Resource>(&self) -> bool {
41 self.index.contains_key(&TypeId::of::<R>())
42 }
43
44 pub fn get<R: Resource>(&self) -> Option<&R> {
45 if let Some(index) = self.index.get(&TypeId::of::<R>()) {
46 unsafe {
47 return Some(
48 self.resources[*index]
49 .get()
51 .as_ref()
52 .unwrap()
53 .downcast_ref()
54 .expect("inserted resource has wrong TypeId"),
55 );
56 }
57 }
58 None
59 }
60
61 pub fn get_mut<R: Resource>(&mut self) -> Option<&mut R> {
62 if let Some(index) = self.index.get(&TypeId::of::<R>()) {
63 return Some(
64 self.resources[*index]
65 .get_mut()
66 .downcast_mut()
67 .expect("inserted resource has wrong TypeId"),
68 );
69 }
70 None
71 }
72
73 pub fn query<Q: ResourceQuery>(&self) -> Option<Q::Item<'_>> {
74 let mut global_state = GlobalQueryState::default();
75 let state = <Q::State<'_> as QueryState>::create(&mut global_state);
76 Q::query(self, state)
77 }
78
79 pub fn query_mut<Q: ResourceQueryMut>(&mut self) -> Option<Q::MutItem<'_>> {
80 let mut global_state = GlobalQueryState::default();
81 let state = <Q::State<'_> as QueryState>::create(&mut global_state);
82 Q::query_mut(self, state)
83 }
84}
85
86pub trait ResourceQuery {
89 type Item<'r>;
90
91 type State<'s>: QueryState<'s>;
92
93 fn query<'r, 's>(resources: &'r Resources, state: Self::State<'s>) -> Option<Self::Item<'r>>;
94}
95
96impl<'a, R: Resource> ResourceQuery for &'a R {
97 type Item<'r> = &'r R;
98 type State<'s> = EphemeralQueryState<'s>;
99
100 fn query<'r, 's>(resources: &'r Resources, _state: Self::State<'s>) -> Option<Self::Item<'r>> {
101 resources.get::<R>()
102 }
103}
104
105pub trait ResourceQueryMut {
108 type MutItem<'r>;
109
110 type State<'s>: QueryState<'s>;
111
112 fn query_mut<'r, 's>(
113 resources: &'r mut Resources,
114 state: Self::State<'s>,
115 ) -> Option<Self::MutItem<'r>>;
116}
117
118impl<'a, R: Resource> ResourceQueryMut for &'a R {
119 type MutItem<'r> = &'r R;
120 type State<'s> = EphemeralQueryState<'s>;
121
122 fn query_mut<'r, 's>(
123 resources: &'r mut Resources,
124 state: Self::State<'s>,
125 ) -> Option<Self::MutItem<'r>> {
126 <&R as ResourceQuery>::query(resources, state)
127 }
128}
129
130impl<'a, R: Resource> ResourceQueryMut for &'a mut R {
131 type MutItem<'r> = &'r mut R;
132 type State<'s> = EphemeralQueryState<'s>;
133
134 fn query_mut<'r, 's>(
135 resources: &'r mut Resources,
136 _state: Self::State<'s>,
137 ) -> Option<Self::MutItem<'r>> {
138 resources.get_mut::<R>()
139 }
140}
141
142pub trait ResourceQueryUnsafe: ResourceQueryMut {
145 unsafe fn query_unsafe<'r, 's>(
146 resources: &'r Resources,
147 state: Self::State<'s>,
148 ) -> Option<Self::MutItem<'r>>;
149}
150
151impl<'a, R: Resource> ResourceQueryUnsafe for &'a R {
152 unsafe fn query_unsafe<'r, 's>(
153 resources: &'r Resources,
154 state: Self::State<'s>,
155 ) -> Option<Self::MutItem<'r>> {
156 <&R as ResourceQuery>::query(resources, state)
157 }
158}
159
160impl<'a, R: Resource> ResourceQueryUnsafe for &'a mut R {
161 unsafe fn query_unsafe<'r, 's>(
164 resources: &'r Resources,
165 state: Self::State<'s>,
166 ) -> Option<Self::MutItem<'r>> {
167 let id = TypeId::of::<R>();
168 let borrowed = &mut state.state.mutably_borrowed;
169
170 if borrowed.contains(&id) {
171 panic!(
172 "tried to borrow an {} more than once mutably",
173 any::type_name::<R>()
174 )
175 }
176
177 borrowed.insert(id);
178
179 if let Some(index) = resources.index.get(&TypeId::of::<R>()) {
180 return Some(
181 resources.resources[*index]
182 .get()
183 .as_mut()
184 .unwrap()
185 .downcast_mut()
186 .expect("inserted resource has wrong TypeId"),
187 );
188 }
189
190 None
191 }
192}
193
194macro_rules! impl_resource_query {
197 ($($param: ident),*) => {
198 impl<$($param: ResourceQuery),*> ResourceQuery for ($($param,)*) {
199 type Item<'r> = ($($param::Item<'r>,)*);
200 type State<'s> = EphemeralQueryState<'s>;
201
202 fn query<'r, 's>(resources: &'r Resources, mut state: Self::State<'s>) -> Option<Self::Item<'r>> {
203 Some(
204 (
205 $($param::query(resources, state.clone_to::<$param::State<'_>>())?,)*
206 )
207 )
208 }
209 }
210
211 impl<$($param: ResourceQueryMut + ResourceQueryUnsafe + 'static),*> ResourceQueryMut for ($($param,)*)
212 {
213 type MutItem<'r> = ($($param::MutItem<'r>,)*);
214 type State<'s> = EphemeralQueryState<'s>;
215
216 fn query_mut<'r, 's>(
217 resources: &'r mut Resources,
218 mut state: Self::State<'s>,
219 ) -> Option<Self::MutItem<'r>> {
220 unsafe {
221 Some(
222 (
223 $(<$param as ResourceQueryUnsafe>::query_unsafe(resources, state.clone_to::<$param::State<'_>>())?,)*
224 )
225 )
226 }
227 }
228 }
229 };
230}
231
232impl_resource_query!(R1);
233impl_resource_query!(R1, R2);
234impl_resource_query!(R1, R2, R3);
235impl_resource_query!(R1, R2, R3, R4);
236impl_resource_query!(R1, R2, R3, R4, R5);
237impl_resource_query!(R1, R2, R3, R4, R5, R6);