From 2f2ec0f0c4784c9d7085bc640e2b591c8f920c8d Mon Sep 17 00:00:00 2001 From: RGBCube Date: Fri, 5 Jan 2024 00:22:34 +0300 Subject: [PATCH] Use our own proc-macro2 fork and don't allocate anything at release (somewhat) --- Cargo.lock | 4 ++-- README.md | 20 +++++++++++++++++++- embed/src/lib.rs | 19 ++++++++----------- embed_macros/Cargo.toml | 3 +++ embed_macros/src/lib.rs | 9 ++++----- 5 files changed, 36 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c58b461..33cd329 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,9 +38,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.47" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1726efe18f42ae774cc644f330953a5e7b3c3003d3edcecf18850fe9d4dd9afb" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", diff --git a/README.md b/README.md index 3c49bbc..7f5c142 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,26 @@ A super simple file and directory embedding crate, that loads files from the filesystem in debug mode, allowing for quick edit-and-test cycles without compilation. +It is also super efficient, and does not heap allocate when the +files are embedded on release mode by utilizing `std::borrow::Cow`. + On release mode it falls back to `include_str!`, `include_bytes!` -and our own custom `include_dir!` implementation. +and our own custom `include_dir!`-like implementation. ## Usage +Add this to your Cargo.toml: + +```toml +[dependencies] +embed = { git = "https://github.com/RGBCube/embed-rs" } + +[patch.crates-io] +proc-macro2 = { git = "https://github.com/RGBCube/proc-macro2" } +``` + +Then you can use this crate as so: + ```rs let contents: Cow<'_, str> = embed::string!("path/to/file.txt"); let bytes: Cow<'_, [u8]> = embed::bytes!("path/to/image.png"); @@ -17,6 +32,9 @@ let dir: embed::Dir = embed::dir!("path/to"); let files: Vec = dir.flatten(); ``` +I am not sure what name to publish this +crate in, lmk if you find a good one. + ## License ``` diff --git a/embed/src/lib.rs b/embed/src/lib.rs index 4ebf700..459aadc 100644 --- a/embed/src/lib.rs +++ b/embed/src/lib.rs @@ -1,5 +1,3 @@ -#![cfg(procmacro2_semver_exempt)] - use std::{ borrow::Cow, fs, @@ -29,15 +27,13 @@ pub fn __string_runtime(neighbor: &str, path: &str) -> String { #[macro_export] macro_rules! string { ($path:literal) => {{ - use ::std::borrow::Cow; - #[cfg(debug_assertions)] { - Cow::Owned(::embed::__string_runtime(file!(), $path)) + ::std::borrow::Cow::Owned(::embed::__string_runtime(file!(), $path)) } #[cfg(not(debug_assertions))] { - Cow::Borrowed(include_str!($path)) + ::std::borrow::Cow::Borrowed(include_str!($path)) } }}; } @@ -90,7 +86,7 @@ pub enum DirEntry { #[derive(Debug, Clone)] pub struct Dir { /// The entries the directory houses. - pub children: Vec, + pub children: Cow<'static, [DirEntry]>, /// The absolute path of the directory. pub path: Cow<'static, Path>, } @@ -100,7 +96,8 @@ impl Dir { pub fn flatten(self) -> Vec { let mut entries = Vec::new(); - for child in self.children { + for child in self.children.into_owned() { + // TODO: Eliminate allocation. match child { DirEntry::File(file) => entries.push(file), DirEntry::Dir(dir) => entries.append(&mut dir.flatten()), @@ -136,7 +133,7 @@ fn read_dir(directory: &Path) -> Vec { ); if filetype.is_dir() { - let children = read_dir(path.as_ref()); + let children = Cow::Owned(read_dir(path.as_ref())); entries.push(DirEntry::Dir(Dir { children, path })) } else if filetype.is_file() { @@ -161,8 +158,8 @@ pub fn __dir_runtime(neighbor: &str, path: &str) -> Dir { let children = read_dir(&directory); Dir { - children, - path: Cow::Owned(directory), + children: children.into(), + path: directory.into(), } } diff --git a/embed_macros/Cargo.toml b/embed_macros/Cargo.toml index bea8357..6f33304 100644 --- a/embed_macros/Cargo.toml +++ b/embed_macros/Cargo.toml @@ -16,3 +16,6 @@ proc-macro = true proc-macro2 = { version = "1", features = [ "span-locations" ] } quote = "1" syn = "2" + +[patch.crates-io] +proc-macro2 = { git = "https://github.com/RGBCube/proc-macro2" } diff --git a/embed_macros/src/lib.rs b/embed_macros/src/lib.rs index f652e8b..d015ecc 100644 --- a/embed_macros/src/lib.rs +++ b/embed_macros/src/lib.rs @@ -1,5 +1,3 @@ -#![cfg(procmacro2_semver_exempt)] - use std::{ fs, path::PathBuf, @@ -38,9 +36,10 @@ impl ToTokens for TokenVec { fn to_tokens(&self, tokens: &mut TokenStream) { let inner = &self.0; - tokens.extend(quote! { - vec![#(#inner),*] - }); + tokens.extend(quote! {{ + const CHILDREN: &[::embed::DirEntry] = &[#(#inner),*]; // FIXME: Not const. + ::std::borrow::Cow::Borrowed(CHILDREN) + }}); } }