use std::{panic::Location, sync::Arc};
use thiserror::Error;
#[derive(Error, Debug, Clone)]
pub enum ErrorKind {
#[error(transparent)]
Io(Arc<std::io::Error>),
#[error(transparent)]
Csv(Arc<csv::Error>),
#[error(transparent)]
Json(Arc<serde_json::Error>),
#[error(transparent)]
Utf8(#[from] std::string::FromUtf8Error),
#[error(transparent)]
ParseFloat(#[from] std::num::ParseFloatError),
#[error(transparent)]
NdarrayShape(#[from] ndarray::ShapeError),
#[error(transparent)]
NdarrayMinMax(#[from] ndarray_stats::errors::MinMaxError),
#[error(transparent)]
RandDistrUniform(#[from] rand_distr::uniform::Error),
#[error("Linear Algebra error: {0}")]
Linalg(String),
#[error("Probability error: {0}")]
Probability(String),
#[error("Parsing error: {0}")]
Parsing(String),
#[error("Missing data error: {0}")]
MissingData(String),
#[error("Statistics error: {0}")]
Stats(String),
#[error("Random distribution error: {0}")]
RandDistr(String),
#[error("Shape error: {0}")]
Shape(String),
#[error("Unreachable error: {0}")]
Unreachable(String),
#[error("Lock poisoning error: {0}")]
Poison(String),
#[error("Index `{0}` is out of bounds")]
IndexOutOfBounds(usize),
#[error("Labels must be unique.")]
NonUniqueLabels,
#[error("Set {0} must not be empty")]
EmptySet(String),
#[error("Sets {0} and {1} must be disjoint")]
SetsNotDisjoint(String, String),
#[error("Set {0} must be a subset of set {1}")]
SubsetMismatch(String, String),
#[error("Graph must be a DAG")]
NotADag,
#[error("Invalid parameter {0}: {1}")]
InvalidParameter(String, String),
#[error("Prior knowledge conflict: {0}")]
PriorKnowledgeConflict(String),
#[error("Labels mismatch: {0} != {1}")]
LabelMismatch(String, String),
#[error("Missing sufficient statistics")]
MissingSufficientStatistics,
#[error("Missing log-likelihood")]
MissingLogLikelihood,
#[error("CSV file must have headers")]
MissingHeader,
#[error("Incompatible shape: {0} != {1}")]
IncompatibleShape(String, String),
#[error("State {0} not found")]
MissingState(String),
#[error("Label {0} not found")]
MissingLabel(String),
#[error("Value is NaN")]
NanValue,
#[error("Missing value at line {0}, column {1}")]
MissingValue(usize, usize),
#[error("Object construction failed: {0}")]
ConstructionError(String),
#[error(transparent)]
Other(Arc<Box<dyn std::error::Error + Send + Sync>>),
}
#[derive(Debug, Clone)]
pub struct Error {
pub kind: ErrorKind,
pub location: &'static Location<'static>,
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} at {}", self.kind, self.location)
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.kind.source()
}
}
impl From<ErrorKind> for Error {
#[track_caller]
fn from(kind: ErrorKind) -> Self {
Self {
kind,
location: Location::caller(),
}
}
}
impl From<std::io::Error> for Error {
#[track_caller]
fn from(err: std::io::Error) -> Self {
ErrorKind::Io(Arc::new(err)).into()
}
}
impl From<csv::Error> for Error {
#[track_caller]
fn from(err: csv::Error) -> Self {
ErrorKind::Csv(Arc::new(err)).into()
}
}
impl From<serde_json::Error> for Error {
#[track_caller]
fn from(err: serde_json::Error) -> Self {
ErrorKind::Json(Arc::new(err)).into()
}
}
impl From<Box<dyn std::error::Error + Send + Sync>> for Error {
#[track_caller]
fn from(err: Box<dyn std::error::Error + Send + Sync>) -> Self {
ErrorKind::Other(Arc::new(err)).into()
}
}
impl From<std::string::FromUtf8Error> for Error {
#[track_caller]
fn from(err: std::string::FromUtf8Error) -> Self {
ErrorKind::Utf8(err).into()
}
}
impl From<std::num::ParseFloatError> for Error {
#[track_caller]
fn from(err: std::num::ParseFloatError) -> Self {
ErrorKind::ParseFloat(err).into()
}
}
impl From<ndarray::ShapeError> for Error {
#[track_caller]
fn from(err: ndarray::ShapeError) -> Self {
ErrorKind::NdarrayShape(err).into()
}
}
impl From<ndarray_stats::errors::MinMaxError> for Error {
#[track_caller]
fn from(err: ndarray_stats::errors::MinMaxError) -> Self {
ErrorKind::NdarrayMinMax(err).into()
}
}
impl From<rand_distr::uniform::Error> for Error {
#[track_caller]
fn from(err: rand_distr::uniform::Error) -> Self {
ErrorKind::RandDistrUniform(err).into()
}
}
pub type Result<T> = std::result::Result<T, Error>;
impl serde::Serialize for Error {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
#[track_caller]
pub fn err<T>(kind: ErrorKind) -> Result<T> {
Err(Error::from(kind))
}
impl Error {
#[allow(non_snake_case)]
#[track_caller]
pub fn Linalg(s: &str) -> Self {
ErrorKind::Linalg(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn Probability(s: &str) -> Self {
ErrorKind::Probability(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn Parsing(s: &str) -> Self {
ErrorKind::Parsing(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn MissingData(s: &str) -> Self {
ErrorKind::MissingData(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn Stats(s: &str) -> Self {
ErrorKind::Stats(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn RandDistr(s: &str) -> Self {
ErrorKind::RandDistr(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn Shape(s: &str) -> Self {
ErrorKind::Shape(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn Unreachable(s: &str) -> Self {
ErrorKind::Unreachable(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn Poison(s: &str) -> Self {
ErrorKind::Poison(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn IndexOutOfBounds(u: usize) -> Self {
ErrorKind::IndexOutOfBounds(u).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn NonUniqueLabels() -> Self {
ErrorKind::NonUniqueLabels.into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn EmptySet(s: &str) -> Self {
ErrorKind::EmptySet(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn SetsNotDisjoint(s1: &str, s2: &str) -> Self {
ErrorKind::SetsNotDisjoint(s1.to_string(), s2.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn SubsetMismatch(s1: &str, s2: &str) -> Self {
ErrorKind::SubsetMismatch(s1.to_string(), s2.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn NotADag() -> Self {
ErrorKind::NotADag.into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn InvalidParameter(s1: &str, s2: &str) -> Self {
ErrorKind::InvalidParameter(s1.to_string(), s2.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn PriorKnowledgeConflict(s: &str) -> Self {
ErrorKind::PriorKnowledgeConflict(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn LabelMismatch(s1: &str, s2: &str) -> Self {
ErrorKind::LabelMismatch(s1.to_string(), s2.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn MissingSufficientStatistics() -> Self {
ErrorKind::MissingSufficientStatistics.into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn MissingLogLikelihood() -> Self {
ErrorKind::MissingLogLikelihood.into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn MissingHeader() -> Self {
ErrorKind::MissingHeader.into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn IncompatibleShape(s1: &str, s2: &str) -> Self {
ErrorKind::IncompatibleShape(s1.to_string(), s2.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn MissingState(s: &str) -> Self {
ErrorKind::MissingState(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn MissingLabel(s: &str) -> Self {
ErrorKind::MissingLabel(s.to_string()).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn NanValue() -> Self {
ErrorKind::NanValue.into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn MissingValue(u1: usize, u2: usize) -> Self {
ErrorKind::MissingValue(u1, u2).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn ConstructionError(s: &str) -> Self {
ErrorKind::ConstructionError(s.to_string()).into()
}
}
impl Error {
#[allow(non_snake_case)]
#[track_caller]
pub fn Io(err: Arc<std::io::Error>) -> Self {
ErrorKind::Io(err).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn Csv(err: Arc<csv::Error>) -> Self {
ErrorKind::Csv(err).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn Json(err: Arc<serde_json::Error>) -> Self {
ErrorKind::Json(err).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn Utf8(err: std::string::FromUtf8Error) -> Self {
ErrorKind::Utf8(err).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn ParseFloat(err: std::num::ParseFloatError) -> Self {
ErrorKind::ParseFloat(err).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn NdarrayShape(err: ndarray::ShapeError) -> Self {
ErrorKind::NdarrayShape(err).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn NdarrayMinMax(err: ndarray_stats::errors::MinMaxError) -> Self {
ErrorKind::NdarrayMinMax(err).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn RandDistrUniform(err: rand_distr::uniform::Error) -> Self {
ErrorKind::RandDistrUniform(err).into()
}
#[allow(non_snake_case)]
#[track_caller]
pub fn Other(err: Arc<Box<dyn std::error::Error + Send + Sync>>) -> Self {
ErrorKind::Other(err).into()
}
}