Skip to main content

pg2sqlite_core/diagnostics/
reporter.rs

1/// Warning output formatting and strict mode enforcement.
2use std::io::Write;
3use std::path::Path;
4
5use super::warning::{Severity, Warning};
6
7/// Format and output warnings to the specified destination.
8pub fn report_warnings(
9    warnings: &[Warning],
10    destination: &WarningDestination,
11) -> std::io::Result<()> {
12    if warnings.is_empty() {
13        return Ok(());
14    }
15
16    let mut sorted = warnings.to_vec();
17    sorted.sort_by(|a, b| a.object.cmp(&b.object).then_with(|| a.code.cmp(b.code)));
18
19    match destination {
20        WarningDestination::Stderr => {
21            let stderr = std::io::stderr();
22            let mut handle = stderr.lock();
23            for w in &sorted {
24                writeln!(handle, "{w}")?;
25            }
26        }
27        WarningDestination::File(path) => {
28            let mut file = std::fs::File::create(path)?;
29            for w in &sorted {
30                writeln!(file, "{w}")?;
31            }
32        }
33    }
34
35    Ok(())
36}
37
38/// Check strict mode: fail if any warning has severity >= Lossy.
39pub fn check_strict(warnings: &[Warning]) -> Result<(), StrictViolation> {
40    let violations: Vec<&Warning> = warnings
41        .iter()
42        .filter(|w| w.severity >= Severity::Lossy)
43        .collect();
44
45    if violations.is_empty() {
46        Ok(())
47    } else {
48        let messages: Vec<String> = violations.iter().map(|w| w.to_string()).collect();
49        Err(StrictViolation { messages })
50    }
51}
52
53/// Error returned when strict mode finds lossy conversions.
54#[derive(Debug)]
55pub struct StrictViolation {
56    pub messages: Vec<String>,
57}
58
59impl std::fmt::Display for StrictViolation {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        writeln!(
62            f,
63            "Strict mode: {} lossy conversion(s) found:",
64            self.messages.len()
65        )?;
66        for msg in &self.messages {
67            writeln!(f, "  {msg}")?;
68        }
69        Ok(())
70    }
71}
72
73impl std::error::Error for StrictViolation {}
74
75/// Where to send warning output.
76pub enum WarningDestination {
77    Stderr,
78    File(std::path::PathBuf),
79}
80
81impl WarningDestination {
82    pub fn from_option(path: Option<&Path>) -> Self {
83        match path {
84            Some(p) if p.to_str() == Some("stderr") => WarningDestination::Stderr,
85            Some(p) => WarningDestination::File(p.to_path_buf()),
86            None => WarningDestination::Stderr,
87        }
88    }
89}