1use crate::{
2 EMLError, EMLErrorKind, NS_KR,
3 io::{EMLElement, EMLElementReader, EMLElementWriter, QualifiedName},
4};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
16pub enum EMLVersion {
17 V1_2_2,
19
20 V1_3,
22
23 #[default]
25 V1_3_1,
26}
27
28impl EMLVersion {
29 pub const EML_NAME: QualifiedName<'_, '_> = QualifiedName::from_static("Schema", Some(NS_KR));
31
32 pub fn to_str(&self) -> Option<&'static str> {
36 match self {
37 EMLVersion::V1_2_2 => None,
38 EMLVersion::V1_3 => Some("1.3"),
39 EMLVersion::V1_3_1 => Some("1.3.1"),
40 }
41 }
42
43 pub fn is_v1_3_1(&self) -> bool {
45 matches!(self, EMLVersion::V1_3_1)
46 }
47
48 pub fn is_v1_3(&self) -> bool {
50 matches!(self, EMLVersion::V1_3)
51 }
52
53 pub fn is_v1_2_2(&self) -> bool {
55 matches!(self, EMLVersion::V1_2_2)
56 }
57}
58
59impl EMLElement for EMLVersion {
60 const EML_NAME: QualifiedName<'_, '_> = QualifiedName::from_static("Schema", Some(NS_KR));
61
62 fn read_eml(elem: &mut EMLElementReader<'_, '_>) -> Result<Self, EMLError> {
63 let version = elem.attribute_value_req("Version")?;
66 Ok(version.parse()?)
67 }
68
69 fn write_eml(&self, writer: EMLElementWriter) -> Result<(), EMLError> {
70 if self.is_v1_2_2() {
71 return Ok(());
73 }
74 writer
75 .attr(
76 "Version",
77 self.to_str()
78 .expect("Version is not 1.2.2, so should have version string"),
79 )?
80 .empty()
81 }
82}
83
84impl std::fmt::Display for EMLVersion {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 write!(f, "{}", self.to_str().unwrap_or("1.2.2"))
87 }
88}
89
90impl std::str::FromStr for EMLVersion {
91 type Err = UnsupportedEMLVersion;
92
93 fn from_str(s: &str) -> Result<Self, Self::Err> {
94 match s {
95 "1.3.1" => Ok(EMLVersion::V1_3_1),
96 "1.3" => Ok(EMLVersion::V1_3),
97 _ => Err(UnsupportedEMLVersion(s.to_owned())),
98 }
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
104#[error("Unsupported EML_NL version: {0}")]
105pub struct UnsupportedEMLVersion(String);
106
107impl From<UnsupportedEMLVersion> for EMLError {
108 fn from(value: UnsupportedEMLVersion) -> Self {
109 EMLErrorKind::UnsupportedEMLVersion(value.0).without_span()
110 }
111}
112
113pub struct EMLVersionRange {
115 since: Option<EMLVersion>,
117 until: Option<EMLVersion>,
119}
120
121impl EMLVersionRange {
122 pub const ALL: Self = Self {
124 since: None,
125 until: None,
126 };
127
128 pub const fn since(version: EMLVersion) -> Self {
130 Self {
131 since: Some(version),
132 until: None,
133 }
134 }
135
136 pub const fn until(version: EMLVersion) -> Self {
138 Self {
139 since: None,
140 until: Some(version),
141 }
142 }
143
144 pub const fn between(version: EMLVersion, until: EMLVersion) -> Self {
147 Self {
148 since: Some(version),
149 until: Some(until),
150 }
151 }
152
153 pub fn contains(&self, version: EMLVersion) -> bool {
155 match (self.since, self.until) {
156 (None, None) => true,
157 (Some(since), Some(until)) => version >= since && version < until,
158 (Some(since), None) => version >= since,
159 (None, Some(until)) => version < until,
160 }
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn test_eml_version_to_str() {
170 assert_eq!(EMLVersion::V1_3_1.to_str(), Some("1.3.1"));
171 assert_eq!(EMLVersion::V1_3.to_str(), Some("1.3"));
172 assert_eq!(EMLVersion::V1_2_2.to_str(), None);
173 }
174
175 #[test]
176 fn test_eml_version_from_str() {
177 assert_eq!("1.3.1".parse::<EMLVersion>(), Ok(EMLVersion::V1_3_1));
178 assert_eq!("1.3".parse::<EMLVersion>(), Ok(EMLVersion::V1_3));
179 assert!("1.2".parse::<EMLVersion>().is_err());
180 }
181
182 #[test]
183 fn test_comparison_of_eml_versions() {
184 assert!(EMLVersion::V1_3 > EMLVersion::V1_2_2);
185 assert!(EMLVersion::V1_3 >= EMLVersion::V1_3);
186 assert!(EMLVersion::V1_2_2 <= EMLVersion::V1_3);
187 assert!(EMLVersion::V1_2_2 < EMLVersion::V1_3);
188 assert!(EMLVersion::V1_3 != EMLVersion::V1_2_2);
189 assert!(EMLVersion::V1_3 == EMLVersion::V1_3);
190 }
191}