use geo::{Contains, Coord};
use rtz_core::{
base::types::Float,
geo::shared::{ConcreteVec, HasGeometry, HasProperties, Id, RoundDegree, RoundLngLat, ToGeoJson},
};
use std::collections::HashMap;
pub trait HasItemData
where
Self: Sized,
{
fn get_mem_items() -> &'static ConcreteVec<Self>;
}
pub trait HasLookupData: HasItemData
where
Self: Sized,
{
type Lookup: AsRef<[Id]>;
fn get_mem_lookup() -> &'static HashMap<RoundLngLat, Self::Lookup>;
}
pub(crate) trait MapIntoItem<T> {
fn map_into_item(self) -> Option<&'static T>;
}
impl<T> MapIntoItem<T> for Option<&u16>
where
T: HasItemData,
{
fn map_into_item(self) -> Option<&'static T> {
let Some(value) = self else {
return None;
};
let items = T::get_mem_items();
items.get(*value as usize)
}
}
pub(crate) trait MapIntoItems<T> {
fn map_into_items(self) -> Option<Vec<&'static T>>;
}
impl<A, T> MapIntoItems<T> for Option<A>
where
A: AsRef<[Id]>,
T: HasItemData,
{
fn map_into_items(self) -> Option<Vec<&'static T>> {
let Some(value) = self else {
return None;
};
let source = value.as_ref();
let items = T::get_mem_items();
let mut result = Vec::with_capacity(source.len());
for id in source {
let item = &items[*id as usize];
result.push(item);
}
Some(result)
}
}
#[cfg(feature = "self-contained")]
pub fn decode_binary_data<T>(data: &'static [u8]) -> T
where
T: bincode::Decode + bincode::BorrowDecode<'static>,
{
#[cfg(not(feature = "owned-decode"))]
let (value, _len): (T, usize) = bincode::borrow_decode_from_slice(data, rtz_core::geo::shared::get_global_bincode_config())
.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.");
#[cfg(feature = "owned-decode")]
let (value, _len): (T, usize) = bincode::decode_from_slice(data, rtz_core::geo::shared::get_global_bincode_config())
.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.");
value
}
pub trait CanPerformGeoLookup: HasLookupData + HasGeometry + HasProperties
where
Self: 'static,
{
fn lookup(xf: Float, yf: Float) -> Vec<&'static Self> {
let x = xf.floor() as RoundDegree;
let y = yf.floor() as RoundDegree;
let Some(suggestions) = Self::get_lookup_suggestions(x, y) else {
return Vec::new();
};
suggestions.into_iter().filter(|&i| i.geometry().contains(&Coord { x: xf, y: yf })).collect()
}
#[allow(dead_code)]
fn lookup_slow(xf: Float, yf: Float) -> Vec<&'static Self> {
Self::get_mem_items().into_iter().filter(|&i| i.geometry().contains(&Coord { x: xf, y: yf })).collect()
}
fn memory_data_to_geojson() -> String {
let geojson = Self::get_mem_items().to_geojson();
geojson.to_json_value().to_string()
}
fn get_lookup_suggestions(x: RoundDegree, y: RoundDegree) -> Option<Vec<&'static Self>> {
let cache = Self::get_mem_lookup();
cache.get(&(x, y)).map_into_items()
}
}