1
Fork 0
mirror of https://github.com/RGBCube/embd-rs synced 2025-07-27 05:27:44 +00:00

Don't allocate for the children on release

This commit is contained in:
RGBCube 2024-01-05 09:23:43 +03:00
parent 2f2ec0f0c4
commit 161beeaf57
No known key found for this signature in database
2 changed files with 77 additions and 56 deletions

View file

@ -86,17 +86,28 @@ pub enum DirEntry {
#[derive(Debug, Clone)]
pub struct Dir {
/// The entries the directory houses.
pub children: Cow<'static, [DirEntry]>,
pub __children: Cow<'static, [DirEntry]>,
/// The absolute path of the directory.
pub path: Cow<'static, Path>,
pub __path: Cow<'static, str>, /* We are making it a &str because *
* include_*! takes a string anyway. */
}
impl Dir {
/// Returns the children of the directory.
pub fn children(&self) -> &[DirEntry] {
&self.__children
}
/// Returns the path of the directory.
pub fn path(&self) -> &Path {
Path::new(self.__path.as_ref().into())
}
/// Collects all files from the directory into a vector.
pub fn flatten(self) -> Vec<File> {
let mut entries = Vec::new();
for child in self.children.into_owned() {
for child in self.__children.into_owned() {
// TODO: Eliminate allocation.
match child {
DirEntry::File(file) => entries.push(file),
@ -112,9 +123,21 @@ impl Dir {
#[derive(Debug, Clone)]
pub struct File {
/// The content of the file in bytes.
pub content: Cow<'static, [u8]>,
pub __content: Cow<'static, [u8]>,
/// The absolute path of the file.
pub path: Cow<'static, Path>,
pub __path: Cow<'static, str>,
}
impl File {
/// Returns the content of the file.
pub fn content(&self) -> &[u8] {
&self.__content
}
/// Returns the path of the file.
pub fn path(&self) -> &Path {
Path::new(self.__path.as_ref().into())
}
}
fn read_dir(directory: &Path) -> Vec<DirEntry> {
@ -125,21 +148,30 @@ fn read_dir(directory: &Path) -> Vec<DirEntry> {
let filetype = entry.file_type().expect("Failed to read entry filetype");
let path = Cow::Owned::<'static, Path>(
entry
let path = entry
.path()
.canonicalize()
.expect("Failed to canonicalize path"),
);
.expect("Failed to canonicalize path");
let path_str = path
.to_str()
.expect("Failed to convert OsStr to str")
.to_string();
if filetype.is_dir() {
let children = Cow::Owned(read_dir(path.as_ref()));
let children = read_dir(&path);
entries.push(DirEntry::Dir(Dir { children, path }))
entries.push(DirEntry::Dir(Dir {
__children: children.into(),
__path: path_str.into(),
}))
} else if filetype.is_file() {
let content = Cow::Owned(fs::read(&path).expect("Failed to read file contents"));
let content = fs::read(&path).expect("Failed to read file contents");
entries.push(DirEntry::File(File { content, path }))
entries.push(DirEntry::File(File {
__content: content.into(),
__path: path_str.into(),
}))
}
}
@ -155,11 +187,16 @@ pub fn __dir_runtime(neighbor: &str, path: &str) -> Dir {
.canonicalize()
.expect("Failed to canonicalize path");
let directory_str = directory
.to_str()
.expect("Failed to convert OsStr to str")
.to_string();
let children = read_dir(&directory);
Dir {
children: children.into(),
path: directory.into(),
__children: children.into(),
__path: directory_str.into(),
}
}

View file

@ -1,6 +1,6 @@
use std::{
fs,
path::PathBuf,
path::Path,
};
use proc_macro as pm1;
@ -15,21 +15,6 @@ use syn::{
LitStr,
};
struct PathBuf2(PathBuf);
impl ToTokens for PathBuf2 {
fn to_tokens(&self, tokens: &mut TokenStream) {
let raw = self
.0
.to_str()
.expect("Failed to get the string representation of PathBuf");
tokens.extend(quote! {
::std::borrow::Cow::Borrowed(::std::path::Path::new(#raw))
});
}
}
struct TokenVec(Vec<TokenStream>);
impl ToTokens for TokenVec {
@ -37,8 +22,7 @@ impl ToTokens for TokenVec {
let inner = &self.0;
tokens.extend(quote! {{
const CHILDREN: &[::embed::DirEntry] = &[#(#inner),*]; // FIXME: Not const.
::std::borrow::Cow::Borrowed(CHILDREN)
::std::borrow::Cow::Borrowed(&[#(#inner),*])
}});
}
}
@ -77,53 +61,53 @@ fn dir_release(input: TokenStream, path: &str) -> TokenStream {
let base = neighbor.parent().expect("Failed to get the parent of file");
let directory = PathBuf2(
base.join(path)
let directory = base
.join(path)
.canonicalize()
.expect("Failed to canonicalize path"),
);
.expect("Failed to canonicalize path");
let children = read_dir(&directory.0);
let directory_str = directory.to_str().expect("Failed to convert OsStr to str");
let children = read_dir(&directory);
quote! {
::embed::Dir {
children: #children,
path: #directory,
__children: #children,
__path: ::std::borrow::Cow::Borrowed(#directory_str),
}
}
}
fn read_dir(directory: &PathBuf) -> TokenVec {
fn read_dir(directory: &Path) -> TokenVec {
let mut entries = Vec::new();
for entry in fs::read_dir(directory).expect("Failed to list directory contents") {
let entry = entry.expect("Failed to read entry");
let path = PathBuf2(entry.path());
let path = entry.path();
let filetype = fs::metadata(&path.0)
let path_str = path
.to_str()
.expect("Failed to get the string representation of PathBuf");
let filetype = fs::metadata(&path)
.expect("Failed to get file metadata")
.file_type();
if filetype.is_dir() {
let children = read_dir(&path.0);
let children = read_dir(&path);
entries.push(quote! {
::embed::DirEntry::Dir(::embed::Dir {
children: #children,
path: #path,
__children: #children,
__path: ::std::borrow::Cow::Borrowed(#path_str),
})
});
} else if filetype.is_file() {
let path_str = path
.0
.to_str()
.expect("Failed to get the string representation of PathBuf");
entries.push(quote! {
::embed::DirEntry::File(::embed::File {
content: ::std::borrow::Cow::Borrowed(include_bytes!(#path_str)),
path: #path,
__content: ::std::borrow::Cow::Borrowed(include_bytes!(#path_str)),
__path: ::std::borrow::Cow::Borrowed(#path_str),
})
});
}