1use std::{
2 any,
3 any::TypeId,
4 cell::UnsafeCell,
5 collections::{btree_map, BTreeMap, HashSet},
6};
7
8use downcast_rs::{impl_downcast, Downcast};
9
10use crate::{
11 coords::{Quadkey, WorldTileCoords},
12 io::geometry_index::GeometryIndex,
13};
14
15#[derive(Copy, Clone, Debug)]
16pub struct Tile {
17 pub coords: WorldTileCoords,
18}
19
20pub trait TileComponent: Downcast + 'static {}
23impl_downcast!(TileComponent);
24
25#[derive(Default)]
26pub struct Tiles {
27 pub tiles: BTreeMap<Quadkey, Tile>,
28 pub components: BTreeMap<Quadkey, Vec<UnsafeCell<Box<dyn TileComponent>>>>,
29 pub geometry_index: GeometryIndex,
30}
31
32impl Tiles {
33 pub fn query<Q: ComponentQuery>(&self, coords: WorldTileCoords) -> Option<Q::Item<'_>> {
34 let mut global_state = GlobalQueryState::default();
35 let state = <Q::State<'_> as QueryState>::create(&mut global_state);
36 Q::query(self, Tile { coords }, state)
37 }
38
39 pub fn query_mut<Q: ComponentQueryMut>(
40 &mut self,
41 coords: WorldTileCoords,
42 ) -> Option<Q::MutItem<'_>> {
43 let mut global_state = GlobalQueryState::default();
44 let state = <Q::State<'_> as QueryState>::create(&mut global_state);
45 Q::query_mut(self, Tile { coords }, state)
46 }
47
48 pub fn exists(&self, coords: WorldTileCoords) -> bool {
49 if let Some(key) = coords.build_quad_key() {
50 self.tiles.get(&key).is_some()
51 } else {
52 false
53 }
54 }
55
56 pub fn spawn_mut(&mut self, coords: WorldTileCoords) -> Option<TileSpawnResult> {
57 if let Some(key) = coords.build_quad_key() {
58 if let Some(tile) = self.tiles.get(&key) {
59 let tile = *tile;
60 Some(TileSpawnResult { tiles: self, tile })
61 } else {
62 let tile = Tile { coords };
63 self.tiles.insert(key, tile);
64 self.components.insert(key, Vec::new());
65 Some(TileSpawnResult { tiles: self, tile })
66 }
67 } else {
68 None
69 }
70 }
71
72 pub fn clear(&mut self) {
73 self.tiles.clear();
74 self.components.clear();
75 }
76}
77
78pub struct TileSpawnResult<'t> {
79 tiles: &'t mut Tiles,
80 tile: Tile,
81}
82
83impl<'w> TileSpawnResult<'w> {
84 pub fn insert<T: TileComponent>(&mut self, component: T) -> &mut Self {
85 let components = &mut self.tiles.components;
86 let coords = self.tile.coords;
87
88 if let Some(entry) = coords.build_quad_key().map(|key| components.entry(key)) {
89 match entry {
90 btree_map::Entry::Vacant(_entry) => {
91 panic!("Can not add a component at {coords}. Entity does not exist.",)
92 }
93 btree_map::Entry::Occupied(mut entry) => {
94 entry.get_mut().push(UnsafeCell::new(Box::new(component)));
95 }
96 }
97 }
98 self
99 }
100}
101
102#[derive(Default)]
103pub struct GlobalQueryState {
104 mutably_borrowed: HashSet<TypeId>,
105}
106
107pub trait QueryState<'s> {
108 fn create(state: &'s mut GlobalQueryState) -> Self;
109 fn clone_to<'a, S: QueryState<'a>>(&'a mut self) -> S;
110}
111
112pub struct EphemeralQueryState<'s> {
113 state: &'s mut GlobalQueryState,
114}
115
116impl<'s> QueryState<'s> for EphemeralQueryState<'s> {
117 fn create(state: &'s mut GlobalQueryState) -> Self {
118 Self { state }
119 }
120
121 fn clone_to<'a, S: QueryState<'a>>(&'a mut self) -> S {
122 S::create(self.state)
123 }
124}
125
126pub trait ComponentQuery {
129 type Item<'t>;
130
131 type State<'s>: QueryState<'s>;
132
133 fn query<'t, 's>(
134 tiles: &'t Tiles,
135 tile: Tile,
136 state: Self::State<'s>,
137 ) -> Option<Self::Item<'t>>;
138}
139
140impl<'a, T: TileComponent> ComponentQuery for &'a T {
141 type Item<'t> = &'t T;
142 type State<'s> = EphemeralQueryState<'s>;
143
144 fn query<'t, 's>(
145 tiles: &'t Tiles,
146 tile: Tile,
147 _state: Self::State<'s>,
148 ) -> Option<Self::Item<'t>> {
149 let components = tiles.components.get(&tile.coords.build_quad_key()?)?;
150
151 components
152 .iter()
153 .find(|component| unsafe {
155 component.get().as_ref().unwrap().as_ref().type_id() == TypeId::of::<T>()
156 })
157 .map(|component| unsafe {
158 component
159 .get()
160 .as_ref()
161 .unwrap()
162 .as_ref()
163 .downcast_ref()
164 .expect("inserted component has wrong TypeId")
165 })
166 }
167}
168
169pub trait ComponentQueryMut {
172 type MutItem<'t>;
173
174 type State<'s>: QueryState<'s>;
175
176 fn query_mut<'t, 's>(
177 tiles: &'t mut Tiles,
178 tile: Tile,
179 state: Self::State<'s>,
180 ) -> Option<Self::MutItem<'t>>;
181}
182
183impl<'a, T: TileComponent> ComponentQueryMut for &'a T {
184 type MutItem<'t> = &'t T;
185 type State<'s> = EphemeralQueryState<'s>;
186
187 fn query_mut<'t, 's>(
188 tiles: &'t mut Tiles,
189 tile: Tile,
190 state: Self::State<'s>,
191 ) -> Option<Self::MutItem<'t>> {
192 <&T as ComponentQuery>::query(tiles, tile, state)
193 }
194}
195
196impl<'a, T: TileComponent> ComponentQueryMut for &'a mut T {
197 type MutItem<'t> = &'t mut T;
198 type State<'s> = EphemeralQueryState<'s>;
199
200 fn query_mut<'t, 's>(
201 tiles: &'t mut Tiles,
202 tile: Tile,
203 _state: Self::State<'s>,
204 ) -> Option<Self::MutItem<'t>> {
205 let components = tiles.components.get_mut(&tile.coords.build_quad_key()?)?;
206
207 components
208 .iter_mut()
209 .find(|component| unsafe {
210 component.get().as_ref().unwrap().as_ref().type_id() == TypeId::of::<T>()
211 })
212 .map(|component| {
213 component
214 .get_mut()
215 .as_mut()
216 .downcast_mut()
217 .expect("inserted component has wrong TypeId")
218 })
219 }
220}
221
222pub trait ComponentQueryUnsafe: ComponentQueryMut {
225 unsafe fn query_unsafe<'t, 's>(
226 tiles: &'t Tiles,
227 tile: Tile,
228 state: Self::State<'s>,
229 ) -> Option<Self::MutItem<'t>>;
230}
231
232impl<'a, T: TileComponent> ComponentQueryUnsafe for &'a T {
233 unsafe fn query_unsafe<'t, 's>(
234 tiles: &'t Tiles,
235 tile: Tile,
236 state: Self::State<'s>,
237 ) -> Option<Self::MutItem<'t>> {
238 <&T as ComponentQuery>::query(tiles, tile, state)
239 }
240}
241
242impl<'a, T: TileComponent> ComponentQueryUnsafe for &'a mut T {
243 unsafe fn query_unsafe<'t, 's>(
246 tiles: &'t Tiles,
247 tile: Tile,
248 state: Self::State<'s>,
249 ) -> Option<Self::MutItem<'t>> {
250 let id = TypeId::of::<T>();
251 let borrowed = &mut state.state.mutably_borrowed;
252
253 if borrowed.contains(&id) {
254 panic!(
255 "tried to borrow an {} more than once mutably",
256 any::type_name::<T>()
257 )
258 }
259
260 borrowed.insert(id);
261
262 let components = tiles.components.get(&tile.coords.build_quad_key()?)?;
263
264 components
265 .iter()
266 .find(|component| {
267 component.get().as_ref().unwrap().as_ref().type_id() == TypeId::of::<T>()
268 })
269 .map(|component| {
270 component
271 .get()
272 .as_mut()
273 .unwrap()
274 .downcast_mut()
275 .expect("inserted component has wrong TypeId")
276 })
277 }
278}
279
280impl<CQ1: ComponentQuery, CQ2: ComponentQuery> ComponentQuery for (CQ1, CQ2) {
283 type Item<'t> = (CQ1::Item<'t>, CQ2::Item<'t>);
284 type State<'s> = EphemeralQueryState<'s>;
285
286 fn query<'t, 's>(
287 tiles: &'t Tiles,
288 tile: Tile,
289 mut state: Self::State<'s>,
290 ) -> Option<Self::Item<'t>> {
291 Some((
292 CQ1::query(tiles, tile, state.clone_to::<CQ1::State<'_>>())?,
293 CQ2::query(tiles, tile, state.clone_to::<CQ2::State<'_>>())?,
294 ))
295 }
296}
297
298impl<
299 CQ1: ComponentQueryMut + ComponentQueryUnsafe + 'static,
300 CQ2: ComponentQueryMut + ComponentQueryUnsafe + 'static,
301 > ComponentQueryMut for (CQ1, CQ2)
302{
303 type MutItem<'t> = (CQ1::MutItem<'t>, CQ2::MutItem<'t>);
304 type State<'s> = EphemeralQueryState<'s>;
305
306 fn query_mut<'t, 's>(
307 tiles: &'t mut Tiles,
308 tile: Tile,
309 mut state: Self::State<'s>,
310 ) -> Option<Self::MutItem<'t>> {
311 unsafe {
312 Some((
313 <CQ1 as ComponentQueryUnsafe>::query_unsafe(
314 tiles,
315 tile,
316 state.clone_to::<CQ1::State<'_>>(),
317 )?,
318 <CQ2 as ComponentQueryUnsafe>::query_unsafe(
319 tiles,
320 tile,
321 state.clone_to::<CQ2::State<'_>>(),
322 )?,
323 ))
324 }
325 }
326}