1use serde::{Deserialize, Serialize};
2use std::{fmt::Display, str::FromStr};
3
4#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Hash)]
6pub enum FileOptions {
7 Image(ImageOptions),
9 Video(VideoOptions),
11 Font(FontOptions),
13 Css(CssOptions),
15 Other(UnknownFileOptions),
17}
18
19impl Display for FileOptions {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 match self {
22 Self::Image(options) => write!(f, "{}", options),
23 Self::Video(options) => write!(f, "{}", options),
24 Self::Font(options) => write!(f, "{}", options),
25 Self::Css(options) => write!(f, "{}", options),
26 Self::Other(options) => write!(f, "{}", options),
27 }
28 }
29}
30
31impl FileOptions {
32 pub fn default_for_extension(extension: Option<&str>) -> Self {
34 match extension {
35 Some("png") => Self::Image(ImageOptions::new(ImageType::Png, None)),
36 Some("jpg") | Some("jpeg") => Self::Image(ImageOptions::new(ImageType::Jpg, None)),
37 Some("avif") => Self::Image(ImageOptions::new(ImageType::Avif, None)),
38 Some("webp") => Self::Image(ImageOptions::new(ImageType::Webp, None)),
39 Some("mp4") => Self::Video(VideoOptions::new(VideoType::MP4)),
40 Some("webm") => Self::Video(VideoOptions::new(VideoType::Webm)),
41 Some("gif") => Self::Video(VideoOptions::new(VideoType::GIF)),
42 Some("ttf") => Self::Font(FontOptions::new(FontType::TTF)),
43 Some("woff") => Self::Font(FontOptions::new(FontType::WOFF)),
44 Some("woff2") => Self::Font(FontOptions::new(FontType::WOFF2)),
45 Some("css") => Self::Css(CssOptions::default()),
46 _ => Self::Other(UnknownFileOptions {
47 extension: extension.map(String::from),
48 }),
49 }
50 }
51
52 pub fn extension(&self) -> Option<&str> {
54 match self {
55 Self::Image(options) => match options.ty {
56 ImageType::Png => Some("png"),
57 ImageType::Jpg => Some("jpg"),
58 ImageType::Avif => Some("avif"),
59 ImageType::Webp => Some("webp"),
60 },
61 Self::Video(options) => match options.ty {
62 VideoType::MP4 => Some("mp4"),
63 VideoType::Webm => Some("webm"),
64 VideoType::GIF => Some("gif"),
65 },
66 Self::Font(options) => match options.ty {
67 FontType::TTF => Some("ttf"),
68 FontType::WOFF => Some("woff"),
69 FontType::WOFF2 => Some("woff2"),
70 },
71 Self::Css(_) => Some("css"),
72 Self::Other(extension) => extension.extension.as_deref(),
73 }
74 }
75}
76
77impl Default for FileOptions {
78 fn default() -> Self {
79 Self::Other(UnknownFileOptions { extension: None })
80 }
81}
82
83#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Hash)]
85pub struct ImageOptions {
86 compress: bool,
87 size: Option<(u32, u32)>,
88 preload: bool,
89 ty: ImageType,
90}
91
92impl Display for ImageOptions {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 if let Some((x, y)) = self.size {
95 write!(f, "{} ({}x{})", self.ty, x, y)?;
96 } else {
97 write!(f, "{}", self.ty)?;
98 }
99 if self.compress {
100 write!(f, " (compressed)")?;
101 }
102 if self.preload {
103 write!(f, " (preload)")?;
104 }
105 Ok(())
106 }
107}
108
109impl ImageOptions {
110 pub fn new(ty: ImageType, size: Option<(u32, u32)>) -> Self {
112 Self {
113 compress: true,
114 size,
115 ty,
116 preload: false,
117 }
118 }
119
120 pub fn preload(&self) -> bool {
122 self.preload
123 }
124
125 pub fn set_preload(&mut self, preload: bool) {
127 self.preload = preload;
128 }
129
130 pub fn ty(&self) -> &ImageType {
132 &self.ty
133 }
134
135 pub fn set_ty(&mut self, ty: ImageType) {
137 self.ty = ty;
138 }
139
140 pub fn size(&self) -> Option<(u32, u32)> {
142 self.size
143 }
144
145 pub fn set_size(&mut self, size: Option<(u32, u32)>) {
147 self.size = size;
148 }
149
150 pub fn compress(&self) -> bool {
152 self.compress
153 }
154
155 pub fn set_compress(&mut self, compress: bool) {
157 self.compress = compress;
158 }
159}
160
161#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Copy, Hash)]
163pub enum ImageType {
164 Png,
166 Jpg,
168 Avif,
170 Webp,
172}
173
174impl Display for ImageType {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 Self::Png => write!(f, "png"),
178 Self::Jpg => write!(f, "jpg"),
179 Self::Avif => write!(f, "avif"),
180 Self::Webp => write!(f, "webp"),
181 }
182 }
183}
184
185impl FromStr for ImageType {
186 type Err = ();
187
188 fn from_str(s: &str) -> Result<Self, Self::Err> {
189 match s {
190 "png" => Ok(Self::Png),
191 "jpg" | "jpeg" => Ok(Self::Jpg),
192 "avif" => Ok(Self::Avif),
193 "webp" => Ok(Self::Webp),
194 _ => Err(()),
195 }
196 }
197}
198
199#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Hash)]
201pub struct VideoOptions {
202 compress: bool,
204 ty: VideoType,
206}
207
208impl Display for VideoOptions {
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 write!(f, "{}", self.ty)?;
211 if self.compress {
212 write!(f, " (compressed)")?;
213 }
214 Ok(())
215 }
216}
217
218impl VideoOptions {
219 pub fn new(ty: VideoType) -> Self {
221 Self { compress: true, ty }
222 }
223
224 pub fn ty(&self) -> &VideoType {
226 &self.ty
227 }
228
229 pub fn set_ty(&mut self, ty: VideoType) {
231 self.ty = ty;
232 }
233
234 pub fn compress(&self) -> bool {
236 self.compress
237 }
238
239 pub fn set_compress(&mut self, compress: bool) {
241 self.compress = compress;
242 }
243}
244
245#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Hash)]
247pub enum VideoType {
248 MP4,
250 Webm,
252 GIF,
254}
255
256impl Display for VideoType {
257 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258 match self {
259 Self::MP4 => write!(f, "mp4"),
260 Self::Webm => write!(f, "webm"),
261 Self::GIF => write!(f, "gif"),
262 }
263 }
264}
265
266#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Hash)]
268pub struct FontOptions {
269 ty: FontType,
270}
271
272impl Display for FontOptions {
273 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
274 write!(f, "{}", self.ty)
275 }
276}
277
278impl FontOptions {
279 pub fn new(ty: FontType) -> Self {
281 Self { ty }
282 }
283
284 pub fn ty(&self) -> &FontType {
286 &self.ty
287 }
288}
289
290#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Hash)]
292pub enum FontType {
293 TTF,
295 WOFF,
297 WOFF2,
299}
300
301impl Display for FontType {
302 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
303 match self {
304 Self::TTF => write!(f, "ttf"),
305 Self::WOFF => write!(f, "woff"),
306 Self::WOFF2 => write!(f, "woff2"),
307 }
308 }
309}
310
311#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Hash)]
313pub struct CssOptions {
314 minify: bool,
315}
316
317impl Display for CssOptions {
318 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
319 if self.minify {
320 write!(f, "minified")?;
321 }
322 Ok(())
323 }
324}
325
326impl CssOptions {
327 pub fn new(minify: bool) -> Self {
329 Self { minify }
330 }
331
332 pub fn minify(&self) -> bool {
334 self.minify
335 }
336}
337
338impl Default for CssOptions {
339 fn default() -> Self {
340 Self { minify: true }
341 }
342}
343
344#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Hash)]
346pub struct UnknownFileOptions {
347 extension: Option<String>,
348}
349
350impl Display for UnknownFileOptions {
351 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352 if let Some(extension) = &self.extension {
353 write!(f, "{}", extension)?;
354 }
355 Ok(())
356 }
357}
358
359impl UnknownFileOptions {
360 pub fn new(extension: Option<String>) -> Self {
362 Self { extension }
363 }
364
365 pub fn extension(&self) -> Option<&str> {
367 self.extension.as_deref()
368 }
369}