manganis_common/
file.rs

1use serde::{Deserialize, Serialize};
2use std::{fmt::Display, str::FromStr};
3
4/// The options for a file asset
5#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Hash)]
6pub enum FileOptions {
7    /// An image asset
8    Image(ImageOptions),
9    /// A video asset
10    Video(VideoOptions),
11    /// A font asset
12    Font(FontOptions),
13    /// A css asset
14    Css(CssOptions),
15    /// Any other asset
16    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    /// Returns the default options for a given extension
33    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    /// Returns the extension for this file
53    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/// The options for an image asset
84#[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    /// Creates a new image options struct
111    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    /// Returns whether the image should be preloaded
121    pub fn preload(&self) -> bool {
122        self.preload
123    }
124
125    /// Sets whether the image should be preloaded
126    pub fn set_preload(&mut self, preload: bool) {
127        self.preload = preload;
128    }
129
130    /// Returns the image type
131    pub fn ty(&self) -> &ImageType {
132        &self.ty
133    }
134
135    /// Sets the image type
136    pub fn set_ty(&mut self, ty: ImageType) {
137        self.ty = ty;
138    }
139
140    /// Returns the size of the image
141    pub fn size(&self) -> Option<(u32, u32)> {
142        self.size
143    }
144
145    /// Sets the size of the image
146    pub fn set_size(&mut self, size: Option<(u32, u32)>) {
147        self.size = size;
148    }
149
150    /// Returns whether the image should be compressed
151    pub fn compress(&self) -> bool {
152        self.compress
153    }
154
155    /// Sets whether the image should be compressed
156    pub fn set_compress(&mut self, compress: bool) {
157        self.compress = compress;
158    }
159}
160
161/// The type of an image
162#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Copy, Hash)]
163pub enum ImageType {
164    /// A png image
165    Png,
166    /// A jpg image
167    Jpg,
168    /// An avif image
169    Avif,
170    /// A webp image
171    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/// The options for a video asset
200#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Hash)]
201pub struct VideoOptions {
202    /// Whether the video should be compressed
203    compress: bool,
204    /// The type of the video
205    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    /// Creates a new video options struct
220    pub fn new(ty: VideoType) -> Self {
221        Self { compress: true, ty }
222    }
223
224    /// Returns the type of the video
225    pub fn ty(&self) -> &VideoType {
226        &self.ty
227    }
228
229    /// Sets the type of the video
230    pub fn set_ty(&mut self, ty: VideoType) {
231        self.ty = ty;
232    }
233
234    /// Returns whether the video should be compressed
235    pub fn compress(&self) -> bool {
236        self.compress
237    }
238
239    /// Sets whether the video should be compressed
240    pub fn set_compress(&mut self, compress: bool) {
241        self.compress = compress;
242    }
243}
244
245/// The type of a video
246#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Hash)]
247pub enum VideoType {
248    /// An mp4 video
249    MP4,
250    /// A webm video
251    Webm,
252    /// A gif video
253    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/// The options for a font asset
267#[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    /// Creates a new font options struct
280    pub fn new(ty: FontType) -> Self {
281        Self { ty }
282    }
283
284    /// Returns the type of the font
285    pub fn ty(&self) -> &FontType {
286        &self.ty
287    }
288}
289
290/// The type of a font
291#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Hash)]
292pub enum FontType {
293    /// A ttf (TrueType) font
294    TTF,
295    /// A woff (Web Open Font Format) font
296    WOFF,
297    /// A woff2 (Web Open Font Format 2) font
298    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/// The options for a css asset
312#[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    /// Creates a new css options struct
328    pub fn new(minify: bool) -> Self {
329        Self { minify }
330    }
331
332    /// Returns whether the css should be minified
333    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/// The options for an unknown file asset
345#[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    /// Creates a new unknown file options struct
361    pub fn new(extension: Option<String>) -> Self {
362        Self { extension }
363    }
364
365    /// Returns the extension of the file
366    pub fn extension(&self) -> Option<&str> {
367        self.extension.as_deref()
368    }
369}