use std::fmt;
use super::dimension::Dimension;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UnitsError {
UnknownUnit {
name: String,
},
DimensionMismatch {
left: Dimension,
right: Dimension,
},
AffineUnit {
name: String,
operation: &'static str,
},
Parse {
expr: String,
message: String,
},
Redefinition {
name: String,
},
}
impl fmt::Display for UnitsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UnitsError::UnknownUnit { name } => write!(f, "unknown unit: {}", name),
UnitsError::DimensionMismatch { left, right } => {
write!(f, "dimension mismatch: {} vs {}", left, right)
}
UnitsError::AffineUnit { name, operation } => {
write!(f, "affine unit '{}' is invalid in {}", name, operation)
}
UnitsError::Parse { expr, message } => {
write!(f, "failed to parse '{}': {}", expr, message)
}
UnitsError::Redefinition { name } => write!(f, "unit already defined: {}", name),
}
}
}
impl std::error::Error for UnitsError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_covers_all_variants() {
let cases: Vec<(UnitsError, &str)> = vec![
(
UnitsError::UnknownUnit {
name: "zorp".to_string(),
},
"unknown unit: zorp",
),
(
UnitsError::AffineUnit {
name: "degC".to_string(),
operation: "mul",
},
"affine unit 'degC' is invalid in mul",
),
(
UnitsError::Parse {
expr: "m^".to_string(),
message: "missing exponent".to_string(),
},
"failed to parse 'm^': missing exponent",
),
(
UnitsError::Redefinition {
name: "smoot".to_string(),
},
"unit already defined: smoot",
),
];
for (err, expected) in cases {
assert_eq!(err.to_string(), expected);
}
let err = UnitsError::DimensionMismatch {
left: Dimension::LENGTH,
right: Dimension::TIME,
};
let msg = err.to_string();
assert!(msg.starts_with("dimension mismatch:"), "got {msg}");
}
#[test]
fn implements_std_error() {
let err = UnitsError::UnknownUnit {
name: "zorp".to_string(),
};
let dyn_err: &dyn std::error::Error = &err;
assert!(dyn_err.source().is_none());
}
}