use std::fmt;
#[derive(Debug)]
pub enum DenetError {
Io(std::io::Error),
ProcessNotFound(usize),
ProcessAccessDenied(usize),
SystemTime(std::time::SystemTimeError),
Serialization(serde_json::Error),
InvalidConfiguration(String),
PlatformNotSupported(String),
EbpfInitError(String),
EbpfNotSupported(String),
Other(String),
}
impl fmt::Display for DenetError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DenetError::Io(err) => write!(f, "I/O error: {err}"),
DenetError::ProcessNotFound(pid) => write!(f, "Process not found: {pid}"),
DenetError::ProcessAccessDenied(pid) => write!(f, "Access denied for process: {pid}"),
DenetError::SystemTime(err) => write!(f, "System time error: {err}"),
DenetError::Serialization(err) => write!(f, "Serialization error: {err}"),
DenetError::InvalidConfiguration(msg) => write!(f, "Invalid configuration: {msg}"),
DenetError::PlatformNotSupported(msg) => write!(f, "Platform not supported: {msg}"),
DenetError::EbpfInitError(msg) => write!(f, "eBPF initialization error: {msg}"),
DenetError::EbpfNotSupported(msg) => write!(f, "eBPF not supported: {msg}"),
DenetError::Other(msg) => write!(f, "Error: {msg}"),
}
}
}
impl std::error::Error for DenetError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
DenetError::Io(ref err) => Some(err),
DenetError::SystemTime(ref err) => Some(err),
DenetError::Serialization(ref err) => Some(err),
_ => None,
}
}
}
impl From<std::io::Error> for DenetError {
fn from(err: std::io::Error) -> Self {
DenetError::Io(err)
}
}
impl From<std::time::SystemTimeError> for DenetError {
fn from(err: std::time::SystemTimeError) -> Self {
DenetError::SystemTime(err)
}
}
impl From<serde_json::Error> for DenetError {
fn from(err: serde_json::Error) -> Self {
DenetError::Serialization(err)
}
}
impl From<DenetError> for std::io::Error {
fn from(err: DenetError) -> Self {
match err {
DenetError::Io(io_err) => io_err,
_ => std::io::Error::other(err.to_string()),
}
}
}
pub type Result<T> = std::result::Result<T, DenetError>;
#[cfg(feature = "python")]
impl From<DenetError> for pyo3::PyErr {
fn from(err: DenetError) -> Self {
use pyo3::exceptions::*;
match err {
DenetError::Io(_) => PyIOError::new_err(err.to_string()),
DenetError::ProcessNotFound(_) => PyRuntimeError::new_err(err.to_string()),
DenetError::ProcessAccessDenied(_) => PyPermissionError::new_err(err.to_string()),
DenetError::InvalidConfiguration(_) => PyValueError::new_err(err.to_string()),
DenetError::PlatformNotSupported(_) => PyNotImplementedError::new_err(err.to_string()),
DenetError::EbpfInitError(_) => PyRuntimeError::new_err(err.to_string()),
DenetError::EbpfNotSupported(_) => PyNotImplementedError::new_err(err.to_string()),
_ => PyRuntimeError::new_err(err.to_string()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::error::Error;
use std::io;
#[test]
fn test_denet_error_display() {
let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
let denet_err = DenetError::Io(io_err);
assert!(denet_err.to_string().contains("I/O error"));
assert!(denet_err.to_string().contains("file not found"));
let pid = 12345;
let err = DenetError::ProcessNotFound(pid);
assert_eq!(err.to_string(), format!("Process not found: {}", pid));
let err = DenetError::ProcessAccessDenied(pid);
assert_eq!(
err.to_string(),
format!("Access denied for process: {}", pid)
);
let time_err = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::now() + std::time::Duration::from_secs(1))
.unwrap_err();
let err = DenetError::SystemTime(time_err);
assert!(err.to_string().contains("System time error"));
let json_err = serde_json::Error::io(io::Error::other("JSON error"));
let err = DenetError::Serialization(json_err);
assert!(err.to_string().contains("Serialization error"));
let msg = "Invalid config parameter";
let err = DenetError::InvalidConfiguration(msg.to_string());
assert_eq!(err.to_string(), format!("Invalid configuration: {}", msg));
let msg = "Windows feature";
let err = DenetError::PlatformNotSupported(msg.to_string());
assert_eq!(err.to_string(), format!("Platform not supported: {}", msg));
let msg = "Failed to initialize BPF";
let err = DenetError::EbpfInitError(msg.to_string());
assert_eq!(
err.to_string(),
format!("eBPF initialization error: {}", msg)
);
let msg = "Kernel too old";
let err = DenetError::EbpfNotSupported(msg.to_string());
assert_eq!(err.to_string(), format!("eBPF not supported: {}", msg));
let msg = "Generic error";
let err = DenetError::Other(msg.to_string());
assert_eq!(err.to_string(), format!("Error: {}", msg));
}
#[test]
fn test_denet_error_source() {
let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
let denet_err = DenetError::Io(io_err);
assert!(denet_err.source().is_some());
let time_err = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::now() + std::time::Duration::from_secs(1))
.unwrap_err();
let denet_err = DenetError::SystemTime(time_err);
assert!(denet_err.source().is_some());
let json_err = serde_json::Error::io(io::Error::other("JSON error"));
let denet_err = DenetError::Serialization(json_err);
assert!(denet_err.source().is_some());
assert!(DenetError::ProcessNotFound(123).source().is_none());
assert!(DenetError::ProcessAccessDenied(456).source().is_none());
assert!(DenetError::InvalidConfiguration("test".to_string())
.source()
.is_none());
assert!(DenetError::PlatformNotSupported("test".to_string())
.source()
.is_none());
assert!(DenetError::EbpfInitError("test".to_string())
.source()
.is_none());
assert!(DenetError::EbpfNotSupported("test".to_string())
.source()
.is_none());
assert!(DenetError::Other("test".to_string()).source().is_none());
}
#[test]
fn test_error_conversions_from_std() {
let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
let denet_err: DenetError = io_err.into();
match denet_err {
DenetError::Io(_) => (),
_ => panic!("Expected Io error variant"),
}
let time_err = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::now() + std::time::Duration::from_secs(1))
.unwrap_err();
let denet_err: DenetError = time_err.into();
match denet_err {
DenetError::SystemTime(_) => (),
_ => panic!("Expected SystemTime error variant"),
}
let json_err = serde_json::Error::io(io::Error::other("JSON error"));
let denet_err: DenetError = json_err.into();
match denet_err {
DenetError::Serialization(_) => (),
_ => panic!("Expected Serialization error variant"),
}
}
#[test]
fn test_error_conversion_to_io_error() {
let original_io_err = io::Error::new(io::ErrorKind::NotFound, "original io error");
let denet_err = DenetError::Io(original_io_err);
let converted_io_err: io::Error = denet_err.into();
assert!(converted_io_err.to_string().contains("original io error"));
let original_err = DenetError::ProcessNotFound(123);
let io_err: io::Error = original_err.into();
assert!(io_err.to_string().contains("Process not found"));
}
#[test]
fn test_result_type_alias() {
let result: Result<i32> = Ok(42);
match result {
Ok(v) => assert_eq!(v, 42),
Err(_) => panic!("Expected Ok but got Err"),
}
let error_result: Result<i32> = Err(DenetError::Other("test error".to_string()));
assert!(error_result.is_err());
match error_result {
Err(DenetError::Other(msg)) => assert_eq!(msg, "test error"),
_ => panic!("Expected Other error variant"),
}
}
#[test]
fn test_denet_error_debug() {
let err = DenetError::ProcessNotFound(123);
let debug_str = format!("{:?}", err);
assert!(debug_str.contains("ProcessNotFound"));
assert!(debug_str.contains("123"));
}
#[cfg(feature = "python")]
#[test]
fn test_python_error_conversion() {
use pyo3::exceptions::*;
use pyo3::Python;
Python::with_gil(|py| {
let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
let denet_err = DenetError::Io(io_err);
let py_err: pyo3::PyErr = denet_err.into();
assert!(py_err.is_instance_of::<PyIOError>(py));
let denet_err = DenetError::ProcessNotFound(123);
let py_err: pyo3::PyErr = denet_err.into();
assert!(py_err.is_instance_of::<PyRuntimeError>(py));
let denet_err = DenetError::ProcessAccessDenied(123);
let py_err: pyo3::PyErr = denet_err.into();
assert!(py_err.is_instance_of::<PyPermissionError>(py));
let denet_err = DenetError::InvalidConfiguration("test".to_string());
let py_err: pyo3::PyErr = denet_err.into();
assert!(py_err.is_instance_of::<PyValueError>(py));
let denet_err = DenetError::PlatformNotSupported("test".to_string());
let py_err: pyo3::PyErr = denet_err.into();
assert!(py_err.is_instance_of::<PyNotImplementedError>(py));
let denet_err = DenetError::EbpfInitError("test".to_string());
let py_err: pyo3::PyErr = denet_err.into();
assert!(py_err.is_instance_of::<PyRuntimeError>(py));
let denet_err = DenetError::EbpfNotSupported("test".to_string());
let py_err: pyo3::PyErr = denet_err.into();
assert!(py_err.is_instance_of::<PyNotImplementedError>(py));
let denet_err = DenetError::Other("test".to_string());
let py_err: pyo3::PyErr = denet_err.into();
assert!(py_err.is_instance_of::<PyRuntimeError>(py));
let time_err = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::now() + std::time::Duration::from_secs(1))
.unwrap_err();
let denet_err = DenetError::SystemTime(time_err);
let py_err: pyo3::PyErr = denet_err.into();
assert!(py_err.is_instance_of::<PyRuntimeError>(py));
let json_err = serde_json::Error::io(io::Error::other("JSON error"));
let denet_err = DenetError::Serialization(json_err);
let py_err: pyo3::PyErr = denet_err.into();
assert!(py_err.is_instance_of::<PyRuntimeError>(py));
});
}
}