Skip to main content

cu_profiler_report/
lib.rs

1//! `cu-profiler-report` — rendering for the core report model.
2//!
3//! Every renderer takes a [`cu_profiler_core::model::Report`] and produces a
4//! string. The crate holds no analysis logic; it only formats already-computed
5//! data, keeping the raw-data/presentation boundary clean.
6#![forbid(unsafe_code)]
7#![warn(missing_docs)]
8
9pub mod html;
10pub mod json;
11pub mod junit;
12pub mod markdown;
13pub mod model;
14pub mod table;
15
16use std::str::FromStr;
17
18use cu_profiler_core::model::Report;
19use cu_profiler_core::{Error, Result};
20
21/// A selectable output format.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum Format {
24    /// Aligned text table.
25    Table,
26    /// Stable JSON.
27    Json,
28    /// Markdown (PR comments).
29    Markdown,
30    /// JUnit XML.
31    Junit,
32    /// Self-contained HTML.
33    Html,
34}
35
36impl Format {
37    /// All formats, for help text and iteration.
38    pub const ALL: [Format; 5] = [
39        Format::Table,
40        Format::Json,
41        Format::Markdown,
42        Format::Junit,
43        Format::Html,
44    ];
45
46    /// Lowercase identifier.
47    #[must_use]
48    pub fn as_str(self) -> &'static str {
49        match self {
50            Format::Table => "table",
51            Format::Json => "json",
52            Format::Markdown => "markdown",
53            Format::Junit => "junit",
54            Format::Html => "html",
55        }
56    }
57}
58
59impl FromStr for Format {
60    type Err = Error;
61
62    fn from_str(s: &str) -> Result<Self> {
63        match s.to_ascii_lowercase().as_str() {
64            "table" => Ok(Format::Table),
65            "json" => Ok(Format::Json),
66            "markdown" | "md" => Ok(Format::Markdown),
67            "junit" | "xml" => Ok(Format::Junit),
68            "html" | "htm" => Ok(Format::Html),
69            other => Err(Error::Config(format!(
70                "unknown output format `{other}` (expected table|json|markdown|junit|html)"
71            ))),
72        }
73    }
74}
75
76/// Render `report` in the requested `format`.
77///
78/// # Errors
79/// Propagates serialization failures from the JSON renderer.
80pub fn render(report: &Report, format: Format) -> Result<String> {
81    Ok(match format {
82        Format::Table => table::render(report),
83        Format::Json => json::render(report)?,
84        Format::Markdown => markdown::render(report),
85        Format::Junit => junit::render(report),
86        Format::Html => html::render(report),
87    })
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn format_parsing_round_trips() {
96        for f in Format::ALL {
97            assert_eq!(Format::from_str(f.as_str()).unwrap(), f);
98        }
99        assert!(Format::from_str("yaml").is_err());
100        assert_eq!(Format::from_str("md").unwrap(), Format::Markdown);
101    }
102}