xsd_types/lexical/
g_day.rs

1use static_regular_grammar::RegularGrammar;
2
3use crate::lexical::parse_timezone;
4
5use super::{Lexical, LexicalFormOf};
6
7/// GDay.
8///
9/// ```abnf
10/// g-day = "---" day [timezone]
11///
12/// day = "0" NZDIGIT
13///     / ("1" / "2") DIGIT
14///     / "3" ("0" / "1")
15///
16/// minute = ("0" / "1" / "2" / "3" / "4" / "5") DIGIT
17///
18/// timezone = ("+" / "-") ((("0" DIGIT / "1" ("0" / "1" / "2" / "3")) ":" minute) / "14:00")
19///          / %s"Z"
20///
21/// NZDIGIT = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
22/// ```
23#[derive(RegularGrammar, PartialEq, Eq, PartialOrd, Ord, Hash)]
24#[grammar(sized(GDayBuf, derive(PartialEq, Eq, PartialOrd, Ord, Hash)))]
25pub struct GDay(str);
26
27impl GDay {
28	pub fn parts(&self) -> Parts {
29		Parts {
30			day: &self.0[3..5],
31			timezone: if self.0.len() > 5 {
32				Some(&self.0[5..])
33			} else {
34				None
35			},
36		}
37	}
38}
39
40impl Lexical for GDay {
41	type Error = InvalidGDay<String>;
42
43	fn parse(value: &str) -> Result<&Self, Self::Error> {
44		Self::new(value).map_err(|_| InvalidGDay(value.to_owned()))
45	}
46}
47
48impl LexicalFormOf<crate::GDay> for GDay {
49	type ValueError = std::convert::Infallible;
50
51	fn try_as_value(&self) -> Result<crate::GDay, Self::ValueError> {
52		Ok(self.parts().to_g_day())
53	}
54}
55
56#[derive(Debug, PartialEq, Eq)]
57pub struct Parts<'a> {
58	pub day: &'a str,
59	pub timezone: Option<&'a str>,
60}
61
62impl<'a> Parts<'a> {
63	pub fn new(day: &'a str, timezone: Option<&'a str>) -> Self {
64		Self { day, timezone }
65	}
66
67	fn to_g_day(&self) -> crate::GDay {
68		crate::GDay::new(self.day.parse().unwrap(), self.timezone.map(parse_timezone)).unwrap()
69	}
70}
71
72#[cfg(test)]
73mod tests {
74	use super::*;
75
76	#[test]
77	fn parsing() {
78		let vectors = [
79			("---12", Parts::new("12", None)),
80			("---31Z", Parts::new("31", Some("Z"))),
81			("---20+05:00", Parts::new("20", Some("+05:00"))),
82		];
83
84		for (input, parts) in vectors {
85			let lexical_repr = GDay::new(input).unwrap();
86			assert_eq!(lexical_repr.parts(), parts);
87
88			let value = lexical_repr.try_as_value().unwrap();
89			assert_eq!(value.to_string().as_str(), input)
90		}
91	}
92}