Skip to content

Commit

Permalink
Consolidate date types
Browse files Browse the repository at this point in the history
  • Loading branch information
reknih committed Sep 22, 2023
1 parent c345ba7 commit 1f0c59f
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 43 deletions.
98 changes: 55 additions & 43 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,7 @@ impl From<Term> for TextTarget {
pub struct Date {
/// The date to format.
#[serde(rename = "@variable")]
pub variable: Variable,
pub variable: DateVariable,
/// How the localized date should be formatted.
#[serde(rename = "@form")]
pub form: Option<DateForm>,
Expand Down Expand Up @@ -998,6 +998,13 @@ pub struct Date {
to_formatting!(Date);
to_affixes!(Date);

impl Date {
/// Whether this is a localized or a standalone date.
pub const fn is_localized(&self) -> bool {
self.form.is_some()
}
}

/// Localized date formats.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Deserialize)]
#[serde(rename_all = "kebab-case")]
Expand All @@ -1019,6 +1026,18 @@ pub enum DateParts {
YearMonthDay,
}

impl DateParts {
/// Check if the date shall contain a month.
pub const fn has_month(self) -> bool {
matches!(self, Self::YearMonth | Self::YearMonthDay)
}

/// Check if the date shall contain a day.
pub const fn has_day(self) -> bool {
matches!(self, Self::YearMonthDay)
}
}

/// Override the default date parts.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)]
pub struct DatePart {
Expand Down Expand Up @@ -1055,8 +1074,8 @@ impl DatePart {
pub const DEFAULT_DELIMITER: &str = "–";

/// Retrieve the form.
pub fn form(&self) -> Option<DateStrongAnyForm> {
DateStrongAnyForm::for_name(self.name, self.form?)
pub fn form(&self) -> DateStrongAnyForm {
DateStrongAnyForm::for_name(self.name, self.form)
}
}

Expand Down Expand Up @@ -1098,52 +1117,59 @@ pub enum DateStrongAnyForm {
impl DateStrongAnyForm {
/// Get a strongly typed date form for a name. Must return `Some` for valid
/// CSL files.
pub fn for_name(name: DatePartName, form: DateAnyForm) -> Option<Self> {
Some(match name {
DatePartName::Day => Self::Day(form.form_for_day()?),
DatePartName::Month => Self::Month(form.form_for_month()?),
DatePartName::Year => Self::Year(form.form_for_year()?),
})
pub fn for_name(name: DatePartName, form: Option<DateAnyForm>) -> Self {
match name {
DatePartName::Day => Self::Day(
form.map(DateAnyForm::form_for_day)
.unwrap_or_else(DateDayForm::default),
),
DatePartName::Month => Self::Month(
form.map(DateAnyForm::form_for_month)
.unwrap_or_else(DateMonthForm::default),
),
DatePartName::Year => Self::Year(
form.map(DateAnyForm::form_for_year)
.unwrap_or_else(LongShortForm::default),
),
}
}
}

impl DateAnyForm {
/// Retrieve the form for a day.
pub fn form_for_day(&self) -> Option<DateDayForm> {
pub fn form_for_day(self) -> DateDayForm {
match self {
Self::Numeric => Some(DateDayForm::Numeric),
Self::NumericLeadingZeros => Some(DateDayForm::NumericLeadingZeros),
Self::Ordinal => Some(DateDayForm::Ordinal),
_ => None,
Self::NumericLeadingZeros => DateDayForm::NumericLeadingZeros,
Self::Ordinal => DateDayForm::Ordinal,
_ => DateDayForm::default(),
}
}

/// Retrieve the form for a month.
pub fn form_for_month(&self) -> Option<DateMonthForm> {
pub fn form_for_month(self) -> DateMonthForm {
match self {
Self::Long => Some(DateMonthForm::Long),
Self::Short => Some(DateMonthForm::Short),
Self::Numeric => Some(DateMonthForm::Numeric),
Self::NumericLeadingZeros => Some(DateMonthForm::NumericLeadingZeros),
_ => None,
Self::Short => DateMonthForm::Short,
Self::Numeric => DateMonthForm::Numeric,
Self::NumericLeadingZeros => DateMonthForm::NumericLeadingZeros,
_ => DateMonthForm::default(),
}
}

/// Retrieve the form for a year.
pub fn form_for_year(&self) -> Option<LongShortForm> {
pub fn form_for_year(self) -> LongShortForm {
match self {
Self::Long => Some(LongShortForm::Long),
Self::Short => Some(LongShortForm::Short),
_ => None,
Self::Short => LongShortForm::Short,
_ => LongShortForm::default(),
}
}
}

/// How a day is formatted.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Deserialize)]
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum DateDayForm {
/// “1”
#[default]
Numeric,
/// “01”
NumericLeadingZeros,
Expand All @@ -1152,10 +1178,11 @@ pub enum DateDayForm {
}

/// How a month is formatted.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Deserialize)]
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum DateMonthForm {
/// “January”
#[default]
Long,
/// “Jan.”
Short,
Expand Down Expand Up @@ -1745,7 +1772,7 @@ pub struct LocaleFile {
pub terms: Option<Terms>,
/// How to format dates in the locale file.
#[serde(default)]
pub date: Vec<DateLocale>,
pub date: Vec<Date>,
/// Style options for the locale.
pub style_options: Option<LocaleOptions>,
}
Expand All @@ -1764,7 +1791,7 @@ pub struct Locale {
pub terms: Option<Terms>,
/// How to format dates in the locale file.
#[serde(default)]
pub date: Vec<DateLocale>,
pub date: Vec<Date>,
/// Style options for the locale.
pub style_options: Option<LocaleOptions>,
}
Expand Down Expand Up @@ -2056,21 +2083,6 @@ pub enum GrammarGender {
Masculine,
}

/// Formats a date in a locale.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)]
pub struct DateLocale {
/// How the localized date should be formatted.
#[serde(rename = "@form")]
pub form: Option<DateForm>,
/// Which parts of the localized date should be included.
#[serde(rename = "@date-parts")]
pub parts: Option<DateParts>,
/// Override the default date parts. Also specifies the order of the parts
/// if `form` is `None`.
#[serde(rename = "$value")]
pub children: Vec<DatePart>,
}

/// Options for the locale.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Deserialize)]
pub struct LocaleOptions {
Expand Down
30 changes: 30 additions & 0 deletions src/taxonomy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,36 @@ impl OtherTerm {
pub const fn is_ordinal(self) -> bool {
matches!(self, Self::Ordinal | Self::OrdinalN(_) | Self::LongOrdinal(_))
}

/// Get the month for a number between 0 and 11.
pub const fn month(i: u8) -> Option<Self> {
match i {
0 => Some(Self::Month01),
1 => Some(Self::Month02),
2 => Some(Self::Month03),
3 => Some(Self::Month04),
4 => Some(Self::Month05),
5 => Some(Self::Month06),
6 => Some(Self::Month07),
7 => Some(Self::Month08),
8 => Some(Self::Month09),
9 => Some(Self::Month10),
10 => Some(Self::Month11),
11 => Some(Self::Month12),
_ => None,
}
}

/// Get the season for a number between 0 and 3.
pub const fn season(i: u8) -> Option<Self> {
match i {
0 => Some(Self::Season01),
1 => Some(Self::Season02),
2 => Some(Self::Season03),
3 => Some(Self::Season04),
_ => None,
}
}
}

impl FromStr for OtherTerm {
Expand Down

0 comments on commit 1f0c59f

Please sign in to comment.