ferrous-opencc 0.1.2

A pure Rust implementation of Open Chinese Convert (OpenCC), for fast and reliable conversion between Traditional and Simplified Chinese.
Documentation
use anyhow::{Context, Result};
use bincode::{Decode, Encode, config};
use fst::MapBuilder;
use std::collections::BTreeMap;
use std::env;
use std::fs;
use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
use std::io::{BufRead, BufReader};
use std::path::{Path, PathBuf};
use std::sync::Arc;

include!("compiler_logic.rs");

fn run() -> Result<()> {
    let out_dir = env::var("OUT_DIR").context("Failed to get OUT_DIR environment variable")?;
    let dest_path = Path::new(&out_dir);
    let mut dict_map_builder = phf_codegen::Map::new();
    let mut config_map_builder = phf_codegen::Map::new();

    let dict_source_dir = PathBuf::from("assets/dictionaries");
    if dict_source_dir.exists() {
        let entries = fs::read_dir(&dict_source_dir)?;
        for entry in entries {
            let entry = entry?;
            let path = entry.path();
            if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("txt") {
                let file_stem = path.file_stem().unwrap().to_str().unwrap();
                let ocd2_key_name = format!("{file_stem}.ocd2");
                let ocb_file_name = format!("{file_stem}.ocb");
                let ocb_path = dest_path.join(&ocb_file_name);
                let ocb_bytes = compile_dictionary(&path)?;
                fs::write(&ocb_path, ocb_bytes)?;
                let ocb_path_str = ocb_path.to_str().unwrap();

                let value_code = format!("include_bytes!(r\"{ocb_path_str}\")");
                dict_map_builder.entry(ocd2_key_name.clone(), &value_code);
            }
        }
    }

    let config_source_dir = PathBuf::from("assets/dictionaries");
    let mut configs_to_add: Vec<(String, String)> = Vec::new();
    if config_source_dir.exists() {
        let entries = fs::read_dir(&config_source_dir)?;
        for entry in entries {
            let entry = entry?;
            let path = entry.path();
            if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("json") {
                let file_name = path.file_name().unwrap().to_str().unwrap().to_string();
                let content = fs::read_to_string(&path)?;
                configs_to_add.push((file_name, content));
            }
        }
    }

    let formatted_config_values: Vec<String> = configs_to_add
        .iter()
        .map(|(_, content)| format!("r#\"{}\"#", content.trim()))
        .collect();

    for (i, (file_name, _)) in configs_to_add.iter().enumerate() {
        config_map_builder.entry(file_name.clone(), &formatted_config_values[i]);
    }

    let generated_map_path = dest_path.join("embedded_map.rs");
    let mut file = BufWriter::new(File::create(&generated_map_path)?);

    writeln!(
        &mut file,
        "// @generated - This file is automatically generated by build.rs."
    )?;
    writeln!(
        &mut file,
        "pub static EMBEDDED_DICTS: phf::Map<&'static str, &'static [u8]> = {};",
        dict_map_builder.build()
    )?;
    writeln!(
        &mut file,
        "pub static EMBEDDED_CONFIGS: phf::Map<&'static str, &'static str> = {};",
        config_map_builder.build()
    )?;

    Ok(())
}

fn main() {
    if let Err(e) = run() {
        eprintln!("cargo:warning=Build script ferrous-opencc/build.rs failed: {e:?}");
        std::process::exit(1);
    }
}