manganis_core/
options.rs

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