icu_provider_source/cldr_serde/
date_fields.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5//! Serde structs representing CLDR JSON dateFields.json files.
6//!
7//! Sample file:
8//! <https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-dates-full/main/en/dateFields.json>
9
10use std::collections::HashMap;
11
12use icu_pattern::{PatternString, SinglePlaceholder};
13use serde::{
14    de::{Error, IgnoredAny, Visitor},
15    Deserialize,
16};
17
18#[derive(Debug, Deserialize, Default)]
19pub(crate) struct PluralRulesPattern {
20    #[serde(rename = "relativeTimePattern-count-0")]
21    pub(crate) explicit_zero: Option<PatternString<SinglePlaceholder>>,
22    #[serde(rename = "relativeTimePattern-count-1")]
23    pub(crate) explicit_one: Option<PatternString<SinglePlaceholder>>,
24    #[serde(rename = "relativeTimePattern-count-zero")]
25    pub(crate) zero: Option<PatternString<SinglePlaceholder>>,
26    #[serde(rename = "relativeTimePattern-count-one")]
27    pub(crate) one: Option<PatternString<SinglePlaceholder>>,
28    #[serde(rename = "relativeTimePattern-count-two")]
29    pub(crate) two: Option<PatternString<SinglePlaceholder>>,
30    #[serde(rename = "relativeTimePattern-count-few")]
31    pub(crate) few: Option<PatternString<SinglePlaceholder>>,
32    #[serde(rename = "relativeTimePattern-count-many")]
33    pub(crate) many: Option<PatternString<SinglePlaceholder>>,
34    #[serde(rename = "relativeTimePattern-count-other")]
35    pub(crate) other: PatternString<SinglePlaceholder>,
36}
37
38#[derive(Debug)]
39pub(crate) struct Relative {
40    pub(crate) count: i8,
41    pub(crate) pattern: String,
42}
43
44#[derive(Debug)]
45pub(crate) struct Field {
46    pub(crate) _display_name: String,
47    pub(crate) _relative_period: Option<String>,
48    pub(crate) relatives: Vec<Relative>,
49    pub(crate) past: PluralRulesPattern,
50    pub(crate) future: PluralRulesPattern,
51}
52
53pub(crate) struct FieldVisitor;
54
55impl<'de> Visitor<'de> for FieldVisitor {
56    type Value = Field;
57    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
58        write!(formatter, "field data")
59    }
60
61    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
62    where
63        A: serde::de::MapAccess<'de>,
64    {
65        let mut display_name = String::new();
66        let mut relative_period = None;
67        let mut relatives = Vec::new();
68        let mut past = None;
69        let mut future = None;
70        if let Some(size_hint) = map.size_hint() {
71            relatives.reserve(size_hint);
72        }
73        while let Some(key) = map.next_key::<String>()? {
74            // Keys must be either "displayName",  "relativePeriod", "relativeTime-type-past", "relativeTime-Type-future", "relative-type-{type}"
75            if key == "displayName" {
76                display_name = map.next_value::<String>()?;
77            } else if key == "relativePeriod" {
78                relative_period = Some(map.next_value::<String>()?);
79            } else if key == "relativeTime-type-past" {
80                if past.is_some() {
81                    return Err(A::Error::duplicate_field(
82                        r#"encountered duplicate key "relativeTime-type-past""#,
83                    ));
84                }
85                let pattern: PluralRulesPattern = map.next_value()?;
86                past = Some(pattern);
87            } else if key == "relativeTime-type-future" {
88                if future.is_some() {
89                    return Err(A::Error::duplicate_field(
90                        r#"encountered duplicate key "relativeTime-type-future""#,
91                    ));
92                }
93                let pattern: PluralRulesPattern = map.next_value()?;
94                future = Some(pattern);
95            } else if let Some(count) = key.strip_prefix("relative-type-") {
96                let count = count
97                    .parse::<i8>()
98                    .map_err(|_| A::Error::unknown_field(&key, &["not able to parse as u32"]))?;
99                relatives.push(Relative {
100                    count,
101                    pattern: map.next_value::<String>()?,
102                });
103            } else {
104                // Ignore other keys
105                let _ = map.next_value::<IgnoredAny>()?;
106            }
107        }
108        Ok(Field {
109            _display_name: display_name,
110            _relative_period: relative_period,
111            relatives,
112            past: past.unwrap_or_default(),
113            future: future.unwrap_or_default(),
114        })
115    }
116}
117
118impl<'de> Deserialize<'de> for Field {
119    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
120    where
121        D: serde::Deserializer<'de>,
122    {
123        deserializer.deserialize_map(FieldVisitor)
124    }
125}
126
127#[derive(Debug, Deserialize)]
128pub(crate) struct Fields(pub(crate) HashMap<String, Field>);
129
130#[derive(Debug, Deserialize)]
131pub(crate) struct Dates {
132    pub(crate) fields: Fields,
133}
134
135#[derive(Debug, Deserialize)]
136pub(crate) struct RelativeTimeDates {
137    pub(crate) dates: Dates,
138}
139
140pub(crate) type Resource = super::LocaleResource<RelativeTimeDates>;