~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.


b51c27da Mark Drobnak

6 years ago
Merge pull request #49 from Tangent128/master
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
+ }