use thiserror::Error;
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum Error {
#[error("order {0} is not a prime power (must be p^k for prime p and k >= 1)")]
NotPrimePower(u32),
#[error("division by zero in GF({order})")]
DivisionByZero {
order: u32,
},
#[error("element {value} is out of range for GF({order}), must be in 0..{order}")]
ElementOutOfRange {
value: u32,
order: u32,
},
#[error("no irreducible polynomial available for GF({0})")]
NoIrreduciblePolynomial(u32),
#[error("invalid OA parameters: {message}")]
InvalidParams {
message: String,
},
#[error("factors {factors} exceeds maximum {max} for {algorithm} construction")]
TooManyFactors {
factors: usize,
max: usize,
algorithm: &'static str,
},
#[error("levels {levels} is not a prime power as required by {algorithm}")]
LevelsNotPrimePower {
levels: u32,
algorithm: &'static str,
},
#[error("{algorithm} requires levels to be a power of 2, got {levels}")]
RequiresPowerOfTwo {
levels: u32,
algorithm: &'static str,
},
#[error("strength {strength} is invalid for {algorithm} (valid range: {min}..={max})")]
InvalidStrength {
strength: u32,
min: u32,
max: u32,
algorithm: &'static str,
},
#[error("construction failed: {message}")]
ConstructionFailed {
message: String,
},
#[error("no suitable algorithm found for OA({runs}, {factors}, {levels}, {strength})")]
NoSuitableAlgorithm {
runs: usize,
factors: usize,
levels: u32,
strength: u32,
},
#[error("verification failed: {message}")]
VerificationFailed {
message: String,
},
#[error("strength mismatch: claimed {claimed}, actual {actual}")]
StrengthMismatch {
claimed: u32,
actual: u32,
},
#[error("dimension mismatch: expected {expected}, got {actual}")]
DimensionMismatch {
expected: String,
actual: String,
},
#[error("index {index} is out of bounds for size {size}")]
IndexOutOfBounds {
index: usize,
size: usize,
},
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
impl Error {
#[must_use]
pub fn invalid_params(message: impl Into<String>) -> Self {
Self::InvalidParams {
message: message.into(),
}
}
#[must_use]
pub fn construction_failed(message: impl Into<String>) -> Self {
Self::ConstructionFailed {
message: message.into(),
}
}
#[must_use]
pub fn verification_failed(message: impl Into<String>) -> Self {
Self::VerificationFailed {
message: message.into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = Error::NotPrimePower(6);
assert!(err.to_string().contains("6"));
assert!(err.to_string().contains("prime power"));
let err = Error::DivisionByZero { order: 7 };
assert!(err.to_string().contains("division by zero"));
assert!(err.to_string().contains("GF(7)"));
let err = Error::TooManyFactors {
factors: 10,
max: 8,
algorithm: "Bose",
};
assert!(err.to_string().contains("10"));
assert!(err.to_string().contains("8"));
assert!(err.to_string().contains("Bose"));
}
#[test]
fn test_error_equality() {
let err1 = Error::NotPrimePower(6);
let err2 = Error::NotPrimePower(6);
let err3 = Error::NotPrimePower(10);
assert_eq!(err1, err2);
assert_ne!(err1, err3);
}
}