use crate::error::{FileError, Result};
use serde::de::DeserializeOwned;
use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum Format {
#[default]
Toml,
Json,
Yaml,
}
impl Format {
#[must_use]
pub const fn extension(self) -> &'static str {
match self {
Self::Toml => "toml",
Self::Json => "json",
Self::Yaml => "yaml",
}
}
#[must_use]
pub const fn all() -> &'static [Self] {
&[Self::Toml, Self::Json, Self::Yaml]
}
pub fn from_path(path: &Path) -> Option<Self> {
path.extension()
.and_then(|ext| ext.to_str())
.and_then(Self::from_extension)
}
#[must_use]
pub fn from_extension(ext: &str) -> Option<Self> {
match ext.to_lowercase().as_str() {
"toml" => Some(Self::Toml),
"json" => Some(Self::Json),
"yaml" | "yml" => Some(Self::Yaml),
_ => None,
}
}
pub fn parse<T: DeserializeOwned>(self, content: &str, path: &Path) -> Result<T> {
match self {
#[cfg(feature = "toml")]
Self::Toml => toml::from_str(content).map_err(|e| FileError::Parse {
path: path.to_path_buf(),
format: "TOML",
source: Box::new(e),
}),
#[cfg(not(feature = "toml"))]
Self::Toml => Err(FileError::UnsupportedFormat {
format: "toml".to_string(),
}),
#[cfg(feature = "json")]
Self::Json => serde_json::from_str(content).map_err(|e| FileError::Parse {
path: path.to_path_buf(),
format: "JSON",
source: Box::new(e),
}),
#[cfg(not(feature = "json"))]
Self::Json => Err(FileError::UnsupportedFormat {
format: "json".to_string(),
}),
#[cfg(feature = "yaml")]
Self::Yaml => serde_yaml::from_str(content).map_err(|e| FileError::Parse {
path: path.to_path_buf(),
format: "YAML",
source: Box::new(e),
}),
#[cfg(not(feature = "yaml"))]
Self::Yaml => Err(FileError::UnsupportedFormat {
format: "yaml".to_string(),
}),
}
}
}
impl std::fmt::Display for Format {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.extension())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_extension() {
assert_eq!(Format::Toml.extension(), "toml");
assert_eq!(Format::Json.extension(), "json");
assert_eq!(Format::Yaml.extension(), "yaml");
}
#[test]
fn test_format_from_extension() {
assert_eq!(Format::from_extension("toml"), Some(Format::Toml));
assert_eq!(Format::from_extension("json"), Some(Format::Json));
assert_eq!(Format::from_extension("yaml"), Some(Format::Yaml));
assert_eq!(Format::from_extension("yml"), Some(Format::Yaml));
assert_eq!(Format::from_extension("unknown"), None);
}
#[test]
fn test_format_from_path() {
assert_eq!(
Format::from_path(Path::new("config.toml")),
Some(Format::Toml)
);
assert_eq!(
Format::from_path(Path::new("/path/to/config.json")),
Some(Format::Json)
);
assert_eq!(Format::from_path(Path::new("config")), None);
}
}