use crate::{
EMLError, EMLErrorKind, NS_KR,
io::{EMLElement, EMLElementReader, EMLElementWriter, QualifiedName},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum EMLVersion {
V1_2_2,
V1_3,
#[default]
V1_3_1,
}
impl EMLVersion {
pub const EML_NAME: QualifiedName<'_, '_> = QualifiedName::from_static("Schema", Some(NS_KR));
pub fn to_str(&self) -> Option<&'static str> {
match self {
EMLVersion::V1_2_2 => None,
EMLVersion::V1_3 => Some("1.3"),
EMLVersion::V1_3_1 => Some("1.3.1"),
}
}
pub fn is_v1_3_1(&self) -> bool {
matches!(self, EMLVersion::V1_3_1)
}
pub fn is_v1_3(&self) -> bool {
matches!(self, EMLVersion::V1_3)
}
pub fn is_v1_2_2(&self) -> bool {
matches!(self, EMLVersion::V1_2_2)
}
}
impl EMLElement for EMLVersion {
const EML_NAME: QualifiedName<'_, '_> = QualifiedName::from_static("Schema", Some(NS_KR));
fn read_eml(elem: &mut EMLElementReader<'_, '_>) -> Result<Self, EMLError> {
let version = elem.attribute_value_req("Version")?;
Ok(version.parse()?)
}
fn write_eml(&self, writer: EMLElementWriter) -> Result<(), EMLError> {
if self.is_v1_2_2() {
return Ok(());
}
writer
.attr(
"Version",
self.to_str()
.expect("Version is not 1.2.2, so should have version string"),
)?
.empty()
}
}
impl std::fmt::Display for EMLVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_str().unwrap_or("1.2.2"))
}
}
impl std::str::FromStr for EMLVersion {
type Err = UnsupportedEMLVersion;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"1.3.1" => Ok(EMLVersion::V1_3_1),
"1.3" => Ok(EMLVersion::V1_3),
_ => Err(UnsupportedEMLVersion(s.to_owned())),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("Unsupported EML_NL version: {0}")]
pub struct UnsupportedEMLVersion(String);
impl From<UnsupportedEMLVersion> for EMLError {
fn from(value: UnsupportedEMLVersion) -> Self {
EMLErrorKind::UnsupportedEMLVersion(value.0).without_span()
}
}
pub struct EMLVersionRange {
since: Option<EMLVersion>,
until: Option<EMLVersion>,
}
impl EMLVersionRange {
pub const ALL: Self = Self {
since: None,
until: None,
};
pub const fn since(version: EMLVersion) -> Self {
Self {
since: Some(version),
until: None,
}
}
pub const fn until(version: EMLVersion) -> Self {
Self {
since: None,
until: Some(version),
}
}
pub const fn between(version: EMLVersion, until: EMLVersion) -> Self {
Self {
since: Some(version),
until: Some(until),
}
}
pub fn contains(&self, version: EMLVersion) -> bool {
match (self.since, self.until) {
(None, None) => true,
(Some(since), Some(until)) => version >= since && version < until,
(Some(since), None) => version >= since,
(None, Some(until)) => version < until,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_eml_version_to_str() {
assert_eq!(EMLVersion::V1_3_1.to_str(), Some("1.3.1"));
assert_eq!(EMLVersion::V1_3.to_str(), Some("1.3"));
assert_eq!(EMLVersion::V1_2_2.to_str(), None);
}
#[test]
fn test_eml_version_from_str() {
assert_eq!("1.3.1".parse::<EMLVersion>(), Ok(EMLVersion::V1_3_1));
assert_eq!("1.3".parse::<EMLVersion>(), Ok(EMLVersion::V1_3));
assert!("1.2".parse::<EMLVersion>().is_err());
}
#[test]
fn test_comparison_of_eml_versions() {
assert!(EMLVersion::V1_3 > EMLVersion::V1_2_2);
assert!(EMLVersion::V1_3 >= EMLVersion::V1_3);
assert!(EMLVersion::V1_2_2 <= EMLVersion::V1_3);
assert!(EMLVersion::V1_2_2 < EMLVersion::V1_3);
assert!(EMLVersion::V1_3 != EMLVersion::V1_2_2);
assert!(EMLVersion::V1_3 == EMLVersion::V1_3);
}
}