am_api/utils/
year_or_date.rs

1//! Year or date
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4use std::fmt::{Display, Formatter};
5use std::str::FromStr;
6use time::format_description::FormatItem;
7use time::macros::format_description;
8use time::Date;
9
10pub(crate) const FORMAT: &[FormatItem] = format_description!("[year]-[month]-[day]");
11
12/// Year or date
13#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub enum YearOrDate {
15    /// Year
16    Year(i16),
17    /// Date
18    Date(Date),
19}
20
21impl Display for YearOrDate {
22    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
23        match self {
24            YearOrDate::Year(year) => write!(f, "{:4}", year),
25            YearOrDate::Date(e) => Display::fmt(e, f),
26        }
27    }
28}
29
30impl Serialize for YearOrDate {
31    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
32    where
33        S: Serializer,
34    {
35        match self {
36            YearOrDate::Year(year) => serializer.serialize_str(&year.to_string()),
37            YearOrDate::Date(date) => Serialize::serialize(date, serializer),
38        }
39    }
40}
41
42impl<'de> Deserialize<'de> for YearOrDate {
43    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
44    where
45        D: Deserializer<'de>,
46    {
47        let s: String = Deserialize::deserialize(deserializer)?;
48
49        Ok(match s.contains('-') {
50            false => YearOrDate::Year(i16::from_str(&s).map_err(serde::de::Error::custom)?),
51            true => YearOrDate::Date(Date::parse(&s, &FORMAT).map_err(serde::de::Error::custom)?),
52        })
53    }
54}