Skip to content

Commit 7ec554e

Browse files
authored
Merge pull request #232 from Wulf/wulf/custom-crate-path
Allow users to specify a custom path to the rust_embed crate in generated code
2 parents 0745567 + e1f172e commit 7ec554e

File tree

3 files changed

+60
-27
lines changed

3 files changed

+60
-27
lines changed

.github/workflows/test.yml

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ jobs:
3737
cargo test --test mime_guess --features "mime-guess" --release
3838
cargo test --test interpolated_path --features "interpolate-folder-path"
3939
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
4042
cargo build --example basic
4143
cargo build --example rocket --features rocket
4244
cargo build --example actix --features actix

impl/src/lib.rs

+38-27
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use syn::{parse_macro_input, Data, DeriveInput, Expr, ExprLit, Fields, Lit, Meta
1717

1818
fn embedded(
1919
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,
2121
) -> syn::Result<TokenStream2> {
2222
extern crate rust_embed_utils;
2323

@@ -30,7 +30,7 @@ fn embedded(
3030
for rust_embed_utils::FileEntry { rel_path, full_canonical_path } in rust_embed_utils::get_files(absolute_folder_path.clone(), matcher) {
3131
match_values.insert(
3232
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)?,
3434
);
3535

3636
list_values.push(if let Some(prefix) = prefix {
@@ -63,9 +63,9 @@ fn embedded(
6363
}
6464
});
6565
let value_type = if cfg!(feature = "compression") {
66-
quote! { fn() -> rust_embed::EmbeddedFile }
66+
quote! { fn() -> #crate_path::EmbeddedFile }
6767
} else {
68-
quote! { rust_embed::EmbeddedFile }
68+
quote! { #crate_path::EmbeddedFile }
6969
};
7070
let get_value = if cfg!(feature = "compression") {
7171
quote! {|idx| (ENTRIES[idx].1)()}
@@ -76,7 +76,7 @@ fn embedded(
7676
#not_debug_attr
7777
impl #ident {
7878
/// 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> {
8080
#handle_prefix
8181
let key = file_path.replace("\\", "/");
8282
const ENTRIES: &'static [(&'static str, #value_type)] = &[
@@ -98,18 +98,20 @@ fn embedded(
9898
}
9999

100100
#not_debug_attr
101-
impl rust_embed::RustEmbed for #ident {
102-
fn get(file_path: &str) -> ::std::option::Option<rust_embed::EmbeddedFile> {
101+
impl #crate_path::RustEmbed for #ident {
102+
fn get(file_path: &str) -> ::std::option::Option<#crate_path::EmbeddedFile> {
103103
#ident::get(file_path)
104104
}
105-
fn iter() -> rust_embed::Filenames {
106-
rust_embed::Filenames::Embedded(#ident::names())
105+
fn iter() -> #crate_path::Filenames {
106+
#crate_path::Filenames::Embedded(#ident::names())
107107
}
108108
}
109109
})
110110
}
111111

112-
fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includes: &[String], excludes: &[String], metadata_only: bool) -> TokenStream2 {
112+
fn dynamic(
113+
ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includes: &[String], excludes: &[String], metadata_only: bool, crate_path: &syn::Path,
114+
) -> TokenStream2 {
113115
let (handle_prefix, map_iter) = if let ::std::option::Option::Some(prefix) = prefix {
114116
(
115117
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
141143
impl #ident {
142144

143145

144-
fn matcher() -> ::rust_embed::utils::PathMatcher {
146+
fn matcher() -> #crate_path::utils::PathMatcher {
145147
#declare_includes
146148
#declare_excludes
147-
static PATH_MATCHER: ::std::sync::OnceLock<::rust_embed::utils::PathMatcher> = ::std::sync::OnceLock::new();
148-
PATH_MATCHER.get_or_init(|| rust_embed::utils::PathMatcher::new(INCLUDES, EXCLUDES)).clone()
149+
static PATH_MATCHER: ::std::sync::OnceLock<#crate_path::utils::PathMatcher> = ::std::sync::OnceLock::new();
150+
PATH_MATCHER.get_or_init(|| #crate_path::utils::PathMatcher::new(INCLUDES, EXCLUDES)).clone()
149151
}
150152
/// 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> {
152154
#handle_prefix
153155

154156
let rel_file_path = file_path.replace("\\", "/");
@@ -171,7 +173,7 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
171173
}
172174
let path_matcher = Self::matcher();
173175
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
175177
} else {
176178
::std::option::Option::None
177179
}
@@ -182,27 +184,27 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
182184
use ::std::path::Path;
183185

184186

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())
186188
.map(|e| #map_iter)
187189
}
188190
}
189191

190192
#[cfg(debug_assertions)]
191-
impl rust_embed::RustEmbed for #ident {
192-
fn get(file_path: &str) -> ::std::option::Option<rust_embed::EmbeddedFile> {
193+
impl #crate_path::RustEmbed for #ident {
194+
fn get(file_path: &str) -> ::std::option::Option<#crate_path::EmbeddedFile> {
193195
#ident::get(file_path)
194196
}
195-
fn iter() -> rust_embed::Filenames {
197+
fn iter() -> #crate_path::Filenames {
196198
// 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()))
198200
}
199201
}
200202
}
201203
}
202204

203205
fn generate_assets(
204206
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,
206208
) -> syn::Result<TokenStream2> {
207209
let embedded_impl = embedded(
208210
ident,
@@ -212,20 +214,23 @@ fn generate_assets(
212214
&includes,
213215
&excludes,
214216
metadata_only,
217+
crate_path,
215218
);
216219
if cfg!(feature = "debug-embed") {
217220
return embedded_impl;
218221
}
219222
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);
221224

222225
Ok(quote! {
223226
#embedded_impl
224227
#dynamic_impl
225228
})
226229
}
227230

228-
fn embed_file(folder_path: Option<&str>, ident: &syn::Ident, rel_path: &str, full_canonical_path: &str, metadata_only: bool) -> syn::Result<TokenStream2> {
231+
fn embed_file(
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> {
229234
let file = rust_embed_utils::read_file_from_fs(Path::new(full_canonical_path)).expect("File should be readable");
230235
let hash = file.metadata.sha256_hash();
231236
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
254259
let full_relative_path = PathBuf::from_iter([folder_path, rel_path]);
255260
let full_relative_path = full_relative_path.to_string_lossy();
256261
quote! {
257-
rust_embed::flate!(static BYTES: [u8] from #full_relative_path);
262+
#crate_path::flate!(static BYTES: [u8] from #full_relative_path);
258263
}
259264
} else {
260265
quote! {
@@ -270,9 +275,9 @@ fn embed_file(folder_path: Option<&str>, ident: &syn::Ident, rel_path: &str, ful
270275
#closure_args {
271276
#embedding_code
272277

273-
rust_embed::EmbeddedFile {
278+
#crate_path::EmbeddedFile {
274279
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)
276281
}
277282
}
278283
})
@@ -317,6 +322,11 @@ fn impl_rust_embed(ast: &syn::DeriveInput) -> syn::Result<TokenStream2> {
317322
_ => return Err(syn::Error::new_spanned(ast, "RustEmbed can only be derived for unit structs")),
318323
};
319324

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+
320330
let mut folder_paths = find_attribute_values(ast, "folder");
321331
if folder_paths.len() != 1 {
322332
return Err(syn::Error::new_spanned(
@@ -384,10 +394,11 @@ fn impl_rust_embed(ast: &syn::DeriveInput) -> syn::Result<TokenStream2> {
384394
includes,
385395
excludes,
386396
metadata_only,
397+
&crate_path,
387398
)
388399
}
389400

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))]
391402
pub fn derive_input_object(input: TokenStream) -> TokenStream {
392403
let ast = parse_macro_input!(input as DeriveInput);
393404
match impl_rust_embed(&ast) {

tests/custom_crate_path.rs

+20
Original file line numberDiff line numberDiff line change
@@ -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;

0 commit comments

Comments
 (0)