~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 (4) hide show
  1. impl/src/lib.rs +22 -2
  2. readme.md +8 -0
  3. src/lib.rs +64 -0
  4. tests/lib.rs +14 -0
impl/src/lib.rs CHANGED
@@ -44,6 +44,15 @@ fn generate_assets(ident: &syn::Ident, folder_path: String) -> quote::Tokens {
44
44
  get_files(String::from(#folder_path)).map(|e| std::borrow::Cow::from(e.rel_path))
45
45
  }
46
46
  }
47
+ impl rust_embed::RustEmbed for #ident {
48
+ fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
49
+ #ident::get(file_path)
50
+ }
51
+ fn iter() -> rust_embed::Filenames {
52
+ // the return type of iter() is unnamable, so we have to box it
53
+ rust_embed::Filenames::Dynamic(Box::new(#ident::iter()))
54
+ }
55
+ }
47
56
  }
48
57
  }
49
58
 
@@ -75,11 +84,22 @@ fn generate_assets(ident: &syn::Ident, folder_path: String) -> quote::Tokens {
75
84
  }
76
85
  }
77
86
 
87
+ fn names() -> std::slice::Iter<'static, &'static str> {
88
+ const items: [&str; #array_len] = [#(#list_values),*];
89
+ items.iter()
90
+ }
78
91
  pub fn iter() -> impl Iterator<Item = std::borrow::Cow<'static, str>> {
79
- static items: [&str; #array_len] = [#(#list_values),*];
80
- items.iter().map(|x| std::borrow::Cow::from(*x))
92
+ Self::names().map(|x| std::borrow::Cow::from(*x))
81
93
  }
82
94
  }
95
+ impl rust_embed::RustEmbed for #ident {
96
+ fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
97
+ #ident::get(file_path)
98
+ }
99
+ fn iter() -> rust_embed::Filenames {
100
+ rust_embed::Filenames::Embedded(#ident::names())
101
+ }
102
+ }
83
103
  }
84
104
  }
85
105
 
readme.md CHANGED
@@ -44,6 +44,14 @@ impl Asset {
44
44
  ...
45
45
  }
46
46
  }
47
+ impl RustEmbed for Asset {
48
+ fn get(file_path: &str) -> Option<Cow<'static, [u8]>> {
49
+ ...
50
+ }
51
+ fn iter() -> impl Iterator<Item = Cow<'static, str>> {
52
+ ...
53
+ }
54
+ }
47
55
  ```
48
56
 
49
57
  ### `get(file_path: &str)`
src/lib.rs CHANGED
@@ -9,3 +9,67 @@ pub use rust_embed_impl::*;
9
9
  #[doc(hidden)]
10
10
  #[cfg(all(debug_assertions, not(feature = "debug-embed")))]
11
11
  pub mod utils;
12
+
13
+ /// A directory of binary assets.
14
+ ///
15
+ /// They should be embedded into the executable for release builds,
16
+ /// but can be read from the filesystem for debug builds.
17
+ ///
18
+ /// This trait is meant to be derived like so:
19
+ /// ```
20
+ /// #[macro_use]
21
+ /// extern crate rust_embed;
22
+ /// #[derive(RustEmbed)]
23
+ /// #[folder = "examples/public/"]
24
+ /// struct Asset;
25
+ /// ```
26
+
27
+ pub trait RustEmbed {
28
+ /// Given a relative path from the assets folder, returns the bytes if found.
29
+ ///
30
+ /// If the feature `debug-embed` is enabled or the binary is compiled in
31
+ /// release mode, the bytes have been embeded in the binary and a
32
+ /// `Cow::Borrowed(&'static [u8])` is returned.
33
+ ///
34
+ /// Otherwise, the bytes are read from the file system on each call and a
35
+ /// `Cow::Owned(Vec<u8>)` is returned.
36
+ fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>>;
37
+
38
+ /// Iterates the files in this assets folder.
39
+ ///
40
+ /// If the feature `debug-embed` is enabled or the binary is compiled in
41
+ /// release mode, a static array to the list of relative paths to the files
42
+ /// is used.
43
+ ///
44
+ /// Otherwise, the files are listed from the file system on each call.
45
+ fn iter() -> Filenames;
46
+ }
47
+
48
+ /// An iterator type over filenames.
49
+ ///
50
+ /// This enum exists for optimization purposes, to avoid boxing the iterator in
51
+ /// some cases. Do not try and match on it, as different variants will exist
52
+ /// depending on the compilation context.
53
+ pub enum Filenames {
54
+ /// Release builds use a nameable iterator type, which can be stack-allocated.
55
+ #[cfg(any(not(debug_assertions), feature = "debug-embed"))]
56
+ Embedded(std::slice::Iter<'static, &'static str>),
57
+
58
+ /// The debug iterator type is currently unnamable and still needs to be
59
+ /// boxed.
60
+ #[cfg(all(debug_assertions, not(feature = "debug-embed")))]
61
+ Dynamic(Box<dyn Iterator<Item = std::borrow::Cow<'static, str>>>),
62
+ }
63
+
64
+ impl Iterator for Filenames {
65
+ type Item = std::borrow::Cow<'static, str>;
66
+ fn next(&mut self) -> Option<Self::Item> {
67
+ match self {
68
+ #[cfg(any(not(debug_assertions), feature = "debug-embed"))]
69
+ Filenames::Embedded(names) => names.next().map(|x| std::borrow::Cow::from(*x)),
70
+
71
+ #[cfg(all(debug_assertions, not(feature = "debug-embed")))]
72
+ Filenames::Dynamic(boxed) => boxed.next(),
73
+ }
74
+ }
75
+ }
tests/lib.rs CHANGED
@@ -31,3 +31,17 @@ fn iter_works() {
31
31
  }
32
32
  assert_eq!(num_files, 6);
33
33
  }
34
+
35
+ #[test]
36
+ fn trait_works_generic() {
37
+ trait_works_generic_helper::<Asset>();
38
+ }
39
+ fn trait_works_generic_helper<E: rust_embed::RustEmbed>() {
40
+ let mut num_files = 0;
41
+ for file in E::iter() {
42
+ assert!(E::get(file.as_ref()).is_some());
43
+ num_files += 1;
44
+ }
45
+ assert_eq!(num_files, 6);
46
+ assert!(E::get("gg.html").is_none(), "gg.html should not exist");
47
+ }