vdsl_sync/domain/
file_type.rs1use serde::{Deserialize, Serialize};
14use std::fmt;
15
16use super::error::DomainError;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
23#[serde(rename_all = "snake_case")]
24pub enum FileType {
25 Image,
28 Asset,
30}
31
32impl FileType {
33 pub fn as_str(&self) -> &'static str {
34 match self {
35 Self::Image => "image",
36 Self::Asset => "asset",
37 }
38 }
39
40 pub fn from_extension(ext: &str) -> Self {
44 match ext.to_ascii_lowercase().as_str() {
45 "png" | "jpg" | "jpeg" | "webp" | "bmp" | "gif" | "tiff" | "tif" => Self::Image,
46 _ => Self::Asset,
47 }
48 }
49}
50
51impl fmt::Display for FileType {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 f.write_str(self.as_str())
54 }
55}
56
57impl std::str::FromStr for FileType {
58 type Err = DomainError;
59
60 fn from_str(s: &str) -> Result<Self, Self::Err> {
61 match s {
62 "image" => Ok(Self::Image),
63 "asset" => Ok(Self::Asset),
64 other => Err(DomainError::InvalidFileType(other.to_string())),
65 }
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn roundtrip() {
75 for ft in [FileType::Image, FileType::Asset] {
76 let s = ft.as_str();
77 let parsed: FileType = s.parse().expect("should parse");
78 assert_eq!(parsed, ft);
79 }
80 }
81
82 #[test]
83 fn invalid_type() {
84 let result: Result<FileType, _> = "video".parse();
85 assert!(result.is_err());
86 }
87
88 #[test]
89 fn invalid_legacy_recipe() {
90 let result: Result<FileType, _> = "recipe".parse();
91 assert!(result.is_err(), "legacy 'recipe' must not parse");
92 }
93
94 #[test]
95 fn invalid_legacy_db() {
96 let result: Result<FileType, _> = "db".parse();
97 assert!(result.is_err(), "legacy 'db' must not parse");
98 }
99
100 #[test]
101 fn display() {
102 assert_eq!(format!("{}", FileType::Image), "image");
103 assert_eq!(format!("{}", FileType::Asset), "asset");
104 }
105
106 #[test]
107 fn from_extension_images() {
108 for ext in &[
109 "png", "jpg", "jpeg", "webp", "bmp", "gif", "tiff", "tif", "PNG", "Jpg",
110 ] {
111 assert_eq!(FileType::from_extension(ext), FileType::Image);
112 }
113 }
114
115 #[test]
116 fn from_extension_assets() {
117 for ext in &["json", "txt", "db", "sqlite", "toml", "yaml", "csv"] {
118 assert_eq!(FileType::from_extension(ext), FileType::Asset);
119 }
120 }
121
122 #[test]
123 fn serde_roundtrip() {
124 let ft = FileType::Asset;
125 let json = serde_json::to_string(&ft).unwrap();
126 assert_eq!(json, "\"asset\"");
127 let back: FileType = serde_json::from_str(&json).unwrap();
128 assert_eq!(back, ft);
129 }
130}