manganis_core/
options.rs

1use const_serialize::SerializeConst;
2
3use crate::{
4    CssAssetOptions, CssModuleAssetOptions, FolderAssetOptions, ImageAssetOptions, JsAssetOptions,
5};
6
7/// Settings for a generic asset
8#[derive(
9    Debug,
10    Eq,
11    PartialEq,
12    PartialOrd,
13    Clone,
14    Copy,
15    Hash,
16    SerializeConst,
17    serde::Serialize,
18    serde::Deserialize,
19)]
20#[non_exhaustive]
21pub struct AssetOptions {
22    /// If a hash should be added to the asset path
23    pub(crate) add_hash: bool,
24    /// The variant of the asset
25    pub(crate) variant: AssetVariant,
26}
27
28impl AssetOptions {
29    /// Create a new asset options builder
30    pub const fn builder() -> AssetOptionsBuilder<()> {
31        AssetOptionsBuilder::new()
32    }
33
34    /// Get the variant of the asset
35    pub const fn variant(&self) -> &AssetVariant {
36        &self.variant
37    }
38
39    /// Check if a hash should be added to the asset path
40    pub const fn hash_suffix(&self) -> bool {
41        self.add_hash
42    }
43
44    /// Try to get the extension for the asset. If the asset options don't define an extension, this will return None
45    pub const fn extension(&self) -> Option<&'static str> {
46        match self.variant {
47            AssetVariant::Image(image) => image.extension(),
48            AssetVariant::Css(_) => Some("css"),
49            AssetVariant::CssModule(_) => Some("css"),
50            AssetVariant::Js(_) => Some("js"),
51            AssetVariant::Folder(_) => None,
52            AssetVariant::Unknown => None,
53        }
54    }
55
56    /// Convert the options into options for a generic asset
57    pub const fn into_asset_options(self) -> AssetOptions {
58        self
59    }
60}
61
62/// A builder for [`AssetOptions`]
63///
64/// ```rust
65/// # use manganis::{AssetOptions, Asset, asset};
66/// static ASSET: Asset = asset!(
67///     "/assets/style.css",
68///     AssetOptions::builder()
69///     .with_hash_suffix(false)
70/// );
71/// ```
72pub struct AssetOptionsBuilder<T> {
73    /// If a hash should be added to the asset path
74    pub(crate) add_hash: bool,
75    /// The variant of the asset
76    pub(crate) variant: T,
77}
78
79impl Default for AssetOptionsBuilder<()> {
80    fn default() -> Self {
81        Self::default()
82    }
83}
84
85impl AssetOptionsBuilder<()> {
86    /// Create a new asset options builder with an unknown variant
87    pub const fn new() -> Self {
88        Self {
89            add_hash: true,
90            variant: (),
91        }
92    }
93
94    /// Create a default asset options builder
95    pub const fn default() -> Self {
96        Self::new()
97    }
98
99    /// Convert the builder into asset options with the given variant
100    pub const fn into_asset_options(self) -> AssetOptions {
101        AssetOptions {
102            add_hash: self.add_hash,
103            variant: AssetVariant::Unknown,
104        }
105    }
106}
107
108impl<T> AssetOptionsBuilder<T> {
109    /// Create a new asset options builder with the given variant
110    pub(crate) const fn variant(variant: T) -> Self {
111        Self {
112            add_hash: true,
113            variant,
114        }
115    }
116
117    /// Set whether a hash should be added to the asset path. Manganis adds hashes to asset paths by default
118    /// for [cache busting](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching#cache_busting).
119    /// With hashed assets, you can serve the asset with a long expiration time, and when the asset changes,
120    /// the hash in the path will change, causing the browser to fetch the new version.
121    ///
122    /// This method will only effect if the hash is added to the bundled asset path. If you are using the asset
123    /// macro, the asset struct still needs to be used in your rust code to ensure the asset is included in the binary.
124    ///
125    /// <div class="warning">
126    ///
127    /// If you are using an asset outside of rust code where you know what the asset hash will be, you must use the
128    /// `#[used]` attribute to ensure the asset is included in the binary even if it is not referenced in the code.
129    ///
130    /// ```rust
131    /// #[used]
132    /// static ASSET: manganis::Asset = manganis::asset!(
133    ///     "/assets/style.css",
134    ///     manganis::AssetOptions::builder()
135    ///         .with_hash_suffix(false)
136    /// );
137    /// ```
138    ///
139    /// </div>
140    pub const fn with_hash_suffix(mut self, add_hash: bool) -> Self {
141        self.add_hash = add_hash;
142        self
143    }
144}
145
146/// Settings for a specific type of asset
147#[derive(
148    Debug,
149    Eq,
150    PartialEq,
151    PartialOrd,
152    Clone,
153    Copy,
154    Hash,
155    SerializeConst,
156    serde::Serialize,
157    serde::Deserialize,
158)]
159#[repr(C, u8)]
160#[non_exhaustive]
161pub enum AssetVariant {
162    /// An image asset
163    Image(ImageAssetOptions),
164    /// A folder asset
165    Folder(FolderAssetOptions),
166    /// A css asset
167    Css(CssAssetOptions),
168    /// A css module asset
169    CssModule(CssModuleAssetOptions),
170    /// A javascript asset
171    Js(JsAssetOptions),
172    /// An unknown asset
173    Unknown,
174}