airsprotocols_mcpserver_filesystem/binary/
format.rs1use std::path::Path;
5
6#[derive(Debug)]
14pub struct FormatDetector;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum FileFormat {
19 Jpeg,
21 Png,
22 Gif,
23 WebP,
24 Tiff,
25 Bmp,
26
27 Pdf,
29
30 Text,
32
33 Unknown,
35}
36
37impl FormatDetector {
38 pub fn new() -> Self {
40 Self
41 }
42
43 pub fn detect_from_bytes(&self, bytes: &[u8]) -> FileFormat {
45 if let Some(kind) = infer::get(bytes) {
46 match kind.mime_type() {
47 "image/jpeg" => FileFormat::Jpeg,
48 "image/png" => FileFormat::Png,
49 "image/gif" => FileFormat::Gif,
50 "image/webp" => FileFormat::WebP,
51 "image/tiff" => FileFormat::Tiff,
52 "image/bmp" => FileFormat::Bmp,
53 "application/pdf" => FileFormat::Pdf,
54 _ => FileFormat::Unknown,
55 }
56 } else {
57 if bytes
59 .iter()
60 .all(|&b| b.is_ascii() || b.is_ascii_whitespace())
61 {
62 FileFormat::Text
63 } else {
64 FileFormat::Unknown
65 }
66 }
67 }
68
69 pub fn detect_from_extension<P: AsRef<Path>>(&self, path: P) -> FileFormat {
71 if let Some(extension) = path.as_ref().extension() {
72 match extension.to_string_lossy().to_lowercase().as_str() {
73 "jpg" | "jpeg" => FileFormat::Jpeg,
74 "png" => FileFormat::Png,
75 "gif" => FileFormat::Gif,
76 "webp" => FileFormat::WebP,
77 "tiff" | "tif" => FileFormat::Tiff,
78 "bmp" => FileFormat::Bmp,
79 "pdf" => FileFormat::Pdf,
80 "txt" | "md" | "rs" | "py" | "js" | "html" | "css" | "json" | "toml" | "yml"
81 | "yaml" => FileFormat::Text,
82 _ => FileFormat::Unknown,
83 }
84 } else {
85 FileFormat::Unknown
86 }
87 }
88
89 pub fn is_supported(&self, format: FileFormat) -> bool {
91 !matches!(format, FileFormat::Unknown)
92 }
93}
94
95impl Default for FormatDetector {
96 fn default() -> Self {
97 Self::new()
98 }
99}
100
101impl FileFormat {
102 pub fn is_image(&self) -> bool {
104 matches!(
105 self,
106 FileFormat::Jpeg
107 | FileFormat::Png
108 | FileFormat::Gif
109 | FileFormat::WebP
110 | FileFormat::Tiff
111 | FileFormat::Bmp
112 )
113 }
114
115 pub fn is_document(&self) -> bool {
117 matches!(self, FileFormat::Pdf)
118 }
119
120 pub fn is_text(&self) -> bool {
122 matches!(self, FileFormat::Text)
123 }
124
125 pub fn mime_type(&self) -> &'static str {
127 match self {
128 FileFormat::Jpeg => "image/jpeg",
129 FileFormat::Png => "image/png",
130 FileFormat::Gif => "image/gif",
131 FileFormat::WebP => "image/webp",
132 FileFormat::Tiff => "image/tiff",
133 FileFormat::Bmp => "image/bmp",
134 FileFormat::Pdf => "application/pdf",
135 FileFormat::Text => "text/plain",
136 FileFormat::Unknown => "application/octet-stream",
137 }
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn test_format_detector_creation() {
147 let detector = FormatDetector::new();
148 assert!(std::mem::size_of_val(&detector) == std::mem::size_of::<FormatDetector>());
150 }
151
152 #[test]
153 fn test_detect_from_extension() {
154 let detector = FormatDetector::new();
155
156 assert_eq!(
157 detector.detect_from_extension("image.jpg"),
158 FileFormat::Jpeg
159 );
160 assert_eq!(
161 detector.detect_from_extension("document.pdf"),
162 FileFormat::Pdf
163 );
164 assert_eq!(
165 detector.detect_from_extension("script.rs"),
166 FileFormat::Text
167 );
168 assert_eq!(
169 detector.detect_from_extension("unknown.xyz"),
170 FileFormat::Unknown
171 );
172 }
173
174 #[test]
175 fn test_file_format_properties() {
176 assert!(FileFormat::Jpeg.is_image());
177 assert!(!FileFormat::Jpeg.is_document());
178 assert!(!FileFormat::Jpeg.is_text());
179
180 assert!(FileFormat::Pdf.is_document());
181 assert!(!FileFormat::Pdf.is_image());
182 assert!(!FileFormat::Pdf.is_text());
183
184 assert!(FileFormat::Text.is_text());
185 assert!(!FileFormat::Text.is_image());
186 assert!(!FileFormat::Text.is_document());
187 }
188
189 #[test]
190 fn test_mime_types() {
191 assert_eq!(FileFormat::Jpeg.mime_type(), "image/jpeg");
192 assert_eq!(FileFormat::Pdf.mime_type(), "application/pdf");
193 assert_eq!(FileFormat::Text.mime_type(), "text/plain");
194 assert_eq!(FileFormat::Unknown.mime_type(), "application/octet-stream");
195 }
196
197 #[test]
198 fn test_is_supported() {
199 let detector = FormatDetector::new();
200
201 assert!(detector.is_supported(FileFormat::Jpeg));
202 assert!(detector.is_supported(FileFormat::Pdf));
203 assert!(detector.is_supported(FileFormat::Text));
204 assert!(!detector.is_supported(FileFormat::Unknown));
205 }
206
207 #[test]
208 fn test_detect_from_bytes_text() {
209 let detector = FormatDetector::new();
210 let text_bytes = b"Hello, world!";
211
212 assert_eq!(detector.detect_from_bytes(text_bytes), FileFormat::Text);
213 }
214}