~repos /rust-embed
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
- .vscode/settings.json +82 -0
- Cargo.lock +35 -1
- Cargo.toml +7 -2
- examples/basic.rs +28 -0
- examples/rocket.rs +14 -14
- examples/rouille.rs +0 -1
- readme.md +20 -22
- src/lib.rs +134 -94
- 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.
|
|
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.
|
|
3
|
+
version = "1.0.0"
|
|
4
|
-
description = "Rust
|
|
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
|
-
|
|
19
|
+
struct Asset;
|
|
15
|
-
use rust_embed::*;
|
|
16
20
|
|
|
17
21
|
#[get("/")]
|
|
18
|
-
fn index<'r>(
|
|
22
|
+
fn index<'r>() -> response::Result<'r> {
|
|
19
|
-
|
|
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>(
|
|
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
|
-
|
|
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
|
-
|
|
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 [](https://travis-ci.org/pyros2097/rust-embed) [](https://crates.io/crates/rust-embed)
|
|
2
|
-
Rust
|
|
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.
|
|
14
|
+
rust-embed="1.0.0"
|
|
23
15
|
```
|
|
24
16
|
|
|
25
17
|
## Documentation
|
|
26
|
-
|
|
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
|
-
|
|
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
|
-
|
|
37
|
+
struct Asset;
|
|
39
38
|
|
|
40
39
|
fn main() {
|
|
41
|
-
let asset = embed!("examples/public/".to_owned());
|
|
42
|
-
let index_html =
|
|
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
|
|
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
|
|
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
|
|
5
|
+
extern crate syn;
|
|
6
|
+
|
|
3
7
|
extern crate walkdir;
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
use proc_macro::TokenStream;
|
|
10
|
+
use syn::*;
|
|
11
|
+
use quote::Tokens;
|
|
6
12
|
|
|
7
13
|
#[cfg(debug_assertions)]
|
|
8
|
-
|
|
14
|
+
fn generate_assets(ident: &syn::Ident, folder_path: String) -> quote::Tokens {
|
|
15
|
+
quote!{
|
|
9
|
-
|
|
16
|
+
use std::fs::File;
|
|
17
|
+
use std::io::Read;
|
|
10
|
-
|
|
18
|
+
use std::path::Path;
|
|
19
|
+
|
|
11
|
-
|
|
20
|
+
impl #ident {
|
|
12
|
-
|
|
21
|
+
pub fn get(file_path: &str) -> Option<Vec<u8>> {
|
|
13
|
-
|
|
22
|
+
let folder_path = #folder_path;
|
|
14
|
-
|
|
23
|
+
let name = &format!("{}{}", folder_path, file_path);
|
|
15
|
-
|
|
24
|
+
let path = &Path::new(name);
|
|
16
|
-
|
|
25
|
+
let key = String::from(path.to_str().expect("Path does not have a string representation"));
|
|
17
|
-
|
|
26
|
+
info!("file: {}", key);
|
|
18
|
-
|
|
27
|
+
let mut file = match File::open(path) {
|
|
19
|
-
|
|
28
|
+
Ok(mut file) => file,
|
|
20
|
-
|
|
29
|
+
Err(e) => {
|
|
21
|
-
|
|
30
|
+
error!("file: {} {}", key, e);
|
|
22
|
-
|
|
31
|
+
return None
|
|
23
|
-
|
|
32
|
+
}
|
|
24
|
-
|
|
33
|
+
};
|
|
25
|
-
|
|
34
|
+
let mut data: Vec<u8> = Vec::new();
|
|
26
|
-
|
|
35
|
+
match file.read_to_end(&mut data) {
|
|
27
|
-
|
|
36
|
+
Ok(_) => Some(data),
|
|
28
|
-
|
|
37
|
+
Err(e) => {
|
|
29
|
-
|
|
38
|
+
error!("file: {} {}", key, e);
|
|
30
|
-
|
|
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
|
|
48
|
+
pub fn generate_assets(folder_path: String) -> Asset {
|
|
38
|
-
|
|
49
|
+
use std::fs::File;
|
|
39
|
-
|
|
50
|
+
use std::io::Read;
|
|
40
|
-
|
|
51
|
+
use std::path::Path;
|
|
41
|
-
|
|
52
|
+
use walkdir::WalkDir;
|
|
42
|
-
|
|
53
|
+
use std::collections::HashMap;
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
info!("loading folder -> {}", parent_path);
|
|
45
|
-
|
|
55
|
+
let mut map = HashMap::new();
|
|
46
|
-
|
|
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
|
-
|
|
61
|
+
info!("asset from file -> {}", entry.path().display());
|
|
48
|
-
|
|
62
|
+
let base = &parent_path.clone();
|
|
63
|
+
let key = String::from(
|
|
64
|
+
entry
|
|
65
|
+
.path()
|
|
66
|
+
.to_str()
|
|
49
|
-
|
|
67
|
+
.expect("Path does not have a string representation"),
|
|
68
|
+
).replace(base, "");
|
|
50
|
-
|
|
69
|
+
let mut file = File::open(&Path::new(&entry.path())).unwrap_or_else(|e| {
|
|
51
|
-
|
|
70
|
+
panic!("could not open file -> {} {}", key, e);
|
|
52
|
-
|
|
71
|
+
});
|
|
53
|
-
|
|
72
|
+
let mut data: Vec<u8> = Vec::new();
|
|
54
|
-
|
|
73
|
+
file.read_to_end(&mut data).unwrap_or_else(|e| {
|
|
55
|
-
|
|
74
|
+
panic!("could not read file -> {} {}", key, e);
|
|
56
|
-
|
|
75
|
+
});
|
|
57
|
-
|
|
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
|
-
|
|
86
|
+
impl #ident {
|
|
60
|
-
|
|
87
|
+
pub fn get(file_path: &str) -> Option<Vec<u8>> {
|
|
61
|
-
|
|
88
|
+
match file_path {
|
|
62
|
-
|
|
89
|
+
"index.html" => Some(vec![]),
|
|
63
|
-
|
|
90
|
+
_ => None,
|
|
64
|
-
|
|
91
|
+
}
|
|
65
|
-
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
66
95
|
}
|
|
67
96
|
|
|
68
|
-
|
|
97
|
+
fn help() {
|
|
69
|
-
|
|
98
|
+
panic!(
|
|
70
|
-
(
|
|
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
|
-
|
|
104
|
+
match ast.body {
|
|
105
|
+
Body::Enum(_) => help(),
|
|
106
|
+
Body::Struct(ref data) => match data {
|
|
107
|
+
&VariantData::Struct(_) => help(),
|
|
74
|
-
|
|
108
|
+
_ => {}
|
|
75
|
-
|
|
109
|
+
},
|
|
110
|
+
};
|
|
76
|
-
|
|
111
|
+
let ident = &ast.ident;
|
|
77
|
-
fn dev() {
|
|
78
|
-
let asset = embed!("examples/public/".to_owned());
|
|
79
|
-
|
|
112
|
+
if ast.attrs.len() == 0 || ast.attrs.len() > 1 {
|
|
80
|
-
None => assert!(false, "index.html should exist"),
|
|
81
|
-
|
|
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
|
-
|
|
118
|
+
if attr_name == "folder" {
|
|
119
|
+
items
|
|
120
|
+
} else {
|
|
84
|
-
|
|
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
|
-
|
|
124
|
+
_ => {
|
|
96
|
-
let asset = embed!("examples/public/".to_owned());
|
|
97
|
-
match asset("index.html".to_owned()) {
|
|
98
|
-
|
|
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
|
+
}
|