mars_agents/
diagnostic.rs1use serde::Serialize;
2
3#[derive(Debug, Clone, Serialize)]
5pub struct Diagnostic {
6 pub level: DiagnosticLevel,
7 pub code: &'static str,
9 pub message: String,
11 #[serde(skip_serializing_if = "Option::is_none")]
13 pub context: Option<String>,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
17#[serde(rename_all = "lowercase")]
18pub enum DiagnosticLevel {
19 Warning,
20 Info,
21}
22
23pub struct DiagnosticCollector {
25 diagnostics: Vec<Diagnostic>,
26}
27
28impl DiagnosticCollector {
29 pub fn new() -> Self {
30 Self {
31 diagnostics: Vec::new(),
32 }
33 }
34
35 pub fn warn(&mut self, code: &'static str, message: impl Into<String>) {
36 self.diagnostics.push(Diagnostic {
37 level: DiagnosticLevel::Warning,
38 code,
39 message: message.into(),
40 context: None,
41 });
42 }
43
44 pub fn info(&mut self, code: &'static str, message: impl Into<String>) {
45 self.diagnostics.push(Diagnostic {
46 level: DiagnosticLevel::Info,
47 code,
48 message: message.into(),
49 context: None,
50 });
51 }
52
53 pub fn warn_with_context(
54 &mut self,
55 code: &'static str,
56 message: impl Into<String>,
57 context: impl Into<String>,
58 ) {
59 self.diagnostics.push(Diagnostic {
60 level: DiagnosticLevel::Warning,
61 code,
62 message: message.into(),
63 context: Some(context.into()),
64 });
65 }
66
67 pub fn extend(&mut self, diagnostics: Vec<Diagnostic>) {
68 self.diagnostics.extend(diagnostics);
69 }
70
71 pub fn drain(&mut self) -> Vec<Diagnostic> {
72 std::mem::take(&mut self.diagnostics)
73 }
74
75 pub fn is_empty(&self) -> bool {
76 self.diagnostics.is_empty()
77 }
78}
79
80impl Default for DiagnosticCollector {
81 fn default() -> Self {
82 Self::new()
83 }
84}
85
86impl std::fmt::Display for Diagnostic {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 let prefix = match self.level {
89 DiagnosticLevel::Warning => "warning",
90 DiagnosticLevel::Info => "info",
91 };
92 write!(f, "{prefix}: {}", self.message)
93 }
94}