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}