2025-06-24 20:27:06 +02:00
|
|
|
|
use serde::de::StdError;
|
2025-06-23 20:59:49 +02:00
|
|
|
|
use std::fmt;
|
|
|
|
|
|
use std::sync::PoisonError;
|
2025-06-23 20:27:16 +02:00
|
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
2025-06-23 20:59:49 +02:00
|
|
|
|
pub type NyxResult<T, E = NyxError> = Result<T, E>;
|
2025-06-23 20:27:16 +02:00
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Error)]
|
|
|
|
|
|
pub enum NyxError {
|
2025-06-24 20:27:06 +02:00
|
|
|
|
#[error("I/O error: {0}")]
|
|
|
|
|
|
Io(#[from] std::io::Error),
|
|
|
|
|
|
|
2025-06-24 21:43:26 +02:00
|
|
|
|
#[error("TOML parse error: {0}")]
|
|
|
|
|
|
Toml(#[from] toml::de::Error),
|
|
|
|
|
|
|
2025-06-24 20:27:06 +02:00
|
|
|
|
#[error("SQLite error: {0}")]
|
|
|
|
|
|
Sql(#[from] rusqlite::Error),
|
|
|
|
|
|
|
|
|
|
|
|
#[error("tree-sitter error: {0}")]
|
|
|
|
|
|
TreeSitter(#[from] tree_sitter::LanguageError),
|
2025-06-23 20:27:16 +02:00
|
|
|
|
|
2025-06-24 20:27:06 +02:00
|
|
|
|
#[error("connection-pool error: {0}")]
|
|
|
|
|
|
Pool(#[from] r2d2::Error),
|
2025-06-23 20:27:16 +02:00
|
|
|
|
|
2025-06-24 20:27:06 +02:00
|
|
|
|
#[error("time error: {0}")]
|
|
|
|
|
|
Time(#[from] std::time::SystemTimeError),
|
2025-06-23 20:27:16 +02:00
|
|
|
|
|
2025-06-24 20:27:06 +02:00
|
|
|
|
#[error("poisoned lock: {0}")]
|
|
|
|
|
|
Poison(String),
|
2025-06-23 20:27:16 +02:00
|
|
|
|
|
2025-06-24 20:27:06 +02:00
|
|
|
|
#[error(transparent)]
|
|
|
|
|
|
Other(#[from] Box<dyn StdError + Send + Sync + 'static>),
|
2025-06-23 20:27:16 +02:00
|
|
|
|
|
2025-06-24 20:27:06 +02:00
|
|
|
|
#[error("{0}")]
|
|
|
|
|
|
Msg(String),
|
2025-06-23 20:59:49 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<T> From<PoisonError<T>> for NyxError
|
|
|
|
|
|
where
|
2025-06-24 20:27:06 +02:00
|
|
|
|
T: fmt::Debug,
|
2025-06-23 20:59:49 +02:00
|
|
|
|
{
|
2025-06-24 20:27:06 +02:00
|
|
|
|
fn from(err: PoisonError<T>) -> Self {
|
|
|
|
|
|
NyxError::Poison(err.to_string())
|
|
|
|
|
|
}
|
2025-06-23 20:59:49 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl From<&str> for NyxError {
|
2025-06-24 20:27:06 +02:00
|
|
|
|
fn from(s: &str) -> Self {
|
|
|
|
|
|
NyxError::Msg(s.to_owned())
|
|
|
|
|
|
}
|
2025-06-23 20:59:49 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl From<String> for NyxError {
|
2025-06-24 20:27:06 +02:00
|
|
|
|
fn from(s: String) -> Self {
|
|
|
|
|
|
NyxError::Msg(s)
|
|
|
|
|
|
}
|
2025-06-23 20:59:49 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl From<Box<dyn std::error::Error>> for NyxError {
|
2025-06-24 20:27:06 +02:00
|
|
|
|
fn from(err: Box<dyn std::error::Error>) -> Self {
|
|
|
|
|
|
NyxError::Msg(err.to_string())
|
|
|
|
|
|
}
|
2025-06-23 20:59:49 +02:00
|
|
|
|
}
|
2025-06-24 23:38:32 +02:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn io_conversion_retains_message() {
|
|
|
|
|
|
let e = std::io::Error::other("boom!");
|
|
|
|
|
|
let n: NyxError = e.into();
|
|
|
|
|
|
assert!(matches!(n, NyxError::Io(_)));
|
|
|
|
|
|
assert!(n.to_string().contains("boom"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn poison_conversion_maps_correct_variant() {
|
|
|
|
|
|
let lock = std::sync::Arc::new(std::sync::Mutex::new(()));
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
let lock2 = std::sync::Arc::clone(&lock);
|
|
|
|
|
|
std::thread::spawn(move || {
|
|
|
|
|
|
let _guard = lock2.lock().unwrap();
|
|
|
|
|
|
panic!("intentional – poison the mutex");
|
|
|
|
|
|
})
|
|
|
|
|
|
.join()
|
|
|
|
|
|
.ok();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let poison = lock.lock().unwrap_err();
|
|
|
|
|
|
let nyx: NyxError = poison.into();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(matches!(nyx, NyxError::Poison(_)));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn simple_string_into_msg() {
|
|
|
|
|
|
let nyx: NyxError = "plain msg".into();
|
|
|
|
|
|
assert!(matches!(nyx, NyxError::Msg(s) if s == "plain msg"));
|
|
|
|
|
|
}
|