use crate::fields::{self, Field, FieldLength, FieldSymbol};
use super::preferences;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Bag {
pub era: Option<Text>,
pub year: Option<Numeric>,
pub month: Option<Month>,
pub day: Option<Numeric>,
pub weekday: Option<Text>,
pub hour: Option<Numeric>,
pub minute: Option<Numeric>,
pub second: Option<Numeric>,
pub time_zone_name: Option<TimeZoneName>,
pub preferences: Option<preferences::Bag>,
}
impl Bag {
pub(crate) fn to_vec_fields(&self) -> Vec<Field> {
let mut fields = Vec::new();
if let Some(_era) = self.era {
unimplemented!("FieldSymbol::Era is needed. See issue #486.")
}
if let Some(year) = self.year {
fields.push(Field {
symbol: FieldSymbol::Year(fields::Year::Calendar),
length: match year {
Numeric::Numeric => FieldLength::One,
Numeric::TwoDigit => FieldLength::TwoDigit,
},
});
}
if let Some(month) = self.month {
fields.push(Field {
symbol: FieldSymbol::Month(fields::Month::Format),
length: match month {
Month::Numeric => FieldLength::One,
Month::TwoDigit => FieldLength::TwoDigit,
Month::Long => FieldLength::Wide,
Month::Short => FieldLength::Abbreviated,
Month::Narrow => FieldLength::Narrow,
},
});
}
if let Some(day) = self.day {
fields.push(Field {
symbol: FieldSymbol::Day(fields::Day::DayOfMonth),
length: match day {
Numeric::Numeric => FieldLength::One,
Numeric::TwoDigit => FieldLength::TwoDigit,
},
});
}
if let Some(weekday) = self.weekday {
fields.push(Field {
symbol: FieldSymbol::Weekday(fields::Weekday::Format),
length: match weekday {
Text::Long => FieldLength::Wide,
Text::Short => FieldLength::One,
Text::Narrow => FieldLength::Narrow,
},
});
}
if let Some(hour) = self.hour {
fields.push(Field {
symbol: FieldSymbol::Hour(match self.preferences {
Some(preferences::Bag {
hour_cycle: Some(hour_cycle),
}) => match hour_cycle {
preferences::HourCycle::H24 => fields::Hour::H24,
preferences::HourCycle::H23 => fields::Hour::H23,
preferences::HourCycle::H12 => fields::Hour::H12,
preferences::HourCycle::H11 => fields::Hour::H11,
},
_ => fields::Hour::H24,
}),
length: match hour {
Numeric::Numeric => FieldLength::One,
Numeric::TwoDigit => FieldLength::TwoDigit,
},
});
}
if let Some(minute) = self.minute {
fields.push(Field {
symbol: FieldSymbol::Minute,
length: match minute {
Numeric::Numeric => FieldLength::One,
Numeric::TwoDigit => FieldLength::TwoDigit,
},
});
}
if let Some(second) = self.second {
fields.push(Field {
symbol: FieldSymbol::Second(fields::Second::Second),
length: match second {
Numeric::Numeric => FieldLength::One,
Numeric::TwoDigit => FieldLength::TwoDigit,
},
});
}
debug_assert!(
fields.windows(2).all(|f| f[0] < f[1]),
"The fields are sorted and unique."
);
fields
}
}
impl Default for Bag {
fn default() -> Self {
Self {
era: None,
year: None,
month: None,
day: None,
weekday: None,
hour: None,
minute: None,
second: None,
time_zone_name: None,
preferences: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Numeric {
#[cfg_attr(feature = "serde", serde(rename = "numeric"))]
Numeric,
#[cfg_attr(feature = "serde", serde(rename = "two-digit"))]
TwoDigit,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Text {
#[cfg_attr(feature = "serde", serde(rename = "long"))]
Long,
#[cfg_attr(feature = "serde", serde(rename = "short"))]
Short,
#[cfg_attr(feature = "serde", serde(rename = "narrow"))]
Narrow,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Month {
#[cfg_attr(feature = "serde", serde(rename = "numeric"))]
Numeric,
#[cfg_attr(feature = "serde", serde(rename = "two-digit"))]
TwoDigit,
#[cfg_attr(feature = "serde", serde(rename = "long"))]
Long,
#[cfg_attr(feature = "serde", serde(rename = "short"))]
Short,
#[cfg_attr(feature = "serde", serde(rename = "narrow"))]
Narrow,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TimeZoneName {
#[cfg_attr(feature = "serde", serde(rename = "long"))]
Long,
#[cfg_attr(feature = "serde", serde(rename = "short"))]
Short,
}
#[cfg(test)]
mod test {
use super::*;
type Symbol = FieldSymbol;
type Length = FieldLength;
#[test]
fn test_component_bag_to_vec_field() {
let bag = Bag {
year: Some(Numeric::Numeric),
month: Some(Month::Long),
day: Some(Numeric::Numeric),
hour: Some(Numeric::Numeric),
minute: Some(Numeric::Numeric),
second: Some(Numeric::Numeric),
..Default::default()
};
assert_eq!(
bag.to_vec_fields(),
vec![
(Symbol::Year(fields::Year::Calendar), Length::One).into(),
(Symbol::Month(fields::Month::Format), Length::Wide).into(),
(Symbol::Day(fields::Day::DayOfMonth), Length::One).into(),
(Symbol::Hour(fields::Hour::H24), Length::One).into(),
(Symbol::Minute, Length::One).into(),
(Symbol::Second(fields::Second::Second), Length::One).into(),
]
);
}
#[test]
fn test_component_bag_to_vec_field2() {
let bag = Bag {
year: Some(Numeric::Numeric),
month: Some(Month::TwoDigit),
day: Some(Numeric::Numeric),
..Default::default()
};
assert_eq!(
bag.to_vec_fields(),
vec![
(Symbol::Year(fields::Year::Calendar), Length::One).into(),
(Symbol::Month(fields::Month::Format), Length::TwoDigit).into(),
(Symbol::Day(fields::Day::DayOfMonth), Length::One).into(),
]
);
}
}