use std::path::Path;
use anyhow::Result;
mod discovery;
mod markdown;
mod model;
#[derive(Debug, Clone, Default)]
pub struct RenderOptions {
pub collapsible: Option<String>,
}
pub fn render(
criterion_dir: impl AsRef<Path>,
allowlist: impl IntoIterator<Item = impl AsRef<str>>,
) -> Result<String> {
render_with_options(criterion_dir, allowlist, &RenderOptions::default())
}
pub fn render_with_options(
criterion_dir: impl AsRef<Path>,
allowlist: impl IntoIterator<Item = impl AsRef<str>>,
options: &RenderOptions,
) -> Result<String> {
let criterion_dir = criterion_dir.as_ref();
let mut entries = discovery::discover_benchmarks(criterion_dir)?;
let names: Vec<String> = allowlist
.into_iter()
.map(|n| n.as_ref().to_string())
.collect();
if !names.is_empty() {
entries.retain(|e| names.iter().any(|n| n == &e.full_id));
}
if entries.is_empty() {
anyhow::bail!("No benchmark results found in {}", criterion_dir.display());
}
let skip_headers = options.collapsible.is_some();
let body = markdown::format_table(&entries, skip_headers);
Ok(match &options.collapsible {
Some(summary) => {
let range = markdown::compute_summary(&entries)
.map(|info| format!(" ({} → {})", info.worst_change, info.best_change))
.unwrap_or_default();
format!("<details>\n<summary>{summary}{range}</summary>\n\n{body}\n</details>\n")
}
None => body,
})
}