Skip to main content

xtask/report/
markdown.rs

1//! Markdown shared by the README and saved benchmark reports.
2
3use crate::report;
4use anyhow::{Context, Result};
5use serde_json::Value;
6use std::{fmt::Write as _, path::Path};
7
8pub(crate) fn cell(value: &str) -> String {
9    value
10        .replace('&', "&")
11        .replace('<', "&lt;")
12        .replace('>', "&gt;")
13        .replace('|', "&#124;")
14        .replace(['\n', '\r'], " ")
15}
16
17pub(crate) fn link(path: &Path) -> String {
18    path.to_string_lossy()
19        .replace('%', "%25")
20        .replace(' ', "%20")
21        .replace('#', "%23")
22        .replace('?', "%3F")
23        .replace('(', "%28")
24        .replace(')', "%29")
25}
26
27pub(crate) fn answers(data: &Value) -> Result<String> {
28    let mut rows = String::new();
29
30    for run in data["runs"].as_array().context("runs")? {
31        let Some(output) = run["output"].as_str() else {
32            continue;
33        };
34
35        writeln!(
36            rows,
37            "| [{}]({}) | {} |",
38            cell(report::text(&run["id"])),
39            link(Path::new(output)),
40            cell(report::text(&run["status"]))
41        )?;
42    }
43
44    if rows.is_empty() {
45        return Ok(rows);
46    }
47
48    Ok(format!(
49        "\n## Answers\n\n| Sample | Status |\n| --- | --- |\n{rows}"
50    ))
51}
52
53pub(crate) fn label(config: &Value) -> &str {
54    if config["id"] == "misses-2bit" {
55        return "4-bit / 2-bit misses + cut";
56    }
57
58    report::text(&config["label"])
59}
60
61pub(crate) fn drawings(data: &Value, directory: &Path) -> Result<String> {
62    let runs = data["runs"].as_array().context("runs")?;
63    let mut images = Vec::new();
64
65    for config in data["configurations"]
66        .as_array()
67        .context("configurations")?
68    {
69        let run = runs.iter().rev().find(|r| {
70            r["configuration"] == config["id"] && r["status"] == "ok" && r["svg"].is_string()
71        });
72        let Some(run) = run else {
73            continue;
74        };
75        let title = cell(label(config));
76        let path = link(&directory.join(run["svg"].as_str().unwrap()));
77
78        images.push((title, format!("![Pelican]({path})")));
79    }
80
81    let mut text = String::new();
82
83    for pair in images.chunks(2) {
84        writeln!(
85            text,
86            "| {} |",
87            pair.iter()
88                .map(|p| p.0.as_str())
89                .collect::<Vec<_>>()
90                .join(" | ")
91        )?;
92        writeln!(text, "| {} |", vec!["---"; pair.len()].join(" | "))?;
93        writeln!(
94            text,
95            "| {} |\n",
96            pair.iter()
97                .map(|p| p.1.as_str())
98                .collect::<Vec<_>>()
99                .join(" | ")
100        )?;
101    }
102
103    Ok(text)
104}