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


89b83a82 pyros2097

7 years ago
add dev version of custom derive macro
Files changed (9) hide show
  1. .vscode/settings.json +82 -0
  2. Cargo.lock +35 -1
  3. Cargo.toml +7 -2
  4. examples/basic.rs +28 -0
  5. examples/rocket.rs +14 -14
  6. examples/rouille.rs +0 -1
  7. readme.md +20 -22
  8. src/lib.rs +134 -94
  9. tests/lib.rs +47 -0
.vscode/settings.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "editor.tabSize": 2,
3
+ "editor.fontSize": 15,
4
+ "editor.wordWrapColumn": 160,
5
+ "editor.minimap.enabled": false,
6
+ "search.exclude": {
7
+ "**/node_modules": true,
8
+ "**/bower_components": true,
9
+ "**/.git": true,
10
+ "**/.DS_Store": true,
11
+ "**/__pycache__": true,
12
+ "**/target": true,
13
+ "**/dist": true,
14
+ "**/.expo": true,
15
+ "**/.cache": true,
16
+ "**/.cache-loader": true,
17
+ },
18
+ "files.exclude": {
19
+ "**/node_modules": true,
20
+ "**/.git": true,
21
+ "**/.DS_Store": true,
22
+ "**/__pycache__": true,
23
+ "**/target": true,
24
+ "**/dist": true,
25
+ "**/.expo": true,
26
+ "**/.cache": true,
27
+ "**/.cache-loader": true,
28
+ },
29
+ "files.watcherExclude": {
30
+ "**/node_modules": true,
31
+ "**/dist": true,
32
+ "**/.git/objects/**": true,
33
+ "**/node_modules/**": true,
34
+ "**/__pycache__": true,
35
+ "**/target": true,
36
+ "**/.expo": true,
37
+ "**/.cache": true,
38
+ "**/.cache-loader": true,
39
+ },
40
+ "workbench.editor.showTabs": false,
41
+ "explorer.openEditors.visible": 0,
42
+ "gitProjectManager.baseProjectsFolders": [
43
+ "~/Code",
44
+ ],
45
+ "gitProjectManager.openInNewWindow": true,
46
+ "window.zoomLevel": 0,
47
+ "window.menuBarVisibility": "toggle",
48
+ "workbench.iconTheme": "vscode-icons",
49
+ "git.confirmSync": false,
50
+ "git.enableSmartCommit": true,
51
+ "workbench.startupEditor": "newUntitledFile",
52
+ "gitlens.advanced.messages": {
53
+ "suppressCommitHasNoPreviousCommitWarning": false,
54
+ "suppressCommitNotFoundWarning": false,
55
+ "suppressFileNotUnderSourceControlWarning": false,
56
+ "suppressGitVersionWarning": false,
57
+ "suppressLineUncommittedWarning": false,
58
+ "suppressNoRepositoryWarning": false,
59
+ "suppressResultsExplorerNotice": true,
60
+ "suppressUpdateNotice": true,
61
+ "suppressWelcomeNotice": false
62
+ },
63
+ "workbench.colorTheme": "Dracula Soft",
64
+ "git.autofetch": true,
65
+ "gitlens.keymap": "alternate",
66
+ "sqltools.format": {
67
+ "indentSize": 2
68
+ },
69
+ "sqltools.connections": [
70
+ {
71
+ "name": "Postgres",
72
+ "server": "localhost",
73
+ "dialect": "PostgreSQL",
74
+ "port": 5432,
75
+ "database": "postgres",
76
+ "username": "postgres",
77
+ "askForPassword": false,
78
+ "password": "postgres",
79
+ "connectionTimeout": 300
80
+ }
81
+ ]
82
+ }
Cargo.lock CHANGED
@@ -555,6 +555,11 @@ dependencies = [
555
555
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
556
556
  ]
557
557
 
558
+ [[package]]
559
+ name = "quote"
560
+ version = "0.3.15"
561
+ source = "registry+https://github.com/rust-lang/crates.io-index"
562
+
558
563
  [[package]]
559
564
  name = "quote"
560
565
  version = "0.4.2"
@@ -709,14 +714,16 @@ dependencies = [
709
714
 
710
715
  [[package]]
711
716
  name = "rust-embed"
712
- version = "0.5.2"
717
+ version = "1.0.0"
713
718
  dependencies = [
714
719
  "fern 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
715
720
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
721
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
716
722
  "rocket 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
717
723
  "rocket_codegen 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
718
724
  "rocket_contrib 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
719
725
  "rouille 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
726
+ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
720
727
  "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
721
728
  ]
722
729
 
@@ -799,6 +806,16 @@ name = "state"
799
806
  version = "0.3.3"
800
807
  source = "registry+https://github.com/rust-lang/crates.io-index"
801
808
 
809
+ [[package]]
810
+ name = "syn"
811
+ version = "0.11.11"
812
+ source = "registry+https://github.com/rust-lang/crates.io-index"
813
+ dependencies = [
814
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
815
+ "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
816
+ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
817
+ ]
818
+
802
819
  [[package]]
803
820
  name = "syn"
804
821
  version = "0.12.14"
@@ -809,6 +826,14 @@ dependencies = [
809
826
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
810
827
  ]
811
828
 
829
+ [[package]]
830
+ name = "synom"
831
+ version = "0.11.3"
832
+ source = "registry+https://github.com/rust-lang/crates.io-index"
833
+ dependencies = [
834
+ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
835
+ ]
836
+
812
837
  [[package]]
813
838
  name = "tempdir"
814
839
  version = "0.3.6"
@@ -915,6 +940,11 @@ name = "unicode-normalization"
915
940
  version = "0.1.5"
916
941
  source = "registry+https://github.com/rust-lang/crates.io-index"
917
942
 
943
+ [[package]]
944
+ name = "unicode-xid"
945
+ version = "0.0.4"
946
+ source = "registry+https://github.com/rust-lang/crates.io-index"
947
+
918
948
  [[package]]
919
949
  name = "unicode-xid"
920
950
  version = "0.1.0"
@@ -1074,6 +1104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1074
1104
  "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
1075
1105
  "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
1076
1106
  "checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
1107
+ "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
1077
1108
  "checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408"
1078
1109
  "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
1079
1110
  "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
@@ -1099,7 +1130,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1099
1130
  "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
1100
1131
  "checksum smallvec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4f357e8cd37bf8822e1b964e96fd39e2cb5a0424f8aaa284ccaccc2162411c"
1101
1132
  "checksum state 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e2fe297055568778ddc83eb1d4292bcdab36bf9e5e7adf4d0ce4ee59caf778d9"
1133
+ "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
1102
1134
  "checksum syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8c5bc2d6ff27891209efa5f63e9de78648d7801f085e4653701a692ce938d6fd"
1135
+ "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
1103
1136
  "checksum tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f73eebdb68c14bcb24aef74ea96079830e7fa7b31a6106e42ea7ee887c1e134e"
1104
1137
  "checksum term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "f2077e54d38055cf1ca0fd7933a2e00cd3ec8f6fed352b2a377f06dcdaaf3281"
1105
1138
  "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
@@ -1113,6 +1146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1113
1146
  "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
1114
1147
  "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
1115
1148
  "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
1149
+ "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
1116
1150
  "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
1117
1151
  "checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae"
1118
1152
  "checksum url 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)" = "cbaa8377a162d88e7d15db0cf110c8523453edcbc5bc66d2b6fffccffa34a068"
Cargo.toml CHANGED
@@ -1,7 +1,7 @@
1
1
  [package]
2
2
  name = "rust-embed"
3
- version = "0.5.2"
3
+ version = "1.0.0"
4
- description = "Rust Marco which loads files into the rust binary at compile time during release and loads the file from the fs during dev"
4
+ description = "Rust Custom Derive Macro which loads files into the rust binary at compile time during release and loads the file from the fs during dev"
5
5
  readme = "readme.md"
6
6
  documentation = "https://docs.rs/rust-embed"
7
7
  repository = "https://github.com/pyros2097/rust-embed"
@@ -10,7 +10,12 @@ keywords = ["http", "rocket", "static", "web", "server"]
10
10
  categories = ["web-programming::http-server"]
11
11
  authors = ["pyros2097 <pyros2097@gmail.com>"]
12
12
 
13
+ [lib]
14
+ proc-macro = true
15
+
13
16
  [dependencies]
17
+ syn = "0.11"
18
+ quote = "0.3"
14
19
  log = "0.4"
15
20
  walkdir = "2.1.4"
16
21
 
examples/basic.rs ADDED
@@ -0,0 +1,28 @@
1
+ #![feature(attr_literals)]
2
+ #[macro_use]
3
+ extern crate log;
4
+ #[macro_use]
5
+ extern crate rust_embed;
6
+ extern crate fern;
7
+
8
+ #[derive(RustEmbed)]
9
+ #[folder("examples/public/")]
10
+ struct Asset;
11
+
12
+ fn main() {
13
+ fern::Dispatch::new()
14
+ .format(move |out, message, record| {
15
+ out.finish(format_args!(
16
+ "[{}][{}] {}",
17
+ record.target(),
18
+ record.level(),
19
+ message
20
+ ))
21
+ })
22
+ .level(log::LevelFilter::Info)
23
+ .chain(std::io::stdout())
24
+ .apply()
25
+ .expect("Could not initialize logger");
26
+ let index_html = Asset::get("index.html").unwrap();
27
+ println!("{:?}", std::str::from_utf8(&index_html));
28
+ }
examples/rocket.rs CHANGED
@@ -1,22 +1,26 @@
1
- #![feature(test, plugin, decl_macro)]
1
+ #![feature(test, plugin, decl_macro, attr_literals)]
2
2
  #![plugin(rocket_codegen)]
3
+ extern crate fern;
4
+ #[macro_use]
5
+ extern crate log;
3
6
  extern crate rocket;
4
7
  extern crate rocket_contrib;
8
+ #[macro_use]
5
9
  extern crate rust_embed;
6
- extern crate fern;
7
- extern crate log;
8
10
 
9
11
  use std::path::PathBuf;
10
12
  use std::ffi::OsStr;
11
13
  use std::io::Cursor;
12
14
  use rocket::response;
13
15
  use rocket::http::{ContentType, Status};
16
+
17
+ #[derive(RustEmbed)]
18
+ #[folder("examples/public/")]
14
- use rocket::State;
19
+ struct Asset;
15
- use rust_embed::*;
16
20
 
17
21
  #[get("/")]
18
- fn index<'r>(asset: State<Asset>) -> response::Result<'r> {
22
+ fn index<'r>() -> response::Result<'r> {
19
- asset("index.html".to_owned()).map_or_else(
23
+ Asset::get("index.html").map_or_else(
20
24
  || Err(Status::NotFound),
21
25
  |d| {
22
26
  response::Response::build()
@@ -28,7 +32,7 @@ fn index<'r>(asset: State<Asset>) -> response::Result<'r> {
28
32
  }
29
33
 
30
34
  #[get("/dist/<file..>")]
31
- fn dist<'r>(asset: State<Asset>, file: PathBuf) -> response::Result<'r> {
35
+ fn dist<'r>(file: PathBuf) -> response::Result<'r> {
32
36
  let filename = file.display().to_string();
33
37
  let ext = file
34
38
  .as_path()
@@ -36,7 +40,7 @@ fn dist<'r>(asset: State<Asset>, file: PathBuf) -> response::Result<'r> {
36
40
  .and_then(OsStr::to_str)
37
41
  .expect("Could not get file extension");
38
42
  let content_type = ContentType::from_extension(ext).expect("Could not get file content type");
39
- asset(filename.clone()).map_or_else(
43
+ Asset::get(&filename.clone()).map_or_else(
40
44
  || Err(Status::NotFound),
41
45
  |d| {
42
46
  response::Response::build()
@@ -61,9 +65,5 @@ fn main() {
61
65
  .chain(std::io::stdout())
62
66
  .apply()
63
67
  .expect("Could not initialize logger");
64
- let asset = embed!("examples/public/".to_owned());
65
- rocket::ignite()
66
- .manage(asset)
67
- .mount("/", routes![index, dist])
68
+ rocket::ignite().mount("/", routes![index, dist]).launch();
68
- .launch();
69
69
  }
examples/rouille.rs CHANGED
@@ -1,4 +1,3 @@
1
- #[macro_use]
2
1
  extern crate rouille;
3
2
 
4
3
  use rouille::Response;
readme.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ## Rust Embed [![Build Status](https://travis-ci.org/pyros2097/rust-embed.svg?branch=master)](https://travis-ci.org/pyros2097/rust-embed) [![crates.io](http://meritbadge.herokuapp.com/rust-embed)](https://crates.io/crates/rust-embed)
2
- Rust Marco which loads files into the rust binary at compile time during release and loads the file from the fs during dev.
2
+ Rust Custom Derive Macro which loads files into the rust binary at compile time during release and loads the file from the fs during dev.
3
3
 
4
4
  You can use this to embed your css, js and images into a single executable.
5
5
 
@@ -7,55 +7,53 @@ This is similar to [go-embed](https://github.com/pyros2097/go-embed).
7
7
 
8
8
  This is similar to [pony-embed](https://github.com/pyros2097/pony-embed).
9
9
 
10
- Note:
11
-
12
- This is not the same as std macros,
13
- `include_bytes!`
14
- `include_str!`
15
- these are macros which generate code at compile time for only files.
16
- `embed!("examples/public/")` accepts folders and returns a function to get the contents using the file path
17
-
18
10
  ## Installation
19
11
 
20
12
  ```
21
13
  [dependencies]
22
- rust-embed="0.5.2"
14
+ rust-embed="1.0.0"
23
15
  ```
24
16
 
25
17
  ## Documentation
26
- The `embed!` macro takes a folder path and returns a function which allows you to get the file by passing the file path within the folder. So now you can statically compile all your assets i.e. your /static/ or /public/ folders into the rust executable and serve them during release and in development it will load the file from the file
27
- system so that it doesn't take to much time to compile;]
28
-
18
+ Declare a struct name it Asset or something and add an attribute `folder` to it which has the path to your static folder.
29
19
  ```rust
20
+ #![feature(attr_literals)]
21
+
22
+ #[derive(RustEmbed)]
30
- asset(path: String) -> Option<Vec<u8>>
23
+ #[folder("examples/public/")]
24
+ struct Asset;
31
25
  ```
32
26
 
33
27
  ## Usage
34
28
  ```rust
29
+ #![feature(attr_literals)]
35
30
  #[macro_use]
36
31
  extern crate rust_embed;
32
+ #[macro_use]
33
+ extern crate log;
37
34
 
35
+ #[derive(RustEmbed)]
36
+ #[folder("examples/public/")]
38
- use rust_embed::*;
37
+ struct Asset;
39
38
 
40
39
  fn main() {
41
- let asset = embed!("examples/public/".to_owned());
42
- let index_html = asset("index.html".to_owned()).unwrap();
40
+ let index_html = Asset::get("index.html").unwrap();
43
- println!("{}", index_html);
41
+ println!("{:?}", std::str::from_utf8(&index_html));
44
42
  }
45
43
  ```
46
44
 
47
45
  ## Examples
48
46
  To run the example in dev mode where it reads from the fs,
49
47
 
50
- `cargo run --example rocket`
48
+ `cargo run --example basic`
51
49
 
52
50
  To run the example in release mode where it reads from binary,
53
51
 
54
- `cargo run --release --example rocket`
52
+ `cargo run --release --example basic`
55
53
  ## Testing
56
- debug: `cargo test --lib`
54
+ debug: `cargo test --tests --lib`
57
55
 
58
- release: `cargo test --lib --release`
56
+ release: `cargo test --tests --lib --release`
59
57
 
60
58
  Go Rusketeers!
61
59
  The power is yours!
src/lib.rs CHANGED
@@ -1,110 +1,150 @@
1
+ #![recursion_limit = "1024"]
2
+ extern crate proc_macro;
1
3
  #[macro_use]
4
+ extern crate quote;
2
- extern crate log;
5
+ extern crate syn;
6
+
3
7
  extern crate walkdir;
4
8
 
5
- pub type Asset = Box<Fn(String) -> Option<Vec<u8>> + std::marker::Sync + std::marker::Send>;
9
+ use proc_macro::TokenStream;
10
+ use syn::*;
11
+ use quote::Tokens;
6
12
 
7
13
  #[cfg(debug_assertions)]
8
- pub fn generate_assets(parent_path: String) -> Asset {
14
+ fn generate_assets(ident: &syn::Ident, folder_path: String) -> quote::Tokens {
15
+ quote!{
9
- use std::fs::File;
16
+ use std::fs::File;
17
+ use std::io::Read;
10
- use std::path::Path;
18
+ use std::path::Path;
19
+
11
- use std::io::Read;
20
+ impl #ident {
12
- info!("loading folder -> {}", parent_path);
21
+ pub fn get(file_path: &str) -> Option<Vec<u8>> {
13
- Box::new(move |file_path| {
22
+ let folder_path = #folder_path;
14
- let name = &format!("{}{}", parent_path, file_path);
23
+ let name = &format!("{}{}", folder_path, file_path);
15
- let path = &Path::new(name);
24
+ let path = &Path::new(name);
16
- let key = String::from(path.to_str().expect("Path does not have a string representation"));
25
+ let key = String::from(path.to_str().expect("Path does not have a string representation"));
17
- info!("asset from file -> {}", key);
26
+ info!("file: {}", key);
18
- let mut file = match File::open(path) {
27
+ let mut file = match File::open(path) {
19
- Ok(mut file) => file,
28
+ Ok(mut file) => file,
20
- Err(e) => {
29
+ Err(e) => {
21
- error!("could not open file -> {} {}", key, e);
30
+ error!("file: {} {}", key, e);
22
- return None
31
+ return None
23
- }
32
+ }
24
- };
33
+ };
25
- let mut data: Vec<u8> = Vec::new();
34
+ let mut data: Vec<u8> = Vec::new();
26
- match file.read_to_end(&mut data) {
35
+ match file.read_to_end(&mut data) {
27
- Ok(_) => Some(data),
36
+ Ok(_) => Some(data),
28
- Err(e) => {
37
+ Err(e) => {
29
- error!("could not open file -> {} {}", key, e);
38
+ error!("file: {} {}", key, e);
30
- return None
39
+ return None
31
- }
40
+ }
32
- }
41
+ }
33
- })
42
+ }
43
+ }
44
+ }
34
45
  }
35
46
 
36
47
  #[cfg(not(debug_assertions))]
37
- pub fn generate_assets<'a>(parent_path: String) -> Asset {
48
+ pub fn generate_assets(folder_path: String) -> Asset {
38
- use std::fs::File;
49
+ use std::fs::File;
39
- use std::io::Read;
50
+ use std::io::Read;
40
- use std::path::Path;
51
+ use std::path::Path;
41
- use walkdir::WalkDir;
52
+ use walkdir::WalkDir;
42
- use std::collections::HashMap;
53
+ use std::collections::HashMap;
43
-
44
- info!("loading folder -> {}", parent_path);
54
+ info!("loading folder -> {}", parent_path);
45
- let mut map = HashMap::new();
55
+ let mut map = HashMap::new();
46
- for entry in WalkDir::new(parent_path.clone()).into_iter().filter_map(|e| e.ok()).filter(|e| e.file_type().is_file()) {
56
+ for entry in WalkDir::new(parent_path.clone())
57
+ .into_iter()
58
+ .filter_map(|e| e.ok())
59
+ .filter(|e| e.file_type().is_file())
60
+ {
47
- info!("asset from file -> {}", entry.path().display());
61
+ info!("asset from file -> {}", entry.path().display());
48
- let base = &parent_path.clone();
62
+ let base = &parent_path.clone();
63
+ let key = String::from(
64
+ entry
65
+ .path()
66
+ .to_str()
49
- let key = String::from(entry.path().to_str().expect("Path does not have a string representation")).replace(base, "");
67
+ .expect("Path does not have a string representation"),
68
+ ).replace(base, "");
50
- let mut file = File::open(&Path::new(&entry.path())).unwrap_or_else(|e| {
69
+ let mut file = File::open(&Path::new(&entry.path())).unwrap_or_else(|e| {
51
- panic!("could not open file -> {} {}", key, e);
70
+ panic!("could not open file -> {} {}", key, e);
52
- });
71
+ });
53
- let mut data: Vec<u8> = Vec::new();
72
+ let mut data: Vec<u8> = Vec::new();
54
- file.read_to_end(&mut data).unwrap_or_else(|e| {
73
+ file.read_to_end(&mut data).unwrap_or_else(|e| {
55
- panic!("could not read file -> {} {}", key, e);
74
+ panic!("could not read file -> {} {}", key, e);
56
- });
75
+ });
57
- map.insert(key, data);
76
+ map.insert(key, data);
77
+ }
78
+ Box::new(move |file_path| {
79
+ info!("asset from cache -> {}", file_path);
80
+ match map.get(&file_path) {
81
+ Some(s) => Some(s.to_vec()),
82
+ None => None,
58
83
  }
84
+ });
85
+ quote!{
59
- Box::new(move |file_path| {
86
+ impl #ident {
60
- info!("asset from cache -> {}", file_path);
87
+ pub fn get(file_path: &str) -> Option<Vec<u8>> {
61
- match map.get(&file_path) {
88
+ match file_path {
62
- Some(s) => Some(s.to_vec()),
89
+ "index.html" => Some(vec![]),
63
- None => None,
90
+ _ => None,
64
- }
91
+ }
65
- })
92
+ }
93
+ }
94
+ }
66
95
  }
67
96
 
68
- #[macro_export]
97
+ fn help() {
69
- macro_rules! embed {
98
+ panic!(
70
- ($x:expr) => ( $crate::generate_assets($x) )
99
+ "#[derive(RustEmbed)] should contain one attribute like this #[golem(\"examples/public/\")]"
100
+ );
71
101
  }
72
102
 
103
+ fn impl_rust_embed(ast: &syn::DeriveInput) -> Tokens {
73
- #[cfg(test)]
104
+ match ast.body {
105
+ Body::Enum(_) => help(),
106
+ Body::Struct(ref data) => match data {
107
+ &VariantData::Struct(_) => help(),
74
- mod tests {
108
+ _ => {}
75
- #[test]
109
+ },
110
+ };
76
- #[cfg(debug_assertions)]
111
+ let ident = &ast.ident;
77
- fn dev() {
78
- let asset = embed!("examples/public/".to_owned());
79
- match asset("index.html".to_owned()) {
112
+ if ast.attrs.len() == 0 || ast.attrs.len() > 1 {
80
- None => assert!(false, "index.html should exist"),
81
- _ => assert!(true),
113
+ help();
82
- }
114
+ }
115
+ let value = &ast.attrs[0].value;
116
+ let items = match value {
117
+ &MetaItem::List(ref attr_name, ref items) => {
83
- match asset("gg.html".to_owned()) {
118
+ if attr_name == "folder" {
119
+ items
120
+ } else {
84
- Some(_) => assert!(false, "gg.html should not exist"),
121
+ panic!("#[derive(RustEmbed)] attribute name must be folder");
85
- _ => assert!(true),
86
- }
122
+ }
87
- match asset("images/llama.png".to_owned()) {
88
- None => assert!(false, "llama.png should exist"),
89
- _ => assert!(true),
90
- }
91
123
  }
92
-
93
- #[test]
94
- #[cfg(not(debug_assertions))]
95
- fn prod() {
124
+ _ => {
96
- let asset = embed!("examples/public/".to_owned());
97
- match asset("index.html".to_owned()) {
98
- None => assert!(false, "index.html should exist"),
125
+ panic!("#[derive(RustEmbed)] attribute name must be folder");
99
- _ => assert!(true),
100
- }
101
- match asset("gg.html".to_owned()) {
102
- Some(_) => assert!(false, "gg.html should not exist"),
103
- _ => assert!(true),
104
- }
105
- match asset("images/llama.png".to_owned()) {
106
- None => assert!(false, "llama.png should exist"),
107
- _ => assert!(true),
108
- }
109
126
  }
127
+ };
128
+ let item = &items[0];
129
+ let lit = match item {
130
+ &NestedMetaItem::Literal(ref l) => l,
131
+ _ => {
132
+ panic!("Hello");
133
+ }
134
+ };
135
+ let folder_path = match lit {
136
+ &Lit::Str(ref val, _) => val.clone(),
137
+ _ => {
138
+ panic!("#[derive(RustEmbed)] attribute value must be a string literal");
139
+ }
140
+ };
141
+ generate_assets(ident, folder_path)
142
+ }
143
+
144
+ #[proc_macro_derive(RustEmbed, attributes(folder))]
145
+ pub fn derive_input_object(input: TokenStream) -> TokenStream {
146
+ let s = input.to_string();
147
+ let ast = syn::parse_derive_input(&s).unwrap();
148
+ let gen = impl_rust_embed(&ast);
149
+ gen.parse().unwrap()
110
150
  }
tests/lib.rs ADDED
@@ -0,0 +1,47 @@
1
+ #![feature(attr_literals)]
2
+ #[macro_use]
3
+ extern crate log;
4
+ #[macro_use]
5
+ extern crate rust_embed;
6
+
7
+ #[test]
8
+ #[cfg(debug_assertions)]
9
+ fn dev() {
10
+ #[derive(RustEmbed)]
11
+ #[folder("examples/public/")]
12
+ struct Asset;
13
+
14
+ match Asset::get("index.html") {
15
+ None => assert!(false, "index.html should exist"),
16
+ _ => assert!(true),
17
+ }
18
+ match Asset::get("gg.html") {
19
+ Some(_) => assert!(false, "gg.html should not exist"),
20
+ _ => assert!(true),
21
+ }
22
+ match Asset::get("images/llama.png") {
23
+ None => assert!(false, "llama.png should exist"),
24
+ _ => assert!(true),
25
+ }
26
+ }
27
+
28
+ #[test]
29
+ #[cfg(not(debug_assertions))]
30
+ fn prod() {
31
+ #[derive(RustEmbed)]
32
+ #[folder("examples/public/")]
33
+ struct Asset;
34
+
35
+ match Asset::get("index.html") {
36
+ None => assert!(false, "index.html should exist"),
37
+ _ => assert!(true),
38
+ }
39
+ match Asset::get("gg.html") {
40
+ Some(_) => assert!(false, "gg.html should not exist"),
41
+ _ => assert!(true),
42
+ }
43
+ match Asset::get("images/llama.png") {
44
+ None => assert!(false, "llama.png should exist"),
45
+ _ => assert!(true),
46
+ }
47
+ }