use serde::{Deserialize, Serialize};
use std::fmt;
use super::error::DomainError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum FileType {
Image,
Asset,
}
impl FileType {
pub fn as_str(&self) -> &'static str {
match self {
Self::Image => "image",
Self::Asset => "asset",
}
}
pub fn from_extension(ext: &str) -> Self {
match ext.to_ascii_lowercase().as_str() {
"png" | "jpg" | "jpeg" | "webp" | "bmp" | "gif" | "tiff" | "tif" => Self::Image,
_ => Self::Asset,
}
}
}
impl fmt::Display for FileType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl std::str::FromStr for FileType {
type Err = DomainError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"image" => Ok(Self::Image),
"asset" => Ok(Self::Asset),
other => Err(DomainError::InvalidFileType(other.to_string())),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn roundtrip() {
for ft in [FileType::Image, FileType::Asset] {
let s = ft.as_str();
let parsed: FileType = s.parse().expect("should parse");
assert_eq!(parsed, ft);
}
}
#[test]
fn invalid_type() {
let result: Result<FileType, _> = "video".parse();
assert!(result.is_err());
}
#[test]
fn invalid_legacy_recipe() {
let result: Result<FileType, _> = "recipe".parse();
assert!(result.is_err(), "legacy 'recipe' must not parse");
}
#[test]
fn invalid_legacy_db() {
let result: Result<FileType, _> = "db".parse();
assert!(result.is_err(), "legacy 'db' must not parse");
}
#[test]
fn display() {
assert_eq!(format!("{}", FileType::Image), "image");
assert_eq!(format!("{}", FileType::Asset), "asset");
}
#[test]
fn from_extension_images() {
for ext in &[
"png", "jpg", "jpeg", "webp", "bmp", "gif", "tiff", "tif", "PNG", "Jpg",
] {
assert_eq!(FileType::from_extension(ext), FileType::Image);
}
}
#[test]
fn from_extension_assets() {
for ext in &["json", "txt", "db", "sqlite", "toml", "yaml", "csv"] {
assert_eq!(FileType::from_extension(ext), FileType::Asset);
}
}
#[test]
fn serde_roundtrip() {
let ft = FileType::Asset;
let json = serde_json::to_string(&ft).unwrap();
assert_eq!(json, "\"asset\"");
let back: FileType = serde_json::from_str(&json).unwrap();
assert_eq!(back, ft);
}
}