axum_embed_files_macros/
lib.rs1use std::path::Path;
2
3use proc_macro::TokenStream;
4use quote::quote;
5
6use axum_embed_files_core::{content_type, etag, last_modified};
7
8#[derive(Debug)]
9struct Input {
10 filename: String,
11 dir: Option<String>,
12}
13
14impl syn::parse::Parse for Input {
15 fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
16 let first_str: syn::LitStr = input.parse()?;
17 if input.is_empty() {
18 return Ok(Input {
19 filename: first_str.value(),
20 dir: None,
21 });
22 }
23
24 let _: syn::Token![,] = input.parse()?;
25
26 let filename: syn::LitStr = input.parse()?;
27
28 Ok(Input {
29 filename: filename.value(),
30 dir: Some(first_str.value()),
31 })
32 }
33}
34
35#[cfg(not(feature = "serve-from-fs"))]
36fn render_bytes(file_path: &Path) -> proc_macro2::TokenStream {
37 let file_path_str = file_path.display().to_string(); quote!(include_bytes!(#file_path_str))
39}
40
41#[cfg(feature = "serve-from-fs")]
42fn render_bytes(_file_path: &Path) -> proc_macro2::TokenStream {
43 let empty = syn::LitByteStr::new(&[], proc_macro2::Span::call_site());
44 quote!(#empty)
45}
46
47#[proc_macro]
59pub fn embed_file(params: TokenStream) -> TokenStream {
60 let input: Input = syn::parse(params).unwrap();
61
62 let file_dir = {
63 let mut p = std::env::current_dir().unwrap();
64 if let Some(next) = &input.dir {
65 p = p.join(next);
66 }
67 p
68 };
69
70 let file_path = file_dir.join(&input.filename);
71
72 let contents = std::fs::read(&file_path).unwrap();
73
74 let directory = file_dir.display().to_string();
75 let filename = &input.filename;
76 let bytes = render_bytes(&file_path);
77 let etag = etag::generate(&contents[..]);
78 let last_modified = last_modified::of_path(&file_path).unwrap();
79 let content_type = match content_type::guess_from_path(&file_path) {
80 None => quote!(None),
81 Some(t) => quote!(Some(#t)),
82 };
83
84 quote! {
85 ::axum_embed_files::service::EmbeddedFileService {
86 directory: #directory,
87 filename: #filename,
88 bytes: #bytes,
89 etag: #etag,
90 last_modified: #last_modified,
91 content_type: #content_type,
92 }
93 }.into()
94}