xtalforge_modules/
report.rs1use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct ReportSection {
13 pub heading: String,
15 pub body: String,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21pub struct Report {
22 pub run_id: String,
24 pub title: String,
26 pub summary: String,
28 pub sections: Vec<ReportSection>,
30 pub references: Vec<String>,
32}
33
34impl Report {
35 #[must_use]
40 pub fn to_markdown(&self) -> String {
41 let mut out = String::new();
42 out.push_str(&format!("# {}\n\n", self.title));
43 if !self.run_id.trim().is_empty() {
44 out.push_str(&format!("Run: `{}`\n\n", self.run_id));
45 }
46 if !self.summary.trim().is_empty() {
47 out.push_str(self.summary.trim());
48 out.push_str("\n\n");
49 }
50 for section in &self.sections {
51 out.push_str(&format!("## {}\n\n", section.heading));
52 let body = section.body.trim();
53 if !body.is_empty() {
54 out.push_str(body);
55 out.push_str("\n\n");
56 }
57 }
58 if !self.references.is_empty() {
59 out.push_str("## References\n\n");
60 for reference in &self.references {
61 out.push_str(&format!("- {reference}\n"));
62 }
63 }
64 let mut trimmed = out.trim_end().to_owned();
65 trimmed.push('\n');
66 trimmed
67 }
68}