file_format/macros.rs
1//! Macros for generating the [`FileFormat`](crate::FileFormat) enum and associated methods.
2
3/// Generates the [`FileFormat`](crate::FileFormat) enum with methods for retrieving information.
4///
5/// # Parameters
6///
7/// - `format`: Variant representing the file format.
8/// - `name`: Full name of the file format.
9/// - `short_name`: Abbreviated name of the file format (optional).
10/// - `media_type`: Common media type associated with the file format.
11/// - `extension`: Common file extension used for the file format.
12/// - `kind`: Type or category of the file format.
13macro_rules! formats {
14 {
15 $(
16 format = $format:ident
17 name = $name:literal
18 $(short_name = $short_name:literal)?
19 media_type = $media_type:literal
20 extension = $extension:literal
21 kind = $kind:ident
22 )*
23 } => {
24 /// A file format.
25 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
26 #[non_exhaustive]
27 pub enum FileFormat {
28 $(
29 #[doc=concat!($name, $(" (", $short_name, ")",)? ".")]
30 #[doc=concat!("- Media type: `", $media_type, "`")]
31 #[doc=concat!("- Extension: `.", $extension, "`")]
32 #[doc=concat!("- Kind: [", stringify!($kind), "](crate::Kind::", stringify!($kind), ")")]
33 $format,
34 )*
35 }
36
37 impl crate::FileFormat {
38 /// Returns the full name of the file format.
39 ///
40 /// # Examples
41 ///
42 /// Basic usage:
43 ///
44 /// ```
45 /// use file_format::FileFormat;
46 ///
47 /// let fmt = FileFormat::Mpeg12AudioLayer3;
48 /// assert_eq!(fmt.name(), "MPEG-1/2 Audio Layer 3");
49 ///```
50 pub const fn name(&self) -> &str {
51 match self {
52 $(
53 Self::$format => $name,
54 )*
55 }
56 }
57
58 /// Returns the short name of the file format.
59 ///
60 /// Note: this information is not necessarily unique, as multiple file formats might
61 /// share the same short name.
62 ///
63 /// # Examples
64 ///
65 /// Basic usage:
66 ///
67 /// ```
68 /// use file_format::FileFormat;
69 ///
70 /// let fmt = FileFormat::MusicalInstrumentDigitalInterface;
71 /// assert_eq!(fmt.short_name(), Some("MIDI"));
72 ///```
73 pub const fn short_name(&self) -> Option<&str> {
74 match self {
75 $(
76 $(Self::$format => Some($short_name),)?
77 )*
78 _ => None,
79 }
80 }
81
82 /// Returns the common media type (formerly known as MIME type) of the file format as
83 /// defined in [IETF RFC 6838](https://tools.ietf.org/html/rfc6838).
84 ///
85 /// Note: some media types may not be defined in the
86 /// [IANA registry](https://www.iana.org/assignments/media-types/media-types.xhtml).
87 ///
88 /// # Examples
89 ///
90 /// Basic usage:
91 ///
92 /// ```
93 /// use file_format::FileFormat;
94 ///
95 /// let fmt = FileFormat::Zstandard;
96 /// assert_eq!(fmt.media_type(), "application/zstd");
97 ///```
98 pub const fn media_type(&self) -> &str {
99 match self {
100 $(
101 Self::$format => $media_type,
102 )*
103 }
104 }
105
106 /// Returns the common extension of the file format.
107 ///
108 /// Note: this information is never empty.
109 ///
110 /// # Examples
111 ///
112 /// Basic usage:
113 ///
114 /// ```
115 /// use file_format::FileFormat;
116 ///
117 /// let fmt = FileFormat::WindowsMediaVideo;
118 /// assert_eq!(fmt.extension(), "wmv");
119 ///```
120 pub const fn extension(&self) -> &str {
121 match self {
122 $(
123 Self::$format => $extension,
124 )*
125 }
126 }
127
128 /// Returns the [`Kind`](crate::Kind) of the file format.
129 ///
130 /// # Examples
131 ///
132 /// Basic usage:
133 ///
134 /// ```
135 /// use file_format::{FileFormat, Kind};
136 ///
137 /// let fmt = FileFormat::Zip;
138 /// assert_eq!(fmt.kind(), Kind::Archive);
139 ///```
140 pub const fn kind(&self) -> crate::Kind {
141 match self {
142 $(
143 Self::$format => crate::Kind::$kind,
144 )*
145 }
146 }
147 }
148 };
149}
150
151/// Generates the [`FileFormat::from_signature`](crate::FileFormat::from_signature) function.
152///
153/// # Parameters
154///
155/// - `format`: Variant representing the file format.
156/// - `value`: Signature value associated with the format (can be repeated).
157/// - `offset`: Offset to start matching the signature value (defaults to 0 if not specified).
158macro_rules! signatures {
159 {
160 $(
161 format = $format:ident
162 $(value = $($value:literal $(offset = $offset:literal)?),+)+
163 )*
164 } => {
165 impl crate::FileFormat {
166 /// Determines file format by checking its signature.
167 #[allow(clippy::int_plus_one)]
168 pub(crate) fn from_signature(bytes: &[u8]) -> Option<Self> {
169 $(
170 if $($(bytes.len() >= $($offset +)? $value.len()
171 && &bytes[$($offset)?..$($offset +)? $value.len()] == $value)&&*)||* {
172 return Some(Self::$format);
173 }
174 )*
175 None
176 }
177 }
178 };
179}