use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseError {
EmptyFormula,
Syntax {
pos: usize,
msg: String,
},
TermRemovalUnsupported,
DuplicateGroupingVar {
name: String,
},
EmptySlopeTerm {
group: String,
},
RandomInterceptSuppressionUnsupported,
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ParseError::EmptyFormula => write!(f, "formula is empty"),
ParseError::Syntax { pos, msg } => {
write!(f, "formula syntax error at position {pos}: {msg}")
}
ParseError::TermRemovalUnsupported => {
write!(f, "term removal with '-' is not supported")
}
ParseError::DuplicateGroupingVar { name } => {
write!(f, "duplicate grouping variable: {name}")
}
ParseError::EmptySlopeTerm { group } => {
write!(f, "empty slope term for group {group}")
}
ParseError::RandomInterceptSuppressionUnsupported => write!(
f,
"a random slope requires a random intercept in this engine version; \
intercept suppression ('0 +' / '-1 +') in a random-effects term is \
not supported — write '(x | g)' or '(1 + x | g)'"
),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
Parse(ParseError),
UnknownColumn(String),
ResponseNotNumeric(String),
WrongColumnKind {
name: String,
expected: &'static str,
},
SlopeVarNotInDesign(String),
RanefShapeMismatch(String),
EmptyDesign,
TransformNotFinite {
term: String,
row: usize,
},
CbindNeedsBinomial,
ZeroTrials {
row: usize,
},
NegativeCount {
row: usize,
},
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Parse(e) => write!(f, "{e}"),
Error::UnknownColumn(name) => write!(f, "unknown column: {name}"),
Error::ResponseNotNumeric(name) => {
write!(f, "response column '{name}' is not numeric")
}
Error::WrongColumnKind { name, expected } => {
write!(f, "column '{name}' is not {expected}")
}
Error::SlopeVarNotInDesign(name) => write!(
f,
"random-slope variable '{name}' is not a numeric fixed term in the design"
),
Error::RanefShapeMismatch(detail) => write!(
f,
"the fit and the lowered random effects do not describe the same model: {detail}"
),
Error::EmptyDesign => write!(
f,
"the fixed design has no columns: '- 1' / '0 +' with no fixed-effect term"
),
Error::TransformNotFinite { term, row } => {
write!(f, "term '{term}' is not finite at row {row}")
}
Error::CbindNeedsBinomial => {
write!(f, "cbind(successes, failures) needs family = binomial")
}
Error::ZeroTrials { row } => write!(
f,
"cbind(): successes + failures must be positive and finite at every row; row {row} is not"
),
Error::NegativeCount { row } => write!(
f,
"cbind(): successes and failures must be non-negative at every row; row {row} is not"
),
}
}
}
impl std::error::Error for Error {}
impl std::error::Error for ParseError {}
impl From<ParseError> for Error {
fn from(e: ParseError) -> Self {
Error::Parse(e)
}
}