axum_embed_files_macros/
lib.rsuse std::path::Path;
use proc_macro::TokenStream;
use quote::quote;
use axum_embed_files_core::{content_type, etag, last_modified};
#[derive(Debug)]
struct Input {
filename: String,
dir: Option<String>,
}
impl syn::parse::Parse for Input {
fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
let first_str: syn::LitStr = input.parse()?;
if input.is_empty() {
return Ok(Input {
filename: first_str.value(),
dir: None,
});
}
let _: syn::Token![,] = input.parse()?;
let filename: syn::LitStr = input.parse()?;
Ok(Input {
filename: filename.value(),
dir: Some(first_str.value()),
})
}
}
#[cfg(not(feature = "serve-from-fs"))]
fn render_bytes(file_path: &Path) -> proc_macro2::TokenStream {
let file_path_str = file_path.display().to_string(); quote!(include_bytes!(#file_path_str))
}
#[cfg(feature = "serve-from-fs")]
fn render_bytes(_file_path: &Path) -> proc_macro2::TokenStream {
let empty = syn::LitByteStr::new(&[], proc_macro2::Span::call_site());
quote!(#empty)
}
#[proc_macro]
pub fn embed_file(params: TokenStream) -> TokenStream {
let input: Input = syn::parse(params).unwrap();
let file_dir = {
let mut p = std::env::current_dir().unwrap();
if let Some(next) = &input.dir {
p = p.join(next);
}
p
};
let file_path = file_dir.join(&input.filename);
let contents = std::fs::read(&file_path).unwrap();
let directory = file_dir.display().to_string();
let filename = &input.filename;
let bytes = render_bytes(&file_path);
let etag = etag::generate(&contents[..]);
let last_modified = last_modified::of_path(&file_path).unwrap();
let content_type = match content_type::guess_from_path(&file_path) {
None => quote!(None),
Some(t) => quote!(Some(#t)),
};
quote! {
::axum_embed_files::service::EmbeddedFileService {
directory: #directory,
filename: #filename,
bytes: #bytes,
etag: #etag,
last_modified: #last_modified,
content_type: #content_type,
}
}.into()
}