use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ExportFormat {
#[default]
Json,
Yaml,
#[cfg(feature = "export-toml")]
Toml,
#[cfg(feature = "export-markdown")]
Markdown,
}
impl ExportFormat {
#[must_use]
pub fn extension(&self) -> &'static str {
match self {
Self::Json => "json",
Self::Yaml => "yaml",
#[cfg(feature = "export-toml")]
Self::Toml => "toml",
#[cfg(feature = "export-markdown")]
Self::Markdown => "md",
}
}
#[must_use]
pub fn mime_type(&self) -> &'static str {
match self {
Self::Json => "application/json",
Self::Yaml => "application/x-yaml",
#[cfg(feature = "export-toml")]
Self::Toml => "application/toml",
#[cfg(feature = "export-markdown")]
Self::Markdown => "text/markdown",
}
}
#[must_use]
pub fn supports_pretty(&self) -> bool {
match self {
Self::Json => true,
Self::Yaml => false, #[cfg(feature = "export-toml")]
Self::Toml => true,
#[cfg(feature = "export-markdown")]
Self::Markdown => false, }
}
#[must_use]
pub fn all() -> Vec<Self> {
vec![
Self::Json,
Self::Yaml,
#[cfg(feature = "export-toml")]
Self::Toml,
#[cfg(feature = "export-markdown")]
Self::Markdown,
]
}
}
impl fmt::Display for ExportFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Json => write!(f, "json"),
Self::Yaml => write!(f, "yaml"),
#[cfg(feature = "export-toml")]
Self::Toml => write!(f, "toml"),
#[cfg(feature = "export-markdown")]
Self::Markdown => write!(f, "markdown"),
}
}
}
impl std::str::FromStr for ExportFormat {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"json" => Ok(Self::Json),
"yaml" | "yml" => Ok(Self::Yaml),
#[cfg(feature = "export-toml")]
"toml" => Ok(Self::Toml),
#[cfg(feature = "export-markdown")]
"markdown" | "md" => Ok(Self::Markdown),
_ => Err(format!(
"Unknown format: {s}. Available: {}",
Self::all()
.iter()
.map(std::string::ToString::to_string)
.collect::<Vec<_>>()
.join(", ")
)),
}
}
}
pub trait Exporter {
fn export(
&self,
config: &crate::ast::Config,
writer: &mut dyn std::io::Write,
) -> crate::Result<()>;
fn format_name(&self) -> &str;
fn extension(&self) -> &str;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_display() {
assert_eq!(ExportFormat::Json.to_string(), "json");
assert_eq!(ExportFormat::Yaml.to_string(), "yaml");
}
#[test]
fn test_format_from_str() {
assert_eq!("json".parse::<ExportFormat>().unwrap(), ExportFormat::Json);
assert_eq!("yaml".parse::<ExportFormat>().unwrap(), ExportFormat::Yaml);
assert_eq!("yml".parse::<ExportFormat>().unwrap(), ExportFormat::Yaml);
}
#[test]
fn test_format_from_str_case_insensitive() {
assert_eq!("JSON".parse::<ExportFormat>().unwrap(), ExportFormat::Json);
assert_eq!("YaML".parse::<ExportFormat>().unwrap(), ExportFormat::Yaml);
}
#[test]
fn test_format_from_str_invalid() {
let result = "invalid".parse::<ExportFormat>();
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.contains("Unknown format"));
assert!(err.contains("Available"));
}
#[test]
fn test_format_extension() {
assert_eq!(ExportFormat::Json.extension(), "json");
assert_eq!(ExportFormat::Yaml.extension(), "yaml");
}
#[test]
fn test_format_mime_type() {
assert_eq!(ExportFormat::Json.mime_type(), "application/json");
assert_eq!(ExportFormat::Yaml.mime_type(), "application/x-yaml");
}
#[test]
fn test_format_supports_pretty() {
assert!(ExportFormat::Json.supports_pretty());
assert!(!ExportFormat::Yaml.supports_pretty());
}
#[test]
fn test_format_all() {
let formats = ExportFormat::all();
assert!(formats.contains(&ExportFormat::Json));
assert!(formats.contains(&ExportFormat::Yaml));
assert!(!formats.is_empty());
}
#[test]
fn test_format_default() {
assert_eq!(ExportFormat::default(), ExportFormat::Json);
}
#[cfg(feature = "export-toml")]
#[test]
fn test_toml_format() {
assert_eq!(ExportFormat::Toml.extension(), "toml");
assert_eq!(ExportFormat::Toml.mime_type(), "application/toml");
assert!(ExportFormat::Toml.supports_pretty());
}
#[cfg(feature = "export-markdown")]
#[test]
fn test_markdown_format() {
assert_eq!(ExportFormat::Markdown.extension(), "md");
assert_eq!(ExportFormat::Markdown.mime_type(), "text/markdown");
assert!(!ExportFormat::Markdown.supports_pretty());
}
}