use serde::{Deserialize, Serialize};
use thiserror::Error;
pub type Result<T> = std::result::Result<T, McdError>;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Diagnostic {
pub level: DiagnosticLevel,
pub code: String,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub source: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub related: Vec<String>,
}
impl Diagnostic {
#[must_use]
pub fn error(code: impl Into<String>, message: impl Into<String>) -> Self {
Self {
level: DiagnosticLevel::Error,
code: code.into(),
message: message.into(),
source: None,
related: Vec::new(),
}
}
#[must_use]
pub fn with_source(mut self, source: impl Into<String>) -> Self {
self.source = Some(source.into());
self
}
#[must_use]
pub fn with_related(mut self, related: impl Into<String>) -> Self {
self.related.push(related.into());
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum DiagnosticLevel {
Error,
Warning,
Info,
}
#[derive(Debug, Error)]
pub enum McdError {
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("package archive error: {0}")]
Zip(#[from] zip::result::ZipError),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("UTF-8 error: {0}")]
Utf8(#[from] std::string::FromUtf8Error),
#[error("{diagnostic_code}: {diagnostic_message}")]
Diagnostic {
diagnostic_code: String,
diagnostic_message: String,
diagnostic: Box<Diagnostic>,
},
}
impl McdError {
#[must_use]
pub fn from_diagnostic(diagnostic: Diagnostic) -> Self {
Self::Diagnostic {
diagnostic_code: diagnostic.code.clone(),
diagnostic_message: diagnostic.message.clone(),
diagnostic: Box::new(diagnostic),
}
}
#[must_use]
pub fn diagnostic(&self) -> Option<&Diagnostic> {
match self {
Self::Diagnostic { diagnostic, .. } => Some(diagnostic.as_ref()),
Self::Io(_) | Self::Zip(_) | Self::Json(_) | Self::Utf8(_) => None,
}
}
}