sim-citizen 0.1.0

Citizen support outside the SIM kernel.
Documentation
//! Renders the generated census of registered citizens as Markdown.

use crate::{CitizenInfo, registered_citizens};

/// Renders the full census of inventory-registered citizens as Markdown.
///
/// Collects every [`CitizenInfo`] registered through `inventory`, sorts by
/// symbol then crate, and delegates to [`render_citizen_census`].
pub fn citizen_census_markdown() -> String {
    let mut citizens = registered_citizens().collect::<Vec<_>>();
    citizens.sort_by(|left, right| {
        left.symbol
            .cmp(right.symbol)
            .then_with(|| left.crate_name.cmp(right.crate_name))
    });
    render_citizen_census(&citizens)
}

/// Renders the supplied citizen rows as a generated Markdown census table.
///
/// Emits a fixed header plus one table row per [`CitizenInfo`]. Callers pass an
/// already-ordered slice; this function does not sort.
pub fn render_citizen_census(citizens: &[&CitizenInfo]) -> String {
    let mut out = String::new();
    out.push_str("# Generated Citizen Census\n\n");
    out.push_str("Generated by `cargo test --workspace --all-features citizen`.\n");
    out.push_str("Do not edit by hand.\n\n");
    out.push_str(&format!("Total citizens: {}\n\n", citizens.len()));
    out.push_str("| Symbol | Version | Arity | Crate |\n");
    out.push_str("| --- | ---: | ---: | --- |\n");
    for info in citizens {
        out.push_str(&format!(
            "| `{}` | {} | {} | `{}` |\n",
            info.symbol, info.version, info.arity, info.crate_name
        ));
    }
    out
}