Skip to content

Commit f05946c

Browse files
committed
Allow users to specify a custom path to the rust_embed crate in generated code
1 parent ed8faec commit f05946c

File tree

2 files changed

+55
-19
lines changed

2 files changed

+55
-19
lines changed

impl/src/lib.rs

+35-19
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use syn::{parse_macro_input, Data, DeriveInput, Expr, ExprLit, Fields, Lit, Meta
1616

1717
fn embedded(
1818
ident: &syn::Ident, relative_folder_path: Option<&str>, absolute_folder_path: String, prefix: Option<&str>, includes: &[String], excludes: &[String],
19+
crate_path: &syn::Path,
1920
) -> syn::Result<TokenStream2> {
2021
extern crate rust_embed_utils;
2122

@@ -57,9 +58,9 @@ fn embedded(
5758
}
5859
});
5960
let value_type = if cfg!(feature = "compression") {
60-
quote! { fn() -> rust_embed::EmbeddedFile }
61+
quote! { fn() -> #crate_path::EmbeddedFile }
6162
} else {
62-
quote! { rust_embed::EmbeddedFile }
63+
quote! { #crate_path::EmbeddedFile }
6364
};
6465
let get_value = if cfg!(feature = "compression") {
6566
quote! {|idx| (ENTRIES[idx].1)()}
@@ -70,7 +71,7 @@ fn embedded(
7071
#not_debug_attr
7172
impl #ident {
7273
/// Get an embedded file and its metadata.
73-
pub fn get(file_path: &str) -> ::std::option::Option<rust_embed::EmbeddedFile> {
74+
pub fn get(file_path: &str) -> ::std::option::Option<#crate_path::EmbeddedFile> {
7475
#handle_prefix
7576
let key = file_path.replace("\\", "/");
7677
const ENTRIES: &'static [(&'static str, #value_type)] = &[
@@ -92,18 +93,18 @@ fn embedded(
9293
}
9394

9495
#not_debug_attr
95-
impl rust_embed::RustEmbed for #ident {
96-
fn get(file_path: &str) -> ::std::option::Option<rust_embed::EmbeddedFile> {
96+
impl #crate_path::RustEmbed for #ident {
97+
fn get(file_path: &str) -> ::std::option::Option<#crate_path::EmbeddedFile> {
9798
#ident::get(file_path)
9899
}
99-
fn iter() -> rust_embed::Filenames {
100-
rust_embed::Filenames::Embedded(#ident::names())
100+
fn iter() -> #crate_path::Filenames {
101+
#crate_path::Filenames::Embedded(#ident::names())
101102
}
102103
}
103104
})
104105
}
105106

106-
fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includes: &[String], excludes: &[String]) -> TokenStream2 {
107+
fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includes: &[String], excludes: &[String], crate_path: &syn::Path) -> TokenStream2 {
107108
let (handle_prefix, map_iter) = if let ::std::option::Option::Some(prefix) = prefix {
108109
(
109110
quote! { let file_path = file_path.strip_prefix(#prefix)?; },
@@ -128,7 +129,7 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
128129
#[cfg(debug_assertions)]
129130
impl #ident {
130131
/// Get an embedded file and its metadata.
131-
pub fn get(file_path: &str) -> ::std::option::Option<rust_embed::EmbeddedFile> {
132+
pub fn get(file_path: &str) -> ::std::option::Option<#crate_path::EmbeddedFile> {
132133
#handle_prefix
133134

134135
#declare_includes
@@ -144,8 +145,8 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
144145
return ::std::option::Option::None;
145146
}
146147

147-
if rust_embed::utils::is_path_included(&rel_file_path, INCLUDES, EXCLUDES) {
148-
rust_embed::utils::read_file_from_fs(&canonical_file_path).ok()
148+
if #crate_path::utils::is_path_included(&rel_file_path, INCLUDES, EXCLUDES) {
149+
#crate_path::utils::read_file_from_fs(&canonical_file_path).ok()
149150
} else {
150151
::std::option::Option::None
151152
}
@@ -158,26 +159,27 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
158159
#declare_includes
159160
#declare_excludes
160161

161-
rust_embed::utils::get_files(::std::string::String::from(#folder_path), INCLUDES, EXCLUDES)
162+
#crate_path::utils::get_files(::std::string::String::from(#folder_path), INCLUDES, EXCLUDES)
162163
.map(|e| #map_iter)
163164
}
164165
}
165166

166167
#[cfg(debug_assertions)]
167-
impl rust_embed::RustEmbed for #ident {
168-
fn get(file_path: &str) -> ::std::option::Option<rust_embed::EmbeddedFile> {
168+
impl #crate_path::RustEmbed for #ident {
169+
fn get(file_path: &str) -> ::std::option::Option<#crate_path::EmbeddedFile> {
169170
#ident::get(file_path)
170171
}
171-
fn iter() -> rust_embed::Filenames {
172+
fn iter() -> #crate_path::Filenames {
172173
// the return type of iter() is unnamable, so we have to box it
173-
rust_embed::Filenames::Dynamic(::std::boxed::Box::new(#ident::iter()))
174+
#crate_path::Filenames::Dynamic(::std::boxed::Box::new(#ident::iter()))
174175
}
175176
}
176177
}
177178
}
178179

179180
fn generate_assets(
180181
ident: &syn::Ident, relative_folder_path: Option<&str>, absolute_folder_path: String, prefix: Option<String>, includes: Vec<String>, excludes: Vec<String>,
182+
crate_path: &syn::Path,
181183
) -> syn::Result<TokenStream2> {
182184
let embedded_impl = embedded(
183185
ident,
@@ -186,12 +188,13 @@ fn generate_assets(
186188
prefix.as_deref(),
187189
&includes,
188190
&excludes,
191+
crate_path,
189192
);
190193
if cfg!(feature = "debug-embed") {
191194
return embedded_impl;
192195
}
193196
let embedded_impl = embedded_impl?;
194-
let dynamic_impl = dynamic(ident, absolute_folder_path, prefix.as_deref(), &includes, &excludes);
197+
let dynamic_impl = dynamic(ident, absolute_folder_path, prefix.as_deref(), &includes, &excludes, crate_path);
195198

196199
Ok(quote! {
197200
#embedded_impl
@@ -273,6 +276,11 @@ fn impl_rust_embed(ast: &syn::DeriveInput) -> syn::Result<TokenStream2> {
273276
_ => return Err(syn::Error::new_spanned(ast, "RustEmbed can only be derived for unit structs")),
274277
};
275278

279+
let crate_path: syn::Path = find_attribute_values(ast, "crate_path")
280+
.last()
281+
.map(|v| syn::parse_str(&v).unwrap())
282+
.unwrap_or_else(|| syn::parse_str("rust_embed").unwrap());
283+
276284
let mut folder_paths = find_attribute_values(ast, "folder");
277285
if folder_paths.len() != 1 {
278286
return Err(syn::Error::new_spanned(
@@ -331,10 +339,18 @@ fn impl_rust_embed(ast: &syn::DeriveInput) -> syn::Result<TokenStream2> {
331339
return Err(syn::Error::new_spanned(ast, message));
332340
};
333341

334-
generate_assets(&ast.ident, relative_path.as_deref(), absolute_folder_path, prefix, includes, excludes)
342+
generate_assets(
343+
&ast.ident,
344+
relative_path.as_deref(),
345+
absolute_folder_path,
346+
prefix,
347+
includes,
348+
excludes,
349+
&crate_path,
350+
)
335351
}
336352

337-
#[proc_macro_derive(RustEmbed, attributes(folder, prefix, include, exclude))]
353+
#[proc_macro_derive(RustEmbed, attributes(folder, prefix, include, exclude, crate_path))]
338354
pub fn derive_input_object(input: TokenStream) -> TokenStream {
339355
let ast = parse_macro_input!(input as DeriveInput);
340356
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)