embed_file/lib.rs
1#![doc = include_str!("../README.md")]
2#![warn(clippy::all, missing_docs, nonstandard_style, future_incompatible)]
3
4#[macro_export]
5/// Embeds the file contents as a string into the binary in release mode, but
6/// loads it from fs in debug.
7///
8/// The file path should be relative to the source file from which the macro is
9/// called (similar to [`include_str`]).
10///
11/// The macro returns a `Cow<'static, str>`, which can either be a reference to
12/// the static string included in the binary, or an owned string read from the
13/// file in debug mode.
14///
15/// Note: this macro will panic in debug mode if the file cannot be read (which
16/// is what you probably want).
17///
18/// ## Example
19///
20/// ```no_run
21/// # use embed_file::embed_string;
22/// let my_file_contents = embed_string!("path/to/my_file.txt");
23/// println!("{}", my_file_contents);
24/// ```
25macro_rules! embed_string {
26 ($path:literal) => {{
27 #[cfg(debug_assertions)]
28 {
29 use std::{borrow::Cow, fs, path::Path};
30
31 let this_file = Path::new(file!());
32 let this_dir = this_file
33 .parent()
34 .expect(&format!("embed_file: no parent for `{:?}`", this_file));
35 let path = this_dir.join($path);
36 let data = match fs::read_to_string(&path) {
37 Ok(s) => s,
38 Err(e) => panic!("embed_file: can't read `{:?}` because of {:?}", path, e),
39 };
40 let s: Cow<'static, str> = Cow::Owned(data);
41 s
42 }
43 #[cfg(not(debug_assertions))]
44 {
45 use std::borrow::Cow;
46
47 let s: Cow<'static, str> = Cow::Borrowed(include_str!($path));
48 s
49 }
50 }};
51}
52
53#[macro_export]
54/// Embeds the file contents as bytes into the binary in release mode, but
55/// loads it from the filesystem in debug.
56///
57/// The file path should be relative to the source file from which the macro is
58/// called (similar to [`include_bytes`]).
59///
60/// The macro returns a `Cow<'static, [u8]>`, which can either be a reference to
61/// the static byte slice included in the binary, or an owned byte vector read
62/// from the file in debug mode.
63///
64/// Note: this macro will panic in debug mode if the file cannot be read (which
65/// is what you probably want).
66///
67/// ## Example
68///
69/// ```no_run
70/// # use embed_file::embed_bytes;
71/// let my_file_bytes = embed_bytes!("path/to/my_file.bin");
72/// println!("File size: {}", my_file_bytes.len());
73/// ```
74macro_rules! embed_bytes {
75 ($path:literal) => {{
76 #[cfg(debug_assertions)]
77 {
78 use std::{borrow::Cow, fs, path::Path};
79
80 let this_file = Path::new(file!());
81 let this_dir = this_file
82 .parent()
83 .expect(&format!("embed_file: no parent for `{:?}`", this_file));
84 let path = this_dir.join($path);
85 let data = match fs::read(&path) {
86 Ok(bytes) => bytes,
87 Err(e) => panic!("embed_file: can't read `{:?}` because of {:?}", path, e),
88 };
89 let bytes: Cow<'static, [u8]> = Cow::Owned(data);
90 bytes
91 }
92 #[cfg(not(debug_assertions))]
93 {
94 use std::borrow::Cow;
95
96 let bytes: Cow<'static, [u8]> = Cow::Borrowed(include_bytes!($path));
97 bytes
98 }
99 }};
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn test_embed_string() {
108 assert!(embed_string!("lib.rs").contains("# embed-file"));
109 }
110
111 #[test]
112 fn test_embed_bytes() {
113 assert!(String::from_utf8(embed_bytes!("lib.rs").to_vec())
114 .unwrap()
115 .contains("# embed-file"));
116 }
117}