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}