use std::fmt;
pub type Result<T, E = HessboostError> = std::result::Result<T, E>;
#[derive(Debug)]
#[non_exhaustive]
pub enum HessboostError {
DimensionMismatch {
what: &'static str,
expected: usize,
got: usize,
},
InvalidParameter {
name: &'static str,
reason: String,
},
#[non_exhaustive]
InvalidData {
input: &'static str,
dataset: Option<String>,
reason: String,
},
#[non_exhaustive]
IncompatibleModel {
what: &'static str,
reason: String,
},
EmptyDataset(&'static str),
FeatureOutOfBounds {
index: usize,
num_features: usize,
},
Unknown {
kind: &'static str,
name: String,
suggestion: Option<&'static str>,
},
#[non_exhaustive]
Parse {
line: usize,
reason: String,
},
ModelFormat(String),
Gpu(String),
Io(std::io::Error),
Json(serde_json::Error),
}
impl fmt::Display for HessboostError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DimensionMismatch {
what,
expected,
got,
} => write!(
f,
"dimension mismatch: {what} (expected {expected}, got {got})"
),
Self::InvalidParameter { name, reason } => {
write!(f, "invalid parameter `{name}`: {reason}")
}
Self::InvalidData {
input,
dataset,
reason,
} => {
write!(f, "invalid {input}")?;
if let Some(dataset) = dataset {
write!(f, " in dataset `{dataset}`")?;
}
write!(f, ": {reason}")
}
Self::IncompatibleModel { what, reason } => {
write!(f, "incompatible model for `{what}`: {reason}")
}
Self::EmptyDataset(what) => write!(f, "empty dataset: {what}"),
Self::FeatureOutOfBounds {
index,
num_features,
} => write!(
f,
"feature index {index} out of bounds (num_features = {num_features})"
),
Self::Unknown {
kind,
name,
suggestion,
} => {
write!(f, "unknown {kind} `{name}`")?;
if let Some(suggestion) = suggestion {
write!(f, " (did you mean `{suggestion}`?)")?;
}
Ok(())
}
Self::Parse { line, reason } => write!(f, "parse error at line {line}: {reason}"),
Self::ModelFormat(msg) => write!(f, "model format error: {msg}"),
Self::Gpu(msg) => write!(f, "GPU backend error: {msg}"),
Self::Io(e) => e.fmt(f),
Self::Json(e) => e.fmt(f),
}
}
}
impl std::error::Error for HessboostError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => e.source(),
Self::Json(e) => e.source(),
_ => None,
}
}
}
impl From<std::io::Error> for HessboostError {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}
impl From<serde_json::Error> for HessboostError {
fn from(e: serde_json::Error) -> Self {
Self::Json(e)
}
}
impl HessboostError {
pub fn invalid_param(name: &'static str, reason: impl Into<String>) -> Self {
HessboostError::InvalidParameter {
name,
reason: reason.into(),
}
}
pub fn invalid_data(input: &'static str, reason: impl Into<String>) -> Self {
HessboostError::InvalidData {
input,
dataset: None,
reason: reason.into(),
}
}
pub fn incompatible_model(what: &'static str, reason: impl Into<String>) -> Self {
HessboostError::IncompatibleModel {
what,
reason: reason.into(),
}
}
#[must_use]
pub fn in_dataset(self, name: &str) -> Self {
match self {
HessboostError::InvalidData {
input,
dataset: None,
reason,
} => HessboostError::InvalidData {
input,
dataset: Some(name.to_owned()),
reason,
},
other => other,
}
}
pub fn unknown(kind: &'static str, name: impl Into<String>) -> Self {
HessboostError::Unknown {
kind,
name: name.into(),
suggestion: None,
}
}
pub fn model_format(msg: impl Into<String>) -> Self {
HessboostError::ModelFormat(msg.into())
}
pub fn gpu(msg: impl Into<String>) -> Self {
HessboostError::Gpu(msg.into())
}
pub fn missing_field(field: &str) -> Self {
Self::model_format(format!("missing `{field}`"))
}
pub(crate) fn dimension_mismatch(what: &'static str, expected: usize, got: usize) -> Self {
HessboostError::DimensionMismatch {
what,
expected,
got,
}
}
}