~repos /rust-embed

#rust#proc-macro#http

git clone https://pyrossh.dev/repos/rust-embed.git
Discussions: https://groups.google.com/g/rust-embed-devs

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


Files changed (2) hide show
  1. impl/src/lib.rs +34 -22
  2. utils/src/lib.rs +7 -7
impl/src/lib.rs CHANGED
@@ -9,13 +9,15 @@ use proc_macro2::TokenStream as TokenStream2;
9
9
  use std::{env, path::Path};
10
10
  use syn::{Data, DeriveInput, Fields, Lit, Meta, MetaNameValue};
11
11
 
12
- fn embedded(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includes: Vec<String>, excludes: Vec<String>) -> TokenStream2 {
12
+ fn embedded(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includes: &[String], excludes: &[String]) -> TokenStream2 {
13
13
  extern crate rust_embed_utils;
14
14
 
15
15
  let mut match_values = Vec::<TokenStream2>::new();
16
16
  let mut list_values = Vec::<String>::new();
17
17
 
18
+ let includes: Vec<&str> = includes.iter().map(AsRef::as_ref).collect();
19
+ let excludes: Vec<&str> = excludes.iter().map(AsRef::as_ref).collect();
18
- for rust_embed_utils::FileEntry { rel_path, full_canonical_path } in rust_embed_utils::get_files(folder_path, includes, excludes) {
20
+ for rust_embed_utils::FileEntry { rel_path, full_canonical_path } in rust_embed_utils::get_files(folder_path, &includes, &excludes) {
19
21
  match_values.push(embed_file(&rel_path, &full_canonical_path));
20
22
 
21
23
  list_values.push(if let Some(prefix) = prefix {
@@ -78,7 +80,7 @@ fn embedded(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, inclu
78
80
  }
79
81
  }
80
82
 
81
- fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includes: Vec<String>, excludes: Vec<String>) -> TokenStream2 {
83
+ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includes: &[String], excludes: &[String]) -> TokenStream2 {
82
84
  let (handle_prefix, map_iter) = if let Some(prefix) = prefix {
83
85
  (
84
86
  quote! { let file_path = file_path.strip_prefix(#prefix)?; },
@@ -88,12 +90,12 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
88
90
  (TokenStream2::new(), quote! { std::borrow::Cow::from(e.rel_path) })
89
91
  };
90
92
 
91
- let includes = quote! {
93
+ let declare_includes = quote! {
92
- vec![#(String::from(#includes)),*]
94
+ const includes: &[&str] = &[#(#includes),*];
93
95
  };
94
96
 
95
- let excludes = quote! {
97
+ let declare_excludes = quote! {
96
- vec![#(String::from(#excludes)),*]
98
+ const excludes: &[&str] = &[#(#excludes),*];
97
99
  };
98
100
 
99
101
  quote! {
@@ -103,12 +105,13 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
103
105
  pub fn get(file_path: &str) -> Option<rust_embed::EmbeddedFile> {
104
106
  #handle_prefix
105
107
 
106
- let file_path = std::path::Path::new(#folder_path).join(file_path.replace("\\", "/"));
107
- let rel_file_path = file_path.to_str()
108
+ #declare_includes
108
- .expect("Path does not have a string representation")
109
+ #declare_excludes
109
- .strip_prefix(#folder_path).expect("Failed to turn path to relative path");
110
110
 
111
+ let rel_file_path = file_path.replace("\\", "/");
112
+ let file_path = std::path::Path::new(#folder_path).join(&rel_file_path);
113
+
111
- if rust_embed::utils::is_path_included(rel_file_path, &#includes, &#excludes) {
114
+ if rust_embed::utils::is_path_included(&rel_file_path, includes, excludes) {
112
115
  rust_embed::utils::read_file_from_fs(&file_path).ok()
113
116
  } else {
114
117
  None
@@ -118,7 +121,11 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
118
121
  /// Iterates over the file paths in the folder.
119
122
  pub fn iter() -> impl Iterator<Item = std::borrow::Cow<'static, str>> {
120
123
  use std::path::Path;
124
+
125
+ #declare_includes
126
+ #declare_excludes
127
+
121
- rust_embed::utils::get_files(String::from(#folder_path), #includes, #excludes)
128
+ rust_embed::utils::get_files(String::from(#folder_path), includes, excludes)
122
129
  .map(|e| #map_iter)
123
130
  }
124
131
  }
@@ -137,12 +144,12 @@ fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>, includ
137
144
  }
138
145
 
139
146
  fn generate_assets(ident: &syn::Ident, folder_path: String, prefix: Option<String>, includes: Vec<String>, excludes: Vec<String>) -> TokenStream2 {
140
- let embedded_impl = embedded(ident, folder_path.clone(), prefix.as_deref(), includes.clone(), excludes.clone());
147
+ let embedded_impl = embedded(ident, folder_path.clone(), prefix.as_deref(), &includes, &excludes);
141
148
  if cfg!(feature = "debug-embed") {
142
149
  return embedded_impl;
143
150
  }
144
151
 
145
- let dynamic_impl = dynamic(ident, folder_path, prefix.as_deref(), includes, excludes);
152
+ let dynamic_impl = dynamic(ident, folder_path, prefix.as_deref(), &includes, &excludes);
146
153
 
147
154
  quote! {
148
155
  #embedded_impl
@@ -195,11 +202,6 @@ fn find_attribute_values(ast: &syn::DeriveInput, attr_name: &str) -> Vec<String>
195
202
  .collect()
196
203
  }
197
204
 
198
- /// Find a `name = "value"` attribute from the derive input
199
- fn find_attribute_value(ast: &syn::DeriveInput, attr_name: &str) -> Option<String> {
200
- find_attribute_values(ast, attr_name).into_iter().next()
201
- }
202
-
203
205
  fn impl_rust_embed(ast: &syn::DeriveInput) -> TokenStream2 {
204
206
  match ast.data {
205
207
  Data::Struct(ref data) => match data.fields {
@@ -209,8 +211,18 @@ fn impl_rust_embed(ast: &syn::DeriveInput) -> TokenStream2 {
209
211
  _ => panic!("RustEmbed can only be derived for unit structs"),
210
212
  };
211
213
 
214
+ let folder_path: String = {
215
+ let mut it = find_attribute_values(ast, "folder").into_iter();
216
+
217
+ match (it.next(), it.next()) {
218
+ (Some(folder_path), None) => folder_path,
219
+ _ => {
212
- let folder_path = find_attribute_value(ast, "folder").expect("#[derive(RustEmbed)] should contain one attribute like this #[folder = \"examples/public/\"]");
220
+ panic!("#[derive(RustEmbed)] must contain one attribute like this #[folder = \"examples/public/\"]");
221
+ }
222
+ }
223
+ };
224
+
213
- let prefix = find_attribute_value(ast, "prefix");
225
+ let prefix = find_attribute_values(ast, "prefix").into_iter().next();
214
226
  let includes = find_attribute_values(ast, "include");
215
227
  let excludes = find_attribute_values(ast, "exclude");
216
228
 
utils/src/lib.rs CHANGED
@@ -13,17 +13,17 @@ pub struct FileEntry {
13
13
  }
14
14
 
15
15
  #[cfg(not(feature = "include-exclude"))]
16
- pub fn is_path_included(_path: &str, _includes: &Vec<String>, _excludes: &Vec<String>) -> bool {
16
+ pub fn is_path_included(_path: &str, _includes: &[&str], _excludes: &[&str]) -> bool {
17
17
  return true;
18
18
  }
19
19
 
20
20
  #[cfg(feature = "include-exclude")]
21
- pub fn is_path_included(rel_path: &str, includes: &Vec<String>, excludes: &Vec<String>) -> bool {
21
+ pub fn is_path_included(rel_path: &str, includes: &[&str], excludes: &[&str]) -> bool {
22
22
  use glob::Pattern;
23
23
 
24
24
  // ignore path matched by exclusion pattern
25
25
  for exclude in excludes {
26
- let pattern = Pattern::new(exclude).expect(&format!("invalid exclude pattern '{}'", exclude));
26
+ let pattern = Pattern::new(exclude).unwrap_or_else(|_| panic!("invalid exclude pattern '{}'", exclude));
27
27
 
28
28
  if pattern.matches(rel_path) {
29
29
  return false;
@@ -37,18 +37,18 @@ pub fn is_path_included(rel_path: &str, includes: &Vec<String>, excludes: &Vec<S
37
37
 
38
38
  // accept path if matched by inclusion pattern
39
39
  for include in includes {
40
- let pattern = Pattern::new(include).expect(&format!("invalid include pattern '{}'", include));
40
+ let pattern = Pattern::new(include).unwrap_or_else(|_| panic!("invalid include pattern '{}'", include));
41
41
 
42
42
  if pattern.matches(rel_path) {
43
43
  return true;
44
44
  }
45
45
  }
46
46
 
47
- return false;
47
+ false
48
48
  }
49
49
 
50
50
  #[cfg_attr(all(debug_assertions, not(feature = "debug-embed")), allow(unused))]
51
- pub fn get_files(folder_path: String, includes: Vec<String>, excludes: Vec<String>) -> impl Iterator<Item = FileEntry> {
51
+ pub fn get_files<'patterns>(folder_path: String, includes: &'patterns [&str], excludes: &'patterns [&str]) -> impl Iterator<Item = FileEntry> + 'patterns {
52
52
  walkdir::WalkDir::new(&folder_path)
53
53
  .follow_links(true)
54
54
  .into_iter()
@@ -64,7 +64,7 @@ pub fn get_files(folder_path: String, includes: Vec<String>, excludes: Vec<Strin
64
64
  rel_path
65
65
  };
66
66
 
67
- if is_path_included(&rel_path, &includes, &excludes) {
67
+ if is_path_included(&rel_path, includes, excludes) {
68
68
  Some(FileEntry { rel_path, full_canonical_path })
69
69
  } else {
70
70
  None