Skip to main content

sim_citizen/
census.rs

1//! Renders the generated census of registered citizens as Markdown.
2
3use crate::{CitizenInfo, registered_citizens};
4
5/// Renders the full census of inventory-registered citizens as Markdown.
6///
7/// Collects every [`CitizenInfo`] registered through `inventory`, sorts by
8/// symbol then crate, and delegates to [`render_citizen_census`].
9pub fn citizen_census_markdown() -> String {
10    let mut citizens = registered_citizens().collect::<Vec<_>>();
11    citizens.sort_by(|left, right| {
12        left.symbol
13            .cmp(right.symbol)
14            .then_with(|| left.crate_name.cmp(right.crate_name))
15    });
16    render_citizen_census(&citizens)
17}
18
19/// Renders the supplied citizen rows as a generated Markdown census table.
20///
21/// Emits a fixed header plus one table row per [`CitizenInfo`]. Callers pass an
22/// already-ordered slice; this function does not sort.
23pub fn render_citizen_census(citizens: &[&CitizenInfo]) -> String {
24    let mut out = String::new();
25    out.push_str("# Generated Citizen Census\n\n");
26    out.push_str("Generated by `cargo test --workspace --all-features citizen`.\n");
27    out.push_str("Do not edit by hand.\n\n");
28    out.push_str(&format!("Total citizens: {}\n\n", citizens.len()));
29    out.push_str("| Symbol | Version | Arity | Crate |\n");
30    out.push_str("| --- | ---: | ---: | --- |\n");
31    for info in citizens {
32        out.push_str(&format!(
33            "| `{}` | {} | {} | `{}` |\n",
34            info.symbol, info.version, info.arity, info.crate_name
35        ));
36    }
37    out
38}