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> {
53 fn map_into_items(self) -> Option<Vec<&'static T>>;
54}
55
56impl<A, T> MapIntoItems<T> for Option<A>
57where
58 A: AsRef<[Id]>,
59 T: HasItemData,
60{
61 fn map_into_items(self) -> Option<Vec<&'static T>> {
62 let value = self?;
63
64 let source = value.as_ref();
65 let items = T::get_mem_items();
66
67 let mut result = Vec::with_capacity(source.len());
68 for id in source {
69 let item = &items[*id as usize];
70 result.push(item);
71 }
72
73 Some(result)
74 }
75}
76
77#[cfg(feature = "self-contained")]
79pub fn decode_binary_data<T>(data: &'static [u8]) -> T
80where
81 T: bincode::Decode + bincode::BorrowDecode<'static>,
82{
83 #[cfg(not(feature = "owned-decode"))]
84 let (value, _len): (T, usize) = bincode::borrow_decode_from_slice(data, rtz_core::geo::shared::get_global_bincode_config())
85 .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.");
86 #[cfg(feature = "owned-decode")]
87 let (value, _len): (T, usize) = bincode::decode_from_slice(data, rtz_core::geo::shared::get_global_bincode_config())
88 .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.");
89
90 value
91}
92
93pub trait CanPerformGeoLookup: HasLookupData + HasGeometry + HasProperties
95where
96 Self: 'static,
97{
98 fn lookup(xf: Float, yf: Float) -> Vec<&'static Self> {
102 let x = xf.floor() as RoundDegree;
103 let y = yf.floor() as RoundDegree;
104
105 let Some(suggestions) = Self::get_lookup_suggestions(x, y) else {
106 return Vec::new();
107 };
108
109 suggestions.into_iter().filter(|&i| i.geometry().contains(&Coord { x: xf, y: yf })).collect()
110 }
111
112 #[allow(dead_code)]
114 fn lookup_slow(xf: Float, yf: Float) -> Vec<&'static Self> {
115 Self::get_mem_items().into_iter().filter(|&i| i.geometry().contains(&Coord { x: xf, y: yf })).collect()
116 }
117
118 fn memory_data_to_geojson() -> String {
120 let geojson = Self::get_mem_items().to_geojson();
121 geojson.to_json_value().to_string()
122 }
123
124 fn get_lookup_suggestions(x: RoundDegree, y: RoundDegree) -> Option<Vec<&'static Self>> {
126 let cache = Self::get_mem_lookup();
127 cache.get(&(x, y)).map_into_items()
128 }
129}