xsd_types/lexical/
g_year.rs1use static_regular_grammar::RegularGrammar;
2
3use crate::{lexical::parse_timezone, utils::byte_index_of};
4
5use super::{Lexical, LexicalFormOf};
6
7#[derive(RegularGrammar, PartialEq, Eq, PartialOrd, Ord, Hash)]
27#[grammar(sized(GYearBuf, derive(PartialEq, Eq, PartialOrd, Ord, Hash)))]
28pub struct GYear(str);
29
30impl GYear {
31 pub fn parts(&self) -> Parts {
32 let year_end =
33 byte_index_of(self.0.as_bytes(), 4, [b'+', b'-', b'Z']).unwrap_or(self.0.len());
34
35 Parts {
36 year: &self.0[..year_end],
37 timezone: if self.0.len() > year_end {
38 Some(&self.0[year_end..])
39 } else {
40 None
41 },
42 }
43 }
44}
45
46impl Lexical for GYear {
47 type Error = InvalidGYear<String>;
48
49 fn parse(value: &str) -> Result<&Self, Self::Error> {
50 Self::new(value).map_err(|_| InvalidGYear(value.to_owned()))
51 }
52}
53
54impl LexicalFormOf<crate::GYear> for GYear {
55 type ValueError = std::convert::Infallible;
56
57 fn try_as_value(&self) -> Result<crate::GYear, Self::ValueError> {
58 Ok(self.parts().to_g_year_month())
59 }
60}
61
62#[derive(Debug, PartialEq, Eq)]
63pub struct Parts<'a> {
64 pub year: &'a str,
65 pub timezone: Option<&'a str>,
66}
67
68impl<'a> Parts<'a> {
69 pub fn new(year: &'a str, timezone: Option<&'a str>) -> Self {
70 Self { year, timezone }
71 }
72
73 fn to_g_year_month(&self) -> crate::GYear {
74 crate::GYear::new(
75 self.year.parse().unwrap(),
76 self.timezone.map(parse_timezone),
77 )
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn parsing() {
87 let vectors = [
88 ("2014", Parts::new("2014", None)),
89 ("-0001Z", Parts::new("-0001", Some("Z"))),
90 ("10000+05:00", Parts::new("10000", Some("+05:00"))),
91 ];
92
93 for (input, parts) in vectors {
94 let lexical_repr = GYear::new(input).unwrap();
95 assert_eq!(lexical_repr.parts(), parts);
96
97 let value = lexical_repr.try_as_value().unwrap();
98 assert_eq!(value.to_string().as_str(), input)
99 }
100 }
101}