1use std::io::Write;
18
19use flate2::{write::GzEncoder, Compression};
20use proc_macro::TokenStream;
21use quote::quote;
22use syn::{parse_macro_input, LitStr};
23
24#[proc_macro]
26pub fn decompress(input: TokenStream) -> TokenStream {
27 let file_path = parse_macro_input!(input as LitStr);
28 let relative_path = file_path.value();
29
30 let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
32 let absolute_path = std::path::Path::new(&manifest_dir).join(&relative_path);
33
34 let content = match std::fs::read(&absolute_path) {
35 Ok(content) => content,
36 Err(e) => {
37 return syn::Error::new_spanned(
38 file_path,
39 format!(
40 "Failed to read file '{}': {} (resolved to {:?})",
41 relative_path, e, absolute_path
42 ),
43 )
44 .to_compile_error()
45 .into();
46 }
47 };
48
49 let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
50 encoder.write_all(&content).unwrap();
51 let compressed = encoder.finish().unwrap();
52 let bytes = compressed.iter().map(|&b| b as u8);
53
54 let expanded = quote! {
55 {
56 use flate2::read::GzDecoder;
57 use std::io::Read;
58
59 const COMPRESSED: &[u8] = &[#(#bytes),*];
60 let mut decoder = GzDecoder::new(COMPRESSED);
61 let mut decompressed = Vec::new();
62 decoder.read_to_end(&mut decompressed).expect("Decompression failed");
63 decompressed
64 }
65 };
66
67 TokenStream::from(expanded)
68}