cimoxide-gen 0.5.1

Code generator turning ENTSO-E CGMES RDF/SHACL schemas into typed Rust structs and SHACL validators
//! Emits the model crate's generated module: one schema table per family.
//!
//! Every family is a table of classes decoded into property bags; there are no
//! generated types. What a class declares, which profiles define it and which
//! namespaces they bind all live in the family's `SCHEMA`
//! (`generator/classes_gen.rs`).

use std::fmt::Write as FmtWrite;
use std::fs;
use std::path::Path;

use crate::schema::model::*;

/// Write the generated module for `spec` (CGMES) and the other families.
pub fn generate_rust(
    spec: &CimSpecification,
    others: &[&CimSpecification],
    output_dir: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
    fs::create_dir_all(output_dir)?;
    let families: Vec<&CimSpecification> = std::iter::once(spec).chain(others.iter().copied()).collect();
    for f in &families {
        let file = output_dir.join(format!("{}_classes.rs", f.family.id));
        fs::write(file, super::classes_gen::render_classes(f))?;
    }
    let ids: Vec<&str> = families.iter().map(|f| f.family.id).collect();
    fs::write(output_dir.join("mod.rs"), render_mod(&ids))?;
    Ok(())
}

/// The `generated` module of the model crate, re-exported by its hand-written
/// `lib.rs`.
fn render_mod(family_ids: &[&str]) -> String {
    let mut s = String::new();
    writeln!(s, "// Generated by cimgen — do not edit by hand.").unwrap();
    writeln!(s).unwrap();
    for id in family_ids {
        writeln!(s, "pub mod {id}_classes;").unwrap();
    }
    s
}