use core::fmt::Write;
use icu_locale_core::subtags::{region, Region};
use icu_provider::{DataError, DataPayload, DataProvider};
use crate::{
provider::windows::{TimezoneIdentifiersWindowsV1, WindowsZonesToBcp47Map},
TimeZone,
};
#[derive(Debug)]
pub struct WindowsParser {
data: DataPayload<TimezoneIdentifiersWindowsV1>,
}
impl WindowsParser {
#[expect(clippy::new_ret_no_self)]
#[cfg(feature = "compiled_data")]
pub fn new() -> WindowsParserBorrowed<'static> {
WindowsParserBorrowed::new()
}
icu_provider::gen_buffer_data_constructors!(() -> error: DataError,
functions: [
new: skip,
try_new_with_buffer_provider,
try_new_unstable,
Self,
]
);
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new)]
pub fn try_new_unstable<P>(provider: &P) -> Result<Self, DataError>
where
P: DataProvider<TimezoneIdentifiersWindowsV1> + ?Sized,
{
let data = provider.load(Default::default())?.payload;
Ok(Self { data })
}
pub fn as_borrowed(&self) -> WindowsParserBorrowed<'_> {
WindowsParserBorrowed {
data: self.data.get(),
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct WindowsParserBorrowed<'a> {
data: &'a WindowsZonesToBcp47Map<'a>,
}
impl WindowsParserBorrowed<'static> {
pub fn static_to_owned(&self) -> WindowsParser {
WindowsParser {
data: DataPayload::from_static_ref(self.data),
}
}
}
#[cfg(feature = "compiled_data")]
impl Default for WindowsParserBorrowed<'_> {
fn default() -> Self {
Self::new()
}
}
impl WindowsParserBorrowed<'_> {
#[cfg(feature = "compiled_data")]
pub fn new() -> Self {
WindowsParserBorrowed {
data: crate::provider::Baked::SINGLETON_TIMEZONE_IDENTIFIERS_WINDOWS_V1,
}
}
pub fn parse(self, windows_tz: &str, region: Option<Region>) -> Option<TimeZone> {
self.parse_from_utf8(windows_tz.as_bytes(), region)
}
pub fn parse_from_utf8(self, windows_tz: &[u8], region: Option<Region>) -> Option<TimeZone> {
let mut cursor = self.data.map.cursor();
for &byte in windows_tz {
cursor.step(byte);
}
cursor.step(b'/');
cursor
.write_str(region.unwrap_or(region!("001")).as_str())
.ok()?;
self.data.bcp47_ids.get(cursor.take_value()?)
}
}
#[cfg(test)]
mod tests {
use super::*;
use icu_locale_core::subtags::subtag;
#[test]
fn basic_windows_tz_lookup() {
let win_map = WindowsParser::new();
let result = win_map.parse("Central Standard Time", None);
assert_eq!(result, Some(TimeZone(subtag!("uschi"))));
let result = win_map.parse("Eastern Standard Time", None);
assert_eq!(result, Some(TimeZone(subtag!("usnyc"))));
let result = win_map.parse("Eastern Standard Time", Some(region!("CA")));
assert_eq!(result, Some(TimeZone(subtag!("cator"))));
let result = win_map.parse("GMT Standard Time", None);
assert_eq!(result, Some(TimeZone(subtag!("gblon"))));
}
}