~repos /rust-embed

#rust#proc-macro#http

git clone https://pyrossh.dev/repos/rust-embed.git

rust macro which loads files into the rust binary at compile time during release and loads the file from the fs during dev.


7ec554ea Peter John

1 year ago
Merge pull request #232 from Wulf/wulf/custom-crate-path
.github/workflows/test.yml CHANGED
@@ -37,6 +37,8 @@ jobs:
37
37
  cargo test --test mime_guess --features "mime-guess" --release
38
38
  cargo test --test interpolated_path --features "interpolate-folder-path"
39
39
  cargo test --test interpolated_path --features "interpolate-folder-path" --release
40
+ cargo test --test custom_crate_path
41
+ cargo test --test custom_crate_path --release
40
42
  cargo build --example basic
41
43
  cargo build --example rocket --features rocket
42
44
  cargo build --example actix --features actix
impl/src/lib.rs CHANGED
@@ -17,7 +17,7 @@ use syn::{parse_macro_input, Data, DeriveInput, Expr, ExprLit, Fields, Lit, Meta
17
17
 
18
18
  fn embedded(
19
19
  ident: &syn::Ident, relative_folder_path: Option<&str>, absolute_folder_path: String, prefix: Option<&str>, includes: &[String], excludes: &[String],
20
- metadata_only: bool,
20
+ metadata_only: bool, crate_path: &syn::Path,
21
21
  ) -> syn::Result<TokenStream2> {
22
22
  extern crate rust_embed_utils;
23
23
 
@@ -30,7 +30,7 @@ fn embedded(
30
30
  for rust_embed_utils::FileEntry { rel_path, full_canonical_path } in rust_embed_utils::get_files(absolute_folder_path.clone(), matcher) {
31
31
  match_values.insert(
32
32
  rel_path.clone(),
33
- embed_file(relative_folder_path, ident, &rel_path, &full_canonical_path, metadata_only)?,
33
+ embed_file(relative_folder_path, ident, &rel_path, &full_canonical_path, metadata_only, crate_path)?,
34
34
  );
35
35
 
36
36
  list_values.push(if let Some(prefix) = prefix {
@@ -63,9 +63,9 @@ fn embedded(
63
63
  }
64
64
  });
65
65
  let value_type = if cfg!(feature = "compression") {
66
- quote! { fn() -> rust_embed::EmbeddedFile }
66
+ quote! { fn() -> #crate_path::EmbeddedFile }
67
67
  } else {
68
- quote! { rust_embed::EmbeddedFile }
68
+ quote! { #crate_path::EmbeddedFile }
69
69
  };
70
70
  let get_value = if cfg!(feature = "compression") {
71
71
  quote! {|idx| (ENTRIES[idx].1)()}
@@ -76,7 +76,7 @@ fn embedded(
76
76
  #not_debug_attr
77
77
  impl #ident {
78
78
  /// Get an embedded file and its metadata.
79
- pub fn get(file_path: &str) -> ::std::option::Option<rust_embed::EmbeddedFile> {
79
+ pub fn get(file_path: &str) -> ::std::option::Option<#crate_path::EmbeddedFile> {
80
80
  #handle_prefix
81
81
  let key = file_path.replace("\\", "/");
82
82
  const ENTRIES: &'static [(&'static str, #value_type)] = &[
@@ -98,18 +98,20 @@ fn embedded(
98
98
  }
99
99
 
100
100
  #not_debug_attr
101
- impl rust_embed::RustEmbed for #ident {
101
+ impl #crate_path::RustEmbed for #ident {
102
- fn get(file_path: &str) -> ::std::option::Option<rust_embed::EmbeddedFile> {
102
+ fn get(file_path: &str) -> ::std::option::Option<#crate_path::EmbeddedFile> {
103
103
  #ident::get(file_path)
104
104
  }
105
- fn iter() -> rust_embed::Filenames {
105
+ fn iter() -> #crate_path::Filenames {
106
- rust_embed::Filenames::Embedded(#ident::names())
106
+ #crate_path::Filenames::Embedded(#ident::names())
107
107
  }
108
108
  }
109
109
  })
110
110
  }
111
111
 
112
+ fn dynamic(
112
- fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includes: &[String], excludes: &[String], metadata_only: bool) -> TokenStream2 {
113
+ ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includes: &[String], excludes: &[String], metadata_only: bool, crate_path: &syn::Path,
114
+ ) -> TokenStream2 {
113
115
  let (handle_prefix, map_iter) = if let ::std::option::Option::Some(prefix) = prefix {
114
116
  (
115
117
  quote! { let file_path = file_path.strip_prefix(#prefix)?; },
@@ -141,14 +143,14 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
141
143
  impl #ident {
142
144
 
143
145
 
144
- fn matcher() -> ::rust_embed::utils::PathMatcher {
146
+ fn matcher() -> #crate_path::utils::PathMatcher {
145
147
  #declare_includes
146
148
  #declare_excludes
147
- static PATH_MATCHER: ::std::sync::OnceLock<::rust_embed::utils::PathMatcher> = ::std::sync::OnceLock::new();
149
+ static PATH_MATCHER: ::std::sync::OnceLock<#crate_path::utils::PathMatcher> = ::std::sync::OnceLock::new();
148
- PATH_MATCHER.get_or_init(|| rust_embed::utils::PathMatcher::new(INCLUDES, EXCLUDES)).clone()
150
+ PATH_MATCHER.get_or_init(|| #crate_path::utils::PathMatcher::new(INCLUDES, EXCLUDES)).clone()
149
151
  }
150
152
  /// Get an embedded file and its metadata.
151
- pub fn get(file_path: &str) -> ::std::option::Option<rust_embed::EmbeddedFile> {
153
+ pub fn get(file_path: &str) -> ::std::option::Option<#crate_path::EmbeddedFile> {
152
154
  #handle_prefix
153
155
 
154
156
  let rel_file_path = file_path.replace("\\", "/");
@@ -171,7 +173,7 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
171
173
  }
172
174
  let path_matcher = Self::matcher();
173
175
  if path_matcher.is_path_included(&rel_file_path) {
174
- rust_embed::utils::read_file_from_fs(&canonical_file_path).ok() #strip_contents
176
+ #crate_path::utils::read_file_from_fs(&canonical_file_path).ok() #strip_contents
175
177
  } else {
176
178
  ::std::option::Option::None
177
179
  }
@@ -182,19 +184,19 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
182
184
  use ::std::path::Path;
183
185
 
184
186
 
185
- rust_embed::utils::get_files(::std::string::String::from(#folder_path), Self::matcher())
187
+ #crate_path::utils::get_files(::std::string::String::from(#folder_path), Self::matcher())
186
188
  .map(|e| #map_iter)
187
189
  }
188
190
  }
189
191
 
190
192
  #[cfg(debug_assertions)]
191
- impl rust_embed::RustEmbed for #ident {
193
+ impl #crate_path::RustEmbed for #ident {
192
- fn get(file_path: &str) -> ::std::option::Option<rust_embed::EmbeddedFile> {
194
+ fn get(file_path: &str) -> ::std::option::Option<#crate_path::EmbeddedFile> {
193
195
  #ident::get(file_path)
194
196
  }
195
- fn iter() -> rust_embed::Filenames {
197
+ fn iter() -> #crate_path::Filenames {
196
198
  // the return type of iter() is unnamable, so we have to box it
197
- rust_embed::Filenames::Dynamic(::std::boxed::Box::new(#ident::iter()))
199
+ #crate_path::Filenames::Dynamic(::std::boxed::Box::new(#ident::iter()))
198
200
  }
199
201
  }
200
202
  }
@@ -202,7 +204,7 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
202
204
 
203
205
  fn generate_assets(
204
206
  ident: &syn::Ident, relative_folder_path: Option<&str>, absolute_folder_path: String, prefix: Option<String>, includes: Vec<String>, excludes: Vec<String>,
205
- metadata_only: bool,
207
+ metadata_only: bool, crate_path: &syn::Path,
206
208
  ) -> syn::Result<TokenStream2> {
207
209
  let embedded_impl = embedded(
208
210
  ident,
@@ -212,12 +214,13 @@ fn generate_assets(
212
214
  &includes,
213
215
  &excludes,
214
216
  metadata_only,
217
+ crate_path,
215
218
  );
216
219
  if cfg!(feature = "debug-embed") {
217
220
  return embedded_impl;
218
221
  }
219
222
  let embedded_impl = embedded_impl?;
220
- let dynamic_impl = dynamic(ident, absolute_folder_path, prefix.as_deref(), &includes, &excludes, metadata_only);
223
+ let dynamic_impl = dynamic(ident, absolute_folder_path, prefix.as_deref(), &includes, &excludes, metadata_only, crate_path);
221
224
 
222
225
  Ok(quote! {
223
226
  #embedded_impl
@@ -225,7 +228,9 @@ fn generate_assets(
225
228
  })
226
229
  }
227
230
 
231
+ fn embed_file(
228
- fn embed_file(folder_path: Option<&str>, ident: &syn::Ident, rel_path: &str, full_canonical_path: &str, metadata_only: bool) -> syn::Result<TokenStream2> {
232
+ folder_path: Option<&str>, ident: &syn::Ident, rel_path: &str, full_canonical_path: &str, metadata_only: bool, crate_path: &syn::Path,
233
+ ) -> syn::Result<TokenStream2> {
229
234
  let file = rust_embed_utils::read_file_from_fs(Path::new(full_canonical_path)).expect("File should be readable");
230
235
  let hash = file.metadata.sha256_hash();
231
236
  let last_modified = match file.metadata.last_modified() {
@@ -254,7 +259,7 @@ fn embed_file(folder_path: Option<&str>, ident: &syn::Ident, rel_path: &str, ful
254
259
  let full_relative_path = PathBuf::from_iter([folder_path, rel_path]);
255
260
  let full_relative_path = full_relative_path.to_string_lossy();
256
261
  quote! {
257
- rust_embed::flate!(static BYTES: [u8] from #full_relative_path);
262
+ #crate_path::flate!(static BYTES: [u8] from #full_relative_path);
258
263
  }
259
264
  } else {
260
265
  quote! {
@@ -270,9 +275,9 @@ fn embed_file(folder_path: Option<&str>, ident: &syn::Ident, rel_path: &str, ful
270
275
  #closure_args {
271
276
  #embedding_code
272
277
 
273
- rust_embed::EmbeddedFile {
278
+ #crate_path::EmbeddedFile {
274
279
  data: ::std::borrow::Cow::Borrowed(&BYTES),
275
- metadata: rust_embed::Metadata::__rust_embed_new([#(#hash),*], #last_modified, #created #mimetype_tokens)
280
+ metadata: #crate_path::Metadata::__rust_embed_new([#(#hash),*], #last_modified, #created #mimetype_tokens)
276
281
  }
277
282
  }
278
283
  })
@@ -317,6 +322,11 @@ fn impl_rust_embed(ast: &syn::DeriveInput) -> syn::Result<TokenStream2> {
317
322
  _ => return Err(syn::Error::new_spanned(ast, "RustEmbed can only be derived for unit structs")),
318
323
  };
319
324
 
325
+ let crate_path: syn::Path = find_attribute_values(ast, "crate_path")
326
+ .last()
327
+ .map(|v| syn::parse_str(&v).unwrap())
328
+ .unwrap_or_else(|| syn::parse_str("rust_embed").unwrap());
329
+
320
330
  let mut folder_paths = find_attribute_values(ast, "folder");
321
331
  if folder_paths.len() != 1 {
322
332
  return Err(syn::Error::new_spanned(
@@ -384,10 +394,11 @@ fn impl_rust_embed(ast: &syn::DeriveInput) -> syn::Result<TokenStream2> {
384
394
  includes,
385
395
  excludes,
386
396
  metadata_only,
397
+ &crate_path,
387
398
  )
388
399
  }
389
400
 
390
- #[proc_macro_derive(RustEmbed, attributes(folder, prefix, include, exclude, metadata_only))]
401
+ #[proc_macro_derive(RustEmbed, attributes(folder, prefix, include, exclude, metadata_only, crate_path))]
391
402
  pub fn derive_input_object(input: TokenStream) -> TokenStream {
392
403
  let ast = parse_macro_input!(input as DeriveInput);
393
404
  match impl_rust_embed(&ast) {
tests/custom_crate_path.rs ADDED
@@ -0,0 +1,20 @@
1
+ /// This test checks that the `crate_path` attribute can be used
2
+ /// to specify a custom path to the `rust_embed` crate.
3
+
4
+ mod custom {
5
+ pub mod path {
6
+ pub use rust_embed;
7
+ }
8
+ }
9
+
10
+ // We introduce a 'rust_embed' module here to break compilation in case
11
+ // the `rust_embed` crate is not loaded correctly.
12
+ //
13
+ // To test this, try commenting out the attribute which specifies the
14
+ // the custom crate path -- you should find that the test fails to compile.
15
+ mod rust_embed {}
16
+
17
+ #[derive(custom::path::rust_embed::RustEmbed)]
18
+ #[crate_path = "custom::path::rust_embed"]
19
+ #[folder = "examples/public/"]
20
+ struct Asset;