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}