deflate_macro/
lib.rs

1//!
2//!
3//! ## How to use:
4//!
5//! In `Cargo.toml`:
6//! ```toml
7//! [dependencies]
8//! flate2 = { version = "1", default-features = false, features = ["rust_backend"] }
9//! deflate-macro = "0.1"
10//! ```
11//!
12//! ```text
13//! /// Path relative to the cargo crate
14//! pub static COMPILE_TIME_COMPRESSED_RUNTIME_DECOMPRESSED: String = deflate_macro::decompress!("addons.json");
15//! ```
16//!
17use std::io::Write;
18
19use flate2::{write::GzEncoder, Compression};
20use proc_macro::TokenStream;
21use quote::quote;
22use syn::{parse_macro_input, LitStr};
23
24/// Returns decompressed bytes as temporary value (no caching)
25#[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    // Stable workaround: resolve relative to caller crate’s CARGO_MANIFEST_DIR
31    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}