use icu_locid::LanguageIdentifier;
use litemap::LiteMap;
use serde::{
de::{IgnoredAny, MapAccess, Visitor},
Deserialize, Deserializer,
};
#[derive(PartialEq, Debug, Clone, Deserialize)]
pub struct ZoneFormat(pub LiteMap<String, String>);
#[derive(PartialEq, Debug, Clone, Deserialize)]
pub struct MetaZone {
pub long: Option<ZoneFormat>,
pub short: Option<ZoneFormat>,
}
#[derive(PartialEq, Debug, Clone, Deserialize)]
pub struct MetaZones(pub LiteMap<String, MetaZone>);
#[derive(PartialEq, Debug, Clone, Deserialize)]
pub struct LocationWithExemplarCity {
pub long: Option<ZoneFormat>,
pub short: Option<ZoneFormat>,
#[serde(rename = "exemplarCity")]
pub exemplar_city: String,
}
#[derive(PartialEq, Debug, Clone, Deserialize)]
pub struct LocationWithShort {
pub long: Option<ZoneFormat>,
pub short: ZoneFormat,
#[serde(rename = "exemplarCity")]
pub exemplar_city: Option<String>,
}
#[derive(PartialEq, Debug, Clone, Deserialize)]
pub struct LocationWithLong {
pub long: ZoneFormat,
pub short: Option<ZoneFormat>,
#[serde(rename = "exemplarCity")]
pub exemplar_city: Option<String>,
}
#[derive(PartialEq, Debug, Clone, Deserialize)]
#[serde(untagged)]
#[allow(clippy::enum_variant_names)]
pub enum Location {
LocationWithCity(LocationWithExemplarCity),
LocationWithLong(LocationWithLong),
LocationWithShort(LocationWithShort),
}
#[derive(PartialEq, Debug, Clone, Deserialize)]
#[serde(untagged)]
pub enum LocationOrSubRegion {
Location(Location),
SubRegion(LiteMap<String, Location>),
}
#[derive(PartialEq, Debug, Clone, Default, Deserialize)]
pub struct Region(pub LiteMap<String, LocationOrSubRegion>);
#[derive(PartialEq, Debug, Clone, Default, Deserialize)]
pub struct Zones(pub LiteMap<String, Region>);
#[derive(PartialEq, Debug, Default, Clone)]
pub struct TimeZoneNames {
pub hour_format: String,
pub gmt_format: String,
pub gmt_zero_format: String,
pub region_format: String,
pub region_format_variants: LiteMap<String, String>,
pub fallback_format: String,
pub zone: Zones,
pub metazone: Option<MetaZones>,
}
pub struct TimeZoneNamesVisitor;
impl<'de> Visitor<'de> for TimeZoneNamesVisitor {
type Value = TimeZoneNames;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("formatting data by numbering system")
}
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut time_zone_names = TimeZoneNames::default();
while let Some(key) = map.next_key::<String>()? {
if key.eq("hourFormat") {
let value = map.next_value::<String>()?;
time_zone_names.hour_format = value;
} else if key.eq("gmtFormat") {
let value = map.next_value::<String>()?;
time_zone_names.gmt_format = value;
} else if key.eq("gmtZeroFormat") {
let value = map.next_value::<String>()?;
time_zone_names.gmt_zero_format = value;
} else if key.eq("fallbackFormat") {
let value = map.next_value::<String>()?;
time_zone_names.fallback_format = value;
} else if key.starts_with("regionFormat") {
let value = map.next_value::<String>()?;
if key.contains('-') {
let variant = key.split('-').last().unwrap();
time_zone_names
.region_format_variants
.insert(variant.into(), value);
} else {
time_zone_names.region_format = value
}
} else if key.eq("metazone") {
let value = map.next_value::<MetaZones>()?;
time_zone_names.metazone = Some(value);
} else if key.eq("zone") {
let value = map.next_value::<Zones>()?;
time_zone_names.zone = value;
} else {
map.next_value::<IgnoredAny>()?;
}
}
Ok(time_zone_names)
}
}
impl<'de> Deserialize<'de> for TimeZoneNames {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_map(TimeZoneNamesVisitor)
}
}
#[derive(PartialEq, Debug, Clone, Deserialize)]
pub struct Dates {
#[serde(rename = "timeZoneNames")]
pub time_zone_names: TimeZoneNames,
}
#[derive(PartialEq, Debug, Deserialize)]
pub struct LangTimeZones {
pub dates: Dates,
}
#[derive(PartialEq, Debug, Deserialize)]
pub struct LangData(pub LiteMap<LanguageIdentifier, LangTimeZones>);
#[derive(PartialEq, Debug, Deserialize)]
pub struct Resource {
pub main: LangData,
}