use std::fmt;
use std::str::FromStr;
use crate::error::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Format {
Xml,
Binary,
OpenStep,
GnuStep,
}
impl Format {
const ALL: [Self; 4] = [Self::Xml, Self::Binary, Self::OpenStep, Self::GnuStep];
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Self::Xml => "XML",
Self::Binary => "Binary",
Self::OpenStep => "OpenStep",
Self::GnuStep => "GNUStep",
}
}
}
impl fmt::Display for Format {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.name())
}
}
impl FromStr for Format {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::ALL
.into_iter()
.find(|format| s.eq_ignore_ascii_case(format.name()))
.ok_or_else(|| Error::Message(format!("unknown format name: {s}")))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn name_matches_canonical_spellings() {
assert_eq!(Format::Xml.name(), "XML");
assert_eq!(Format::Binary.name(), "Binary");
assert_eq!(Format::OpenStep.name(), "OpenStep");
assert_eq!(Format::GnuStep.name(), "GNUStep");
}
#[test]
fn from_str_round_trips_display_case_insensitively() {
for format in Format::ALL {
assert_eq!(format.to_string().parse::<Format>().ok(), Some(format));
assert_eq!(
format.name().to_lowercase().parse::<Format>().ok(),
Some(format)
);
assert_eq!(
format.name().to_uppercase().parse::<Format>().ok(),
Some(format)
);
}
}
#[test]
fn from_str_rejects_unknown_names() {
for bad in ["", "plist", "XM L", " xml", "xml ", "GNU Step"] {
let err = bad.parse::<Format>();
assert!(
matches!(err, Err(Error::Message(ref m)) if m.starts_with("unknown format name"))
);
}
}
}