use std::fmt;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use crate::error::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum RdmlVersion {
#[serde(rename = "1.0")]
V1_0,
#[serde(rename = "1.1")]
V1_1,
#[serde(rename = "1.2")]
V1_2,
#[serde(rename = "1.3")]
V1_3,
#[serde(rename = "1.4")]
V1_4,
}
impl RdmlVersion {
pub const LATEST_REC: Self = Self::V1_3;
pub const LATEST: Self = Self::V1_4;
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Self::V1_0 => "1.0",
Self::V1_1 => "1.1",
Self::V1_2 => "1.2",
Self::V1_3 => "1.3",
Self::V1_4 => "1.4",
}
}
#[must_use]
pub fn is_writable(self) -> bool {
self != Self::V1_0
}
}
impl fmt::Display for RdmlVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for RdmlVersion {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
match s {
"1.0" => Ok(Self::V1_0),
"1.1" => Ok(Self::V1_1),
"1.2" => Ok(Self::V1_2),
"1.3" => Ok(Self::V1_3),
"1.4" => Ok(Self::V1_4),
other => Err(Error::UnsupportedVersion(other.to_string())),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ReadNote {
pub path: String,
pub message: String,
}
impl ReadNote {
pub(crate) fn new(path: impl Into<String>, message: impl Into<String>) -> Self {
Self {
path: path.into(),
message: message.into(),
}
}
}
impl fmt::Display for ReadNote {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.path, self.message)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct WriteReport {
pub(crate) version: RdmlVersion,
pub(crate) losses: Vec<WriteLoss>,
}
impl WriteReport {
#[must_use]
pub fn version(&self) -> RdmlVersion {
self.version
}
#[must_use]
pub fn losses(&self) -> &[WriteLoss] {
&self.losses
}
pub(crate) fn new(version: RdmlVersion) -> Self {
Self {
version,
losses: Vec::new(),
}
}
#[must_use]
pub fn is_lossless(&self) -> bool {
self.losses.is_empty()
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct WriteLoss {
pub path: String,
pub dropped: String,
pub required_version: RdmlVersion,
}
impl fmt::Display for WriteLoss {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}: dropped {} (requires RDML ≥ {})",
self.path, self.dropped, self.required_version
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn version_strings_round_trip() {
for v in [
RdmlVersion::V1_0,
RdmlVersion::V1_1,
RdmlVersion::V1_2,
RdmlVersion::V1_3,
RdmlVersion::V1_4,
] {
assert_eq!(v.as_str().parse::<RdmlVersion>().unwrap(), v);
}
assert!("2.0".parse::<RdmlVersion>().is_err());
assert!("1".parse::<RdmlVersion>().is_err());
}
#[test]
fn version_ordering() {
assert!(RdmlVersion::V1_0 < RdmlVersion::V1_1);
assert!(RdmlVersion::V1_3 < RdmlVersion::V1_4);
assert!(!RdmlVersion::V1_0.is_writable());
assert!(RdmlVersion::V1_1.is_writable());
}
}