lensfun 0.7.0

Pure-Rust port of LensFun: camera lens correction (distortion, TCA, vignetting) without C dependencies
Documentation
//! Compress every `data/db/*.xml` at build time and emit a Rust file that points
//! to the gzipped bytes in `OUT_DIR`. Runtime decompresses on first call to
//! `Database::load_bundled()`.

use std::fs;
use std::io::Write;
use std::path::PathBuf;

use flate2::Compression;
use flate2::write::GzEncoder;

fn main() {
    let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let db_dir = manifest_dir.join("data").join("db");
    let out_dir = PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR set by cargo"));

    println!("cargo:rerun-if-changed=data/db");
    println!("cargo:rerun-if-changed=build.rs");

    let mut xml_files: Vec<PathBuf> = fs::read_dir(&db_dir)
        .unwrap_or_else(|e| panic!("read {}: {e}", db_dir.display()))
        .filter_map(|entry| entry.ok().map(|e| e.path()))
        .filter(|p| p.is_file() && p.extension().is_some_and(|ext| ext == "xml"))
        .collect();
    xml_files.sort();

    let mut entries = String::new();
    for src in &xml_files {
        let name = src
            .file_name()
            .and_then(|n| n.to_str())
            .expect("xml filename is valid UTF-8");
        let bytes = fs::read(src).unwrap_or_else(|e| panic!("read {}: {e}", src.display()));
        let uncompressed_size = bytes.len();

        let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
        encoder.write_all(&bytes).expect("gzip write");
        let compressed = encoder.finish().expect("gzip finish");

        let gz_name = format!("{name}.gz");
        let gz_path = out_dir.join(&gz_name);
        fs::write(&gz_path, &compressed)
            .unwrap_or_else(|e| panic!("write {}: {e}", gz_path.display()));

        entries.push_str(&format!(
            "    BundledFile {{ name: {name:?}, uncompressed_size: {uncompressed_size}, gz: include_bytes!(concat!(env!(\"OUT_DIR\"), \"/{gz_name}\")) }},\n",
        ));
    }

    let generated = format!(
        "// @generated by build.rs — do not edit.\n\
         pub struct BundledFile {{\n\
         \x20   pub name: &'static str,\n\
         \x20   pub uncompressed_size: usize,\n\
         \x20   pub gz: &'static [u8],\n\
         }}\n\
         pub static BUNDLED_DB: &[BundledFile] = &[\n{entries}];\n",
    );

    let out_file = out_dir.join("bundled_db.rs");
    fs::write(&out_file, generated).unwrap_or_else(|e| panic!("write {}: {e}", out_file.display()));
}