use std::fmt;
use windows::core::{Error as WindowsError, HRESULT};
#[derive(Debug)]
#[allow(dead_code)] pub enum SageError {
ComError { hresult: HRESULT, message: String },
ConnectionError {
database_path: String,
message: String,
},
AuthenticationError { user: String, message: String },
MethodCallError {
method_name: String,
method_id: i32,
message: String,
},
ConversionError {
from_type: String,
to_type: String,
value: String,
},
ValidationError {
field: String,
value: String,
constraint: String,
},
DatabaseNotOpen,
ClassNotRegistered(String),
InvalidParameter {
parameter: String,
expected: String,
received: String,
},
UnsupportedOperation(String),
RegistryError(String),
InternalError(String),
}
impl fmt::Display for SageError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SageError::ComError { hresult, message } => {
write!(f, "Erreur COM (0x{:08X}): {}", hresult.0, message)
}
SageError::ConnectionError {
database_path,
message,
} => {
write!(f, "Erreur de connexion à '{}': {}", database_path, message)
}
SageError::AuthenticationError { user, message } => {
write!(f, "Erreur d'authentification pour '{}': {}", user, message)
}
SageError::MethodCallError {
method_name,
method_id,
message,
} => {
write!(
f,
"Erreur lors de l'appel de '{}' (ID: {}): {}",
method_name, method_id, message
)
}
SageError::ConversionError {
from_type,
to_type,
value,
} => {
write!(
f,
"Erreur de conversion de '{}' vers '{}' pour la valeur '{}'",
from_type, to_type, value
)
}
SageError::ValidationError {
field,
value,
constraint,
} => {
write!(
f,
"Erreur de validation du champ '{}' avec la valeur '{}': {}",
field, value, constraint
)
}
SageError::DatabaseNotOpen => {
write!(f, "Aucune base de données n'est ouverte")
}
SageError::ClassNotRegistered(clsid) => {
write!(
f,
"Classe COM non enregistrée: {}. Exécutez 'regsvr32 objets100c.dll' en tant qu'administrateur",
clsid
)
}
SageError::InvalidParameter {
parameter,
expected,
received,
} => {
write!(
f,
"Paramètre '{}' invalide: attendu '{}', reçu '{}'",
parameter, expected, received
)
}
SageError::UnsupportedOperation(op) => {
write!(f, "Opération non supportée: {}", op)
}
SageError::RegistryError(msg) => {
write!(f, "Erreur de registre Windows: {}", msg)
}
SageError::InternalError(msg) => {
write!(f, "Erreur interne: {}", msg)
}
}
}
}
impl std::error::Error for SageError {}
impl From<WindowsError> for SageError {
fn from(error: WindowsError) -> Self {
let hresult = error.code();
let message = error.message().to_string_lossy().to_owned();
match hresult.0 {
val if val == 0x80040154u32 as i32 => {
SageError::ClassNotRegistered("CLSID non trouvé".to_string())
}
val if val == 0x80070005u32 as i32 => SageError::ComError {
hresult,
message: "Accès refusé. Vérifiez les privilèges administrateur.".to_string(),
},
_ => SageError::ComError { hresult, message },
}
}
}
impl SageError {
pub fn method_call(method_name: &str, method_id: i32, message: &str) -> Self {
SageError::MethodCallError {
method_name: method_name.to_string(),
method_id,
message: message.to_string(),
}
}
#[allow(dead_code)] pub fn connection(database_path: &str, message: &str) -> Self {
SageError::ConnectionError {
database_path: database_path.to_string(),
message: message.to_string(),
}
}
#[allow(dead_code)] pub fn validation(field: &str, value: &str, constraint: &str) -> Self {
SageError::ValidationError {
field: field.to_string(),
value: value.to_string(),
constraint: constraint.to_string(),
}
}
#[allow(dead_code)] pub fn invalid_parameter(parameter: &str, expected: &str, received: &str) -> Self {
SageError::InvalidParameter {
parameter: parameter.to_string(),
expected: expected.to_string(),
received: received.to_string(),
}
}
#[allow(dead_code)] pub fn is_class_not_registered(&self) -> bool {
matches!(self, SageError::ClassNotRegistered(_))
}
#[allow(dead_code)] pub fn is_connection_error(&self) -> bool {
matches!(
self,
SageError::ConnectionError { .. } | SageError::DatabaseNotOpen
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let error = SageError::validation("compte", "invalid", "doit être numérique");
assert!(error.to_string().contains("Erreur de validation"));
}
#[test]
fn test_error_classification() {
let error = SageError::ClassNotRegistered("test".to_string());
assert!(error.is_class_not_registered());
let error = SageError::DatabaseNotOpen;
assert!(error.is_connection_error());
}
}