opening_hours/localization/country/
mod.rs1mod generated;
2
3use std::collections::HashMap;
4use std::sync::{Arc, LazyLock};
5
6use compact_calendar::CompactCalendar;
7use flate2::bufread::DeflateDecoder;
8
9use crate::ContextHolidays;
10
11pub use generated::*;
13
14#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
20pub struct UnknownCountryCode(pub String);
21
22impl std::fmt::Display for UnknownCountryCode {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 write!(f, "Unknown ISO code `{}`", self.0)
25 }
26}
27
28impl std::error::Error for UnknownCountryCode {}
29
30impl Country {
35 #[cfg(feature = "auto-country")]
45 pub fn try_from_coords(coords: crate::localization::Coordinates) -> Option<Self> {
46 use country_boundaries::CountryBoundaries;
47 use std::io::Read;
48
49 static BOUNDARIES: LazyLock<CountryBoundaries> = LazyLock::new(|| {
50 let mut buffer = Vec::new();
51
52 DeflateDecoder::new(include_bytes!(env!("COUNTRY_BOUNDS_FILE")).as_slice())
53 .read_to_end(&mut buffer)
54 .expect("unable to parse country bounds data");
55
56 CountryBoundaries::from_reader(buffer.as_slice())
57 .expect("failed to load country boundaries database")
58 });
59
60 for cc in BOUNDARIES.ids(country_boundaries::LatLon::new(coords.lat(), coords.lon()).ok()?)
61 {
62 if let Ok(res) = cc.parse() {
63 return Some(res);
64 }
65 }
66
67 None
68 }
69
70 pub fn holidays(self) -> ContextHolidays {
81 fn decode_holidays_db(
82 countries: &'static str,
83 encoded_data: &'static [u8],
84 ) -> HashMap<Country, Arc<CompactCalendar>> {
85 let mut reader = DeflateDecoder::new(encoded_data);
86
87 countries
88 .split(',')
89 .filter_map(|region| {
90 let calendar = CompactCalendar::deserialize(&mut reader)
91 .expect("unable to parse holiday data");
92
93 let Ok(country) = region.parse() else {
94 #[cfg(feature = "log")]
95 log::warn!("Unknown initialized country code {region}");
96 return None;
97 };
98
99 Some((country, Arc::new(calendar)))
100 })
101 .collect()
102 }
103
104 static DB_PUBLIC: LazyLock<HashMap<Country, Arc<CompactCalendar>>> = LazyLock::new(|| {
105 decode_holidays_db(
106 env!("HOLIDAYS_PUBLIC_REGIONS"),
107 include_bytes!(env!("HOLIDAYS_PUBLIC_FILE")),
108 )
109 });
110
111 static DB_SCHOOL: LazyLock<HashMap<Country, Arc<CompactCalendar>>> = LazyLock::new(|| {
112 decode_holidays_db(
113 env!("HOLIDAYS_SCHOOL_REGIONS"),
114 include_bytes!(env!("HOLIDAYS_SCHOOL_FILE")),
115 )
116 });
117
118 ContextHolidays::new(
119 DB_PUBLIC.get(&self).cloned().unwrap_or_default(),
120 DB_SCHOOL.get(&self).cloned().unwrap_or_default(),
121 )
122 }
123}