1use geo::{Contains, Coord};
6use rtz_core::{
7 base::types::Float,
8 geo::shared::{ConcreteVec, HasGeometry, HasProperties, Id, RoundDegree, RoundLngLat, ToGeoJson},
9};
10use std::collections::HashMap;
11
12pub trait HasItemData
14where
15 Self: Sized,
16{
17 fn get_mem_items() -> &'static ConcreteVec<Self>;
19}
20
21pub trait HasLookupData: HasItemData
23where
24 Self: Sized,
25{
26 type Lookup: AsRef<[Id]>;
28
29 fn get_mem_lookup() -> &'static HashMap<RoundLngLat, Self::Lookup>;
31}
32
33pub(crate) trait MapIntoItems<T> {
35 fn map_into_items(self) -> Option<Vec<&'static T>>;
36}
37
38impl<A, T> MapIntoItems<T> for Option<A>
39where
40 A: AsRef<[Id]>,
41 T: HasItemData,
42{
43 fn map_into_items(self) -> Option<Vec<&'static T>> {
44 let value = self?;
45
46 let source = value.as_ref();
47 let items = T::get_mem_items();
48
49 let mut result = Vec::with_capacity(source.len());
50 for id in source {
51 let item = &items[*id as usize];
52 result.push(item);
53 }
54
55 Some(result)
56 }
57}
58
59#[cfg(feature = "self-contained")]
61pub fn decode_binary_data<T>(data: &'static [u8]) -> T
62where
63 T: bincode::Decode<()> + bincode::BorrowDecode<'static, ()>,
64{
65 #[cfg(not(feature = "owned-decode"))]
70 let (value, _len): (T, usize) = bincode::borrow_decode_from_slice(data, rtz_core::geo::shared::get_global_bincode_config())
71 .expect("Could not decode binary data: try rebuilding with `force-rebuild` due to a likely precision difference between the generated assets and the current build.");
72 #[cfg(feature = "owned-decode")]
73 let (value, _len): (T, usize) = bincode::decode_from_slice(data, rtz_core::geo::shared::get_global_bincode_config())
74 .expect("Could not decode binary data: try rebuilding with `force-rebuild` due to a likely precision difference between the generated assets and the current build.");
75
76 value
77}
78
79pub trait CanPerformGeoLookup: HasLookupData + HasGeometry + HasProperties
81where
82 Self: 'static,
83{
84 fn lookup(xf: Float, yf: Float) -> Vec<&'static Self> {
88 let x = xf.floor() as RoundDegree;
89 let y = yf.floor() as RoundDegree;
90
91 let Some(suggestions) = Self::get_lookup_suggestions(x, y) else {
92 return Vec::new();
93 };
94
95 suggestions.into_iter().filter(|&i| i.geometry().contains(&Coord { x: xf, y: yf })).collect()
96 }
97
98 #[allow(dead_code)]
100 fn lookup_slow(xf: Float, yf: Float) -> Vec<&'static Self> {
101 Self::get_mem_items().into_iter().filter(|&i| i.geometry().contains(&Coord { x: xf, y: yf })).collect()
102 }
103
104 fn memory_data_to_geojson() -> String {
106 let geojson = Self::get_mem_items().to_geojson();
107 geojson.to_string()
108 }
109
110 fn get_lookup_suggestions(x: RoundDegree, y: RoundDegree) -> Option<Vec<&'static Self>> {
112 let cache = Self::get_mem_lookup();
113 cache.get(&(x, y)).map_into_items()
114 }
115}