#![cfg(not(tarpaulin_include))]
use std::{borrow::Cow, io::Read};
use geo::Geometry;
use serde_json::{Map, Value};
#[cfg(feature = "self-contained")]
use bincode::{
de::{BorrowDecoder, Decoder},
error::DecodeError,
BorrowDecode, Decode, Encode,
};
use crate::{
base::types::Float,
geo::shared::{get_geojson_features_from_string, simplify_geometry, CanGetGeoJsonFeaturesFromSource, EncodableGeometry, EncodableString, HasGeometry, HasProperties, IdFeaturePair},
};
use super::shared::IsTimezone;
#[cfg(not(feature = "extrasimplified"))]
const SIMPLIFICATION_EPSILON: Float = 0.0001;
#[cfg(feature = "extrasimplified")]
const SIMPLIFICATION_EPSILON: Float = 0.01;
#[cfg(not(target_family = "wasm"))]
pub fn get_geojson_features_from_source() -> geojson::FeatureCollection {
let response = reqwest::blocking::get(ADDRESS).unwrap();
let geojson_zip = response.bytes().unwrap();
let mut zip = zip::ZipArchive::new(std::io::Cursor::new(geojson_zip)).unwrap();
let mut geojson_input = String::new();
zip.by_index(0).unwrap().read_to_string(&mut geojson_input).unwrap();
get_geojson_features_from_string(&geojson_input)
}
pub static ADDRESS: &str = "https://github.com/evansiroky/timezone-boundary-builder/releases/download/2024a/timezones-with-oceans.geojson.zip";
pub static TIMEZONE_BINCODE_DESTINATION_NAME: &str = "osm_time_zones.bincode";
pub static LOOKUP_BINCODE_DESTINATION_NAME: &str = "osm_time_zone_lookup.bincode";
#[derive(Debug)]
#[cfg_attr(feature = "self-contained", derive(Encode))]
pub struct OsmTimezone {
pub id: usize,
pub identifier: EncodableString,
pub geometry: EncodableGeometry,
}
#[cfg(feature = "self-contained")]
impl Decode for OsmTimezone {
fn decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
where
D: Decoder,
{
let id = usize::decode(decoder)?;
let identifier = EncodableString::decode(decoder)?;
let geometry = EncodableGeometry::decode(decoder)?;
Ok(OsmTimezone { id, identifier, geometry })
}
}
#[cfg(feature = "self-contained")]
impl<'de> BorrowDecode<'de> for OsmTimezone
where
'de: 'static,
{
fn borrow_decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
where
D: BorrowDecoder<'de>,
{
let id = usize::decode(decoder)?;
let identifier = EncodableString::borrow_decode(decoder)?;
let geometry = EncodableGeometry::borrow_decode(decoder)?;
Ok(OsmTimezone { id, identifier, geometry })
}
}
impl PartialEq for OsmTimezone {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl From<IdFeaturePair> for OsmTimezone {
fn from(value: IdFeaturePair) -> OsmTimezone {
let id = value.0;
let properties = value.1.properties.as_ref().unwrap();
let geometry = value.1.geometry.as_ref().unwrap();
let identifier = EncodableString(Cow::Owned(properties.get("tzid").unwrap().as_str().unwrap().to_string()));
let geometry: Geometry<Float> = geometry.value.clone().try_into().unwrap();
let geometry = EncodableGeometry(simplify_geometry(geometry, SIMPLIFICATION_EPSILON));
OsmTimezone { id, identifier, geometry }
}
}
impl IsTimezone for OsmTimezone {
fn identifier(&self) -> &str {
self.identifier.as_ref()
}
}
impl HasGeometry for OsmTimezone {
fn id(&self) -> usize {
self.id
}
fn geometry(&self) -> &Geometry<Float> {
&self.geometry.0
}
}
impl HasProperties for OsmTimezone {
fn properties(&self) -> Map<String, Value> {
let mut properties = Map::new();
properties.insert("identifier".to_string(), Value::String(self.identifier.to_string()));
properties
}
}
#[cfg(not(target_family = "wasm"))]
impl CanGetGeoJsonFeaturesFromSource for OsmTimezone {
fn get_geojson_features_from_source() -> geojson::FeatureCollection {
get_geojson_features_from_source()
}
}