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}